Merge "msm: kgsl: Dump the A6XX SQE firmware version in the snapshot" 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/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
index 90ddc27..50488b4 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
@@ -49,6 +49,16 @@
Value Type: <stringlist>
Definition: Address names. Must be "llcc"
+- llcc-bank-off:
+ Usage: required
+ Value Type: <u32 array>
+ Definition: Offsets of llcc banks from llcc base address starting from
+ LLCC bank0.
+- llcc-broadcast-off:
+ Usage: required
+ Value Type: <u32>
+ Definition: Offset of broadcast register from LLCC bank0 address.
+
- #cache-cells:
Usage: required
Value Type: <u32>
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 7405115..d95aa59 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -17,6 +17,7 @@
"qcom,gcc-msm8996"
"qcom,gcc-mdm9615"
"qcom,gcc-sdm845"
+ "qcom,debugcc-sdm845"
- reg : shall contain base register location and length
- #clock-cells : shall contain 1
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/cnss/icnss.txt b/Documentation/devicetree/bindings/cnss/icnss.txt
index 15feda3..c801e848 100644
--- a/Documentation/devicetree/bindings/cnss/icnss.txt
+++ b/Documentation/devicetree/bindings/cnss/icnss.txt
@@ -12,13 +12,22 @@
- reg-names: Names of the memory regions defined in reg entry
- interrupts: Copy engine interrupt table
- qcom,wlan-msa-memory: MSA memory size
+ - clocks: List of clock phandles
+ - clock-names: List of clock names corresponding to the "clocks" property
- iommus: SMMUs and corresponding Stream IDs needed by WLAN
- qcom,wlan-smmu-iova-address: I/O virtual address range as <start length>
format to be used for allocations associated between WLAN and SMMU
Optional properties:
+ - <supply-name>-supply: phandle to the regulator device tree node
+ optional "supply-name" is "vdd-0.8-cx-mx".
+ - qcom,<supply>-config: Specifies voltage levels for supply. Should be
+ specified in pairs (min, max), units uV. There can
+ be optional load in uA and Regulator settle delay in
+ uS.
- qcom,icnss-vadc: VADC handle for vph_pwr read APIs.
- qcom,icnss-adc_tm: VADC handle for vph_pwr notification APIs.
+ - qcom,smmu-s1-bypass: Boolean context flag to set SMMU to S1 bypass
Example:
@@ -26,6 +35,8 @@
compatible = "qcom,icnss";
reg = <0x0a000000 0x1000000>;
reg-names = "membase";
+ clocks = <&clock_gcc clk_aggre2_noc_clk>;
+ clock-names = "smmu_aggre2_noc_clk";
iommus = <&anoc2_smmu 0x1900>,
<&anoc2_smmu 0x1901>;
qcom,wlan-smmu-iova-address = <0 0x10000000>;
@@ -43,4 +54,7 @@
<0 140 0 /* CE10 */ >,
<0 141 0 /* CE11 */ >;
qcom,wlan-msa-memory = <0x200000>;
+ qcom,smmu-s1-bypass;
+ vdd-0.8-cx-mx-supply = <&pm8998_l5>;
+ qcom,vdd-0.8-cx-mx-config = <800000 800000 2400 1000>;
};
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/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt
index b6544961..f4b6013 100644
--- a/Documentation/devicetree/bindings/gpu/adreno.txt
+++ b/Documentation/devicetree/bindings/gpu/adreno.txt
@@ -152,6 +152,11 @@
baseAddr - base address of the gpu channels in the qdss stm memory region
size - size of the gpu stm region
+- qcom,gpu-qtimer:
+ <baseAddr size>
+ baseAddr - base address of the qtimer memory region
+ size - size of the qtimer region
+
- qcom,tsens-name:
Specify the name of GPU temperature sensor. This name will be used
to get the temperature from the thermal driver API.
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index ef6c04a..2d971b7a 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -25,6 +25,8 @@
- reg : Base address and size of the SMMU.
+- reg-names : For the "qcom,qsmmu-v500" device "tcu-base" is expected.
+
- #global-interrupts : The number of global interrupts exposed by the
device.
@@ -176,6 +178,9 @@
"base" is the main TBU register region.
"status-reg" indicates whether hw can process a new request.
+-qcom,stream-id-range:
+ Pair of values describing the smallest supported stream-id
+ and the size of the entire set.
Example:
smmu {
@@ -186,5 +191,6 @@
<0x2000 0x8>;
reg-names = "base",
"status-reg";
+ qcom,stream-id-range = <0x800 0x400>;
};
};
diff --git a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
index a77a291..1e6aac5 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-wled.txt
@@ -75,6 +75,9 @@
- qcom,lcd-auto-pfm-thresh : Specify the auto-pfm threshold, if the headroom voltage level
falls below this threshold and auto PFM is enabled, boost
controller will enter into PFM mode automatically.
+- qcom,lcd-psm-ctrl : A boolean property to specify if PSM needs to be
+ controlled dynamically when WLED module is enabled
+ or disabled.
Optional properties if 'qcom,disp-type-amoled' is mentioned in DT:
- qcom,loop-comp-res-kohm : control to select the compensation resistor in kohm. default is 320.
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/misc/qpnp-misc.txt b/Documentation/devicetree/bindings/misc/qpnp-misc.txt
new file mode 100644
index 0000000..a34cbde
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/qpnp-misc.txt
@@ -0,0 +1,25 @@
+QPNP-MISC
+
+QPNP-MISC provides a way to read the PMIC part number and revision.
+
+Required properties:
+- compatible : should be "qcom,qpnp-misc"
+- reg : offset and length of the PMIC peripheral register map.
+
+Optional properties:
+- qcom,pwm-sel: Select PWM source. Possible values:
+ 0: LOW
+ 1: PWM1_in
+ 2: PWM2_in
+ 3: PWM1_in & PWM2_in
+- qcom,enable-gp-driver: Enable the GP driver. Should only be specified
+ if a non-zero PWM source is specified under
+ "qcom,pwm-sel" property.
+
+Example:
+ qcom,misc@900 {
+ compatible = "qcom,qpnp-misc";
+ reg = <0x900 0x100>;
+ qcom,pwm-sel = <2>;
+ qcom,enable-gp-driver;
+ };
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
index 485483a..6111c88 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
@@ -1,55 +1,81 @@
-* Qualcomm SDHCI controller (sdhci-msm)
+Qualcomm Technologies, Inc. Standard Secure Digital Host Controller (SDHC)
-This file documents differences between the core properties in mmc.txt
-and the properties used by the sdhci-msm driver.
+Secure Digital Host Controller provides standard host interface to SD/MMC/SDIO cards.
Required properties:
-- compatible: Should contain "qcom,sdhci-msm-v4".
-- reg: Base address and length of the register in the following order:
- - Host controller register map (required)
- - SD Core register map (required)
-- interrupts: Should contain an interrupt-specifiers for the interrupts:
- - Host controller interrupt (required)
-- pinctrl-names: Should contain only one value - "default".
-- pinctrl-0: Should specify pin control groups used for this controller.
-- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
-- clock-names: Should contain the following:
- "iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
- "core" - SDC MMC clock (MCLK) (required)
- "bus" - SDCC bus voter clock (optional)
+ - compatible : should be "qcom,sdhci-msm"
+ - reg : should contain SDHC, SD Core register map.
+ - reg-names : indicates various resources passed to driver (via reg proptery) by name.
+ Required "reg-names" are "hc_mem" and "core_mem"
+ - interrupts : should contain SDHC interrupts.
+ - interrupt-names : indicates interrupts passed to driver (via interrupts property) by name.
+ Required "interrupt-names" are "hc_irq" and "pwr_irq".
+ - <supply-name>-supply: phandle to the regulator device tree node
+ Required "supply-name" are "vdd" and "vdd-io".
+
+Required alias:
+- The slot number is specified via an alias with the following format
+ 'sdhc{n}' where n is the slot number.
+
+Optional Properties:
+ - interrupt-names - "status_irq". This status_irq will be used for card
+ detection.
+ - qcom,bus-width - defines the bus I/O width that controller supports.
+ Units - number of bits. The valid bus-width values are
+ 1, 4 and 8.
+ - qcom,nonremovable - specifies whether the card in slot is
+ hot pluggable or hard wired.
+ - qcom,bus-speed-mode - specifies supported bus speed modes by host.
+ The supported bus speed modes are :
+ "HS200_1p8v" - indicates that host can support HS200 at 1.8v.
+ "HS200_1p2v" - indicates that host can support HS200 at 1.2v.
+ "DDR_1p8v" - indicates that host can support DDR mode at 1.8v.
+ "DDR_1p2v" - indicates that host can support DDR mode at 1.2v.
+
+In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
+ - qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
+ - qcom,<supply>-lpm_sup - specifies whether supply can be kept in low power mode (lpm).
+ - qcom,<supply>-voltage_level - specifies voltage levels for supply. Should be
+ specified in pairs (min, max), units uV.
+ - qcom,<supply>-current_level - specifies load levels for supply in lpm or
+ high power mode (hpm). Should be specified in
+ pairs (lpm, hpm), units uA.
+
+ - gpios - specifies gpios assigned for sdhc slot.
+ - qcom,gpio-names - a list of strings that map in order to the list of gpios
Example:
- sdhc_1: sdhci@f9824900 {
- compatible = "qcom,sdhci-msm-v4";
- reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
- interrupts = <0 123 0>;
- bus-width = <8>;
- non-removable;
-
- vmmc-supply = <&pm8941_l20>;
- vqmmc-supply = <&pm8941_s3>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&sdc1_clk &sdc1_cmd &sdc1_data>;
-
- clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>;
- clock-names = "core", "iface";
+ aliases {
+ sdhc1 = &sdhc_1;
};
- sdhc_2: sdhci@f98a4900 {
- compatible = "qcom,sdhci-msm-v4";
- reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
- interrupts = <0 125 0>;
- bus-width = <4>;
- cd-gpios = <&msmgpio 62 0x1>;
+ sdhc_1: qcom,sdhc@f9824900 {
+ compatible = "qcom,sdhci-msm";
+ reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
+ reg-names = "hc_mem", "core_mem";
+ interrupts = <0 123 0>, <0 138 0>;
+ interrupt-names = "hc_irq", "pwr_irq";
- vmmc-supply = <&pm8941_l21>;
- vqmmc-supply = <&pm8941_l13>;
+ vdd-supply = <&pm8941_l21>;
+ vdd-io-supply = <&pm8941_l13>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <9000 800000>;
- pinctrl-names = "default";
- pinctrl-0 = <&sdc2_clk &sdc2_cmd &sdc2_data>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <6 22000>;
- clocks = <&gcc GCC_SDCC2_APPS_CLK>, <&gcc GCC_SDCC2_AHB_CLK>;
- clock-names = "core", "iface";
+ qcom,bus-width = <4>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS200_1p8v", "DDR_1p8v";
+
+ gpios = <&msmgpio 40 0>, /* CLK */
+ <&msmgpio 39 0>, /* CMD */
+ <&msmgpio 38 0>, /* DATA0 */
+ <&msmgpio 37 0>, /* DATA1 */
+ <&msmgpio 36 0>, /* DATA2 */
+ <&msmgpio 35 0>; /* DATA3 */
+ qcom,gpio-names = "CLK", "CMD", "DAT0", "DAT1", "DAT2", "DAT3";
};
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/pinctrl/qcom,pmic-gpio.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
index 521c783..c01036d 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
@@ -43,6 +43,17 @@
the first cell will be used to define gpio number and the
second denotes the flags for this gpio
+- qcom,gpios-disallowed:
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Array of the GPIO hardware numbers corresponding to GPIOs
+ which the APSS processor is not allowed to configure.
+ The hardware numbers are indexed from 1.
+ The interrupt resources for these GPIOs must not be defined
+ in "interrupts" and "interrupt-names" properties.
+ GPIOs defined in this array won't be registered as pins
+ in the pinctrl device or gpios in the gpio chip.
+
Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
a general description of GPIO and interrupt bindings.
@@ -233,6 +244,7 @@
gpio-controller;
#gpio-cells = <2>;
+ qcom,gpios-disallowed = <1 20>;
pm8921_gpio_keys: gpio-keys {
volume-keys {
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
index d08ca95..c9cfc88 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-labibb-regulator.txt
@@ -149,6 +149,8 @@
already. If it it not specified, then
output voltage can be configured to
any value in the allowed limit.
+- qcom,notify-lab-vreg-ok-sts: A boolean property which upon set will
+ poll and notify the lab_vreg_ok status.
Following properties are available only for PM660A:
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
index 8b3a38da0..63da8ec 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-lcdb-regulator.txt
@@ -26,6 +26,13 @@
Value type: <prop-encoded-array>
Definition: Base address of the LCDB SPMI peripheral.
+- qcom,force-module-reenable
+ Usage: required if using SW mode for module enable
+ Value type: <bool>
+ Definition: This enables the workaround to force enable
+ the vph_pwr_2p5_ok signal required for
+ turning on the LCDB module.
+
Touch-to-wake (TTW) properties:
TTW supports 2 modes of operation - HW and SW. In the HW mode the enable/disable
@@ -59,7 +66,6 @@
Definition: ON time (in mS) for the VDISP/VDISN signals.
Possible values are 4, 8, 16, 32.
-
========================================
Second Level Nodes - LDO/NCP/BOOST block
========================================
diff --git a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
index 5d80a04..38f599b 100644
--- a/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/qpnp-oledb-regulator.txt
@@ -44,12 +44,12 @@
Value type: <bool>
Definition: Enables the voltage programming through SWIRE signal.
- qcom,ext-pin-control
+- qcom,ext-pin-control
Usage: optional
Value type: <bool>
Definition: Configures the OLED module to be enabled by a external pin.
- qcom,dynamic-ext-pinctl-config
+- qcom,dynamic-ext-pinctl-config
Usage: optional
Value type: <bool>
Definition: Used to dynamically enable/disable the OLEDB module
@@ -57,13 +57,27 @@
rail. This property is applicable only if qcom,ext-pin-ctl
property is specified and it is specific to PM660A.
- qcom,pbs-control
+- qcom,force-pd-control
+ Usage: optional
+ Value type: <bool>
+ Definition: Used to enable the pull down control forcibly via SPMI by
+ disabling the pull down configuration done by hardware
+ automatically through SWIRE pulses.
+
+- qcom,pbs-client
+ Usage: optional
+ Value type: <phandle>
+ Definition: Used to send the PBS trigger to the specified PBS client.
+ This property is applicable only if qcom,force-pd-control
+ property is specified.
+
+- qcom,pbs-control
Usage: optional
Value type: <bool>
Definition: PMIC PBS logic directly configures the output voltage update
and pull down control.
- qcom,oledb-init-voltage-mv
+- qcom,oledb-init-voltage-mv
Usage: optional
Value type: <u32>
Definition: Sets the AVDD bias voltage (in mV) when the module is
@@ -71,53 +85,53 @@
property is not specified. Supported values are from 5.0V
to 8.1V with a step of 100mV.
-qcom,oledb-default-voltage-mv
+- qcom,oledb-default-voltage-mv
Usage: optional
Value type: <u32>
Definition: Sets the default AVDD bias voltage (in mV) before module
enable. Supported values are from 5.0V to 8.1V with the
step of 100mV.
-qcom,bias-gen-warmup-delay-ns
+- qcom,bias-gen-warmup-delay-ns
Usage: optional
Value type: <u32>
Definition: Bias generator warm-up time (ns). Supported values are
6700, 13300, 267000, 534000.
-qcom,peak-curr-limit-ma
+- qcom,peak-curr-limit-ma
Usage: optional
Value type: <u32>
Definition: Peak current limit (in mA). Supported values are 115, 265,
415, 570, 720, 870, 1020, 1170.
-qcom,pull-down-enable
+- qcom,pull-down-enable
Usage: optional
Value type: <u32>
Definition: Pull down configuration of OLEDB.
1 - Enable pull-down
0 - Disable pull-down
-qcom,negative-curr-limit-enable
+- qcom,negative-curr-limit-enable
Usage: optional
Value type: <u32>
Definition: negative current limit enable/disable.
1 = enable negative current limit
0 = disable negative current limit
-qcom,negative-curr-limit-ma
+- qcom,negative-curr-limit-ma
Usage: optional
Value type: <u32>
Definition: Negative current limit (in mA). Supported values are
170, 300, 420, 550.
-qcom,enable-short-circuit
+- qcom,enable-short-circuit
Usage: optional
Value type: <u32>
Definition: Short circuit protection enable/disable.
1 = enable short circuit protection
0 = disable short circuit protection
-qcom,short-circuit-dbnc-time
+- qcom,short-circuit-dbnc-time
usage: optional
Value type: <u32>
Definitioan: Short circuit debounce time (in Fsw). Supported
@@ -126,26 +140,26 @@
Fast precharge properties:
-------------------------
-qcom,fast-precharge-ppulse-enable
+- qcom,fast-precharge-ppulse-enable
usage: optional
Value type: <u32>
Definitioan: Fast precharge pfet pulsing enable/disable.
1 = enable fast precharge pfet pulsing
0 = disable fast precharge pfet pulsing
-qcom,precharge-debounce-time-ms
+- qcom,precharge-debounce-time-ms
usage: optional
Value type: <u32>
Definitioan: Fast precharge debounce time (in ms). Supported
values are 1, 2, 4, 8.
-qcom,precharge-pulse-period-us
+- qcom,precharge-pulse-period-us
usage: optional
Value type: <u32>
Definitioan: Fast precharge pulse period (in us). Supported
values are 3, 6, 9, 12.
-qcom,precharge-pulse-on-time-us
+- qcom,precharge-pulse-on-time-us
usage: optional
Value type: <u32>
Definitioan: Fast precharge pulse on time (in ns). Supported
@@ -154,20 +168,20 @@
Pulse Skip Modulation (PSM) properties:
--------------------------------------
-qcom,psm-enable
+- qcom,psm-enable
Usage: optional
Value type: <u32>
Definition: Pulse Skip Modulation mode.
1 - Enable PSM mode
0 - Disable PSM mode
-qcom,psm-hys-mv
+- qcom,psm-hys-mv
Usage: optional
Value type: <u32>
Definition: PSM hysterysis voltage (in mV).
Supported values are 13mV and 26mV.
-qcom,psm-vref-mv
+- qcom,psm-vref-mv
Usage: optional
Value type: <u32>
Definition: Reference voltage(in mV) control for PSM comparator.
@@ -177,26 +191,26 @@
Pulse Frequency Modulation (PFM) properties:
-------------------------------------------
-qcom,pfm-enable
+- qcom,pfm-enable
Usage: optional
Value type: <u32>
Definition: Pulse Frequency Modulation mode.
1 - Enable PFM mode
0 - Disable PFM mode
-qcom,pfm-hys-mv
+- qcom,pfm-hys-mv
Usage: optional
Value type: <u32>
Definition: PFM hysterysis voltage (in mV).
Supported values are 13mV and 26mV.
-qcom,pfm-curr-limit-ma
+- qcom,pfm-curr-limit-ma
Usage: optional
Value type: <u32>
Definition: PFM current limit (in mA).
Supported values are 130, 200, 270, 340.
-qcom,pfm-off-time-ns
+- qcom,pfm-off-time-ns
Usage: optional
Value type: <u32>
Definition: NFET off time at PFM (in ns).
diff --git a/Documentation/devicetree/bindings/soc/qcom/avtimer.txt b/Documentation/devicetree/bindings/soc/qcom/avtimer.txt
index 157f79b..7c70b1e 100644
--- a/Documentation/devicetree/bindings/soc/qcom/avtimer.txt
+++ b/Documentation/devicetree/bindings/soc/qcom/avtimer.txt
@@ -13,8 +13,16 @@
- compatible : Must be "qcom,avtimer"
Optional properties:
-- clk-div : The clk is at 27MHz and hence ticks are to be
- divided by 27 to achive the msec value.
+- clk-div : Divisor to divide the ticks value to get msec value.
+ If the clock is at 27MHz, the ticks value read from AVTimer
+ registers will have to be divided by 27, to achieve the msec value.
+- clk-mult : Multiplier to multiply the ticks value in order to avoid
+ a floating point operation if the clock is of decimal value.
+ E.g. To get msec out of ticks from a 19.2MHz clock source, the ticks
+ value will have to be divided by 19.2, which will then become a
+ floating point operation. However, to avoid using a floating point
+ operation, the msec can be calculated by multiplying ticks with 10
+ and dividing the result by 192. i.e. msec = (ticks * 10) / 192;
Example:
qcom,avtimer@90f7000 {
@@ -23,4 +31,5 @@
<0x90f7010 0x4>;
reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
qcom,clk-div = <27>;
+ qcom,clk-mult = <10>;
};
diff --git a/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt b/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt
new file mode 100644
index 0000000..d7aefbf
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qpnp-pbs.txt
@@ -0,0 +1,30 @@
+QPNP PBS
+
+QPNP (Qualcomm Technologies, Inc. Plug N Play) PBS is programmable boot sequence
+and this driver is for helping the client drivers triggering such sequence
+to be configured in PMIC.
+
+This document describes the bindings for QPNP PBS driver.
+
+=======================
+Required Node Structure
+=======================
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: should be "qcom,qpnp-pbs".
+
+- reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Base address of the PBS registers.
+
+
+=======
+Example
+=======
+ pm660l_pbs: qcom,pbs@7300 {
+ compatible = "qcom,qpnp-pbs";
+ reg = <0x7300 0x100>;
+ };
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..123a65b 100644
--- a/Documentation/devicetree/bindings/thermal/thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/thermal.txt
@@ -168,6 +168,18 @@
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.
+ "low_limits_floor": Use low limits floor
+ mitigation governor.
+ "low_limits_cap": Use a low limits cap mitigation
+ 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 +187,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/devicetree/bindings/ufs/ufs-qcom.txt b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
index af1ba92..af754fe 100644
--- a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
+++ b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
@@ -7,11 +7,12 @@
contain a phandle reference to UFS PHY node.
Required properties:
-- compatible : compatible list, contains one of the following:
+- compatible : compatible list, contains one of the following
+ according to the relevant phy in use:
"qcom,ufs-phy-qmp-14nm"
"qcom,ufs-phy-qmp-v3"
"qcom,ufs-phy-qrbtc-sdm845"
-according to the relevant phy in use.
+ "qcom,ufs-phy-qmp-v3-660"
- reg : should contain PHY register address space (mandatory),
- reg-names : indicates various resources passed to driver (via reg proptery) by name.
Required "reg-names" is "phy_mem".
@@ -27,11 +28,12 @@
Optional properties:
- vdda-phy-max-microamp : specifies max. load that can be drawn from phy supply
- vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply
-- vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply
-- vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply
-- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on
- qcom,disable-lpm : disable various LPM mechanisms in UFS for platform compatibility
(limit link to PWM Gear-1, 1-lane slow mode; disable hibernate, and avoid suspend/resume)
+- lanes-per-direction: number of lanes available per direction - either 1 or 2.
+ Note that it is assumed that same number of lanes is
+ used both directions at once.
+ If not specified, default is 2 lanes per direction.
Example:
@@ -40,6 +42,7 @@
reg = <0xfc597000 0x800>;
reg-names = "phy_mem";
#phy-cells = <0>;
+ lanes-per-direction = <1>;
vdda-phy-supply = <&pma8084_l4>;
vdda-pll-supply = <&pma8084_l12>;
vdda-phy-max-microamp = <50000>;
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 81c74c5..958194b 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -13,6 +13,9 @@
- reg : <registers mapping>
first entry should contain UFS host controller register address space (mandatory),
second entry is the device ref. clock control register map (optional).
+- reset : reset specifier pair consists of phandle for the reset provider
+ and reset lines used by this controller.
+- reset-names : reset signal name strings sorted in the same order as the resets property.
Optional properties:
- phys : phandle to UFS PHY node
@@ -52,6 +55,8 @@
- lanes-per-direction: number of lanes available per direction - either 1 or 2.
Note that it is assume same number of lanes is used both directions at once.
If not specified, default is 2 lanes per direction.
+- pinctrl-names, pinctrl-0, pinctrl-1,.. pinctrl-n: Refer to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt"
+ for these optional properties
- limit-tx-hs-gear : Specify the max. limit on the TX HS gear.
Valid range: 1-3. 1 => HS-G1, 2 => HS-G2, 3 => HS-G3
- limit-rx-hs-gear : Specify the max. limit on the RX HS gear. Refer "limit-tx-hs-gear" for expected values.
@@ -89,6 +94,8 @@
clocks = <&core 0>, <&ref 0>, <&iface 0>;
clock-names = "core_clk", "ref_clk", "iface_clk";
freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
+ resets = <clock_gcc GCC_UFS_BCR>;
+ reset-names = "core_reset";
phys = <&ufsphy1>;
phy-names = "ufsphy";
rpm-level = <3>;
@@ -146,6 +153,9 @@
- qcom,pm-qos-default-cpu: PM QoS voting is based on the cpu associated with each IO request by the block layer.
This defined the default cpu used for PM QoS voting in case a specific cpu value is not available.
+- qcom,vddp-ref-clk-supply : reference clock to ufs device. Controlled by the host driver.
+- qcom,vddp-ref-clk-max-microamp : specifies max. load that can be drawn for
+ ref-clk supply.
Example:
ufshc@0xfc598000 {
...
diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
index 18056ee..bc66690 100644
--- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt
@@ -66,6 +66,7 @@
event buffers. 1 event buffer is needed per h/w accelerated endpoint.
- qcom,pm-qos-latency: This represents max tolerable CPU latency in microsecs,
which is used as a vote by driver to get max performance in perf mode.
+- qcom,smmu-s1-bypass: If present, configure SMMU to bypass stage 1 translation.
Sub nodes:
- Sub node for "DWC3- USB3 controller".
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/include/asm/dma-iommu.h b/arch/arm/include/asm/dma-iommu.h
index 2ef282f..b4e74af 100644
--- a/arch/arm/include/asm/dma-iommu.h
+++ b/arch/arm/include/asm/dma-iommu.h
@@ -24,6 +24,8 @@
struct kref kref;
};
+#ifdef CONFIG_ARM_DMA_USE_IOMMU
+
struct dma_iommu_mapping *
arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, u64 size);
@@ -33,5 +35,29 @@
struct dma_iommu_mapping *mapping);
void arm_iommu_detach_device(struct device *dev);
+#else /* !CONFIG_ARM_DMA_USE_IOMMU */
+
+static inline struct dma_iommu_mapping *
+arm_iommu_create_mapping(struct bus_type *bus, dma_addr_t base, size_t size)
+{
+ return NULL;
+}
+
+static inline void arm_iommu_release_mapping(struct dma_iommu_mapping *mapping)
+{
+}
+
+static inline int arm_iommu_attach_device(struct device *dev,
+ struct dma_iommu_mapping *mapping)
+{
+ return -ENODEV;
+}
+
+static inline void arm_iommu_detach_device(struct device *dev)
+{
+}
+
+#endif /* CONFIG_ARM_DMA_USE_IOMMU */
+
#endif /* __KERNEL__ */
#endif
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/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
index 3497e50..a94a716 100644
--- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi
@@ -49,7 +49,9 @@
apps_smmu: apps-smmu@0x15000000 {
compatible = "qcom,qsmmu-v500";
- reg = <0x15000000 0x80000>;
+ reg = <0x15000000 0x80000>,
+ <0x150c2000 0x20>;
+ reg-names = "base", "tcu-base";
#iommu-cells = <1>;
qcom,skip-init;
#global-interrupts = <1>;
@@ -128,6 +130,7 @@
reg = <0x150c5000 0x1000>,
<0x150c2200 0x8>;
reg-names = "base", "status-reg";
+ qcom,stream-id-range = <0x0 0x400>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu1_gdsc>;
};
@@ -138,6 +141,7 @@
reg = <0x150c9000 0x1000>,
<0x150c2208 0x8>;
reg-names = "base", "status-reg";
+ qcom,stream-id-range = <0x400 0x400>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu2_gdsc>;
};
@@ -148,6 +152,7 @@
reg = <0x150cd000 0x1000>,
<0x150c2210 0x8>;
reg-names = "base", "status-reg";
+ qcom,stream-id-range = <0x800 0x400>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc>;
};
@@ -158,6 +163,7 @@
reg = <0x150d1000 0x1000>,
<0x150c2218 0x8>;
reg-names = "base", "status-reg";
+ qcom,stream-id-range = <0xc00 0x400>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc>;
};
@@ -168,6 +174,7 @@
reg = <0x150d5000 0x1000>,
<0x150c2220 0x8>;
reg-names = "base", "status-reg";
+ qcom,stream-id-range = <0x1000 0x400>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc>;
};
@@ -178,6 +185,7 @@
reg = <0x150d9000 0x1000>,
<0x150c2228 0x8>;
reg-names = "base", "status-reg";
+ qcom,stream-id-range = <0x1400 0x400>;
/* No GDSC */
};
@@ -187,6 +195,7 @@
reg = <0x150dd000 0x1000>,
<0x150c2230 0x8>;
reg-names = "base", "status-reg";
+ qcom,stream-id-range = <0x1800 0x400>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc>;
};
@@ -197,6 +206,7 @@
reg = <0x150e1000 0x1000>,
<0x150c2238 0x8>;
reg-names = "base", "status-reg";
+ qcom,stream-id-range = <0x1c00 0x400>;
qcom,regulator-names = "vdd";
vdd-supply = <&hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc>;
};
diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi
index 241864f..1f8d20e 100644
--- a/arch/arm64/boot/dts/qcom/pm8005.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8005.dtsi
@@ -32,37 +32,15 @@
label = "pm8005_tz";
};
- pm8005_gpios: gpios {
- compatible = "qcom,qpnp-pin";
+ pm8005_gpios: pinctrl@c000 {
+ compatible = "qcom,spmi-gpio";
+ reg = <0xc000 0x400>;
+ interrupts = <0x4 0xc0 0 IRQ_TYPE_NONE>,
+ <0x4 0xc1 0 IRQ_TYPE_NONE>;
+ interrupt-names = "pm8005_gpio1", "pm8005_gpio2";
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pm8005-gpio";
-
- gpio@c000 {
- reg = <0xc000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- gpio@c100 {
- reg = <0xc100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
-
- gpio@c200 {
- reg = <0xc200 0x100>;
- qcom,pin-num = <3>;
- status = "disabled";
- };
-
- gpio@c300 {
- reg = <0xc300 0x100>;
- qcom,pin-num = <4>;
- status = "disabled";
- };
+ qcom,gpios-disallowed = <3 4>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi
index ed4fdde..5290f46 100644
--- a/arch/arm64/boot/dts/qcom/pm8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi
@@ -72,169 +72,41 @@
label = "pm8998_tz";
};
- pm8998_gpios: gpios {
- compatible = "qcom,qpnp-pin";
+ pm8998_gpios: pinctrl@c000 {
+ compatible = "qcom,spmi-gpio";
+ reg = <0xc000 0x1a00>;
+ interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>,
+ <0x0 0xc1 0 IRQ_TYPE_NONE>,
+ <0x0 0xc3 0 IRQ_TYPE_NONE>,
+ <0x0 0xc4 0 IRQ_TYPE_NONE>,
+ <0x0 0xc5 0 IRQ_TYPE_NONE>,
+ <0x0 0xc6 0 IRQ_TYPE_NONE>,
+ <0x0 0xc7 0 IRQ_TYPE_NONE>,
+ <0x0 0xc8 0 IRQ_TYPE_NONE>,
+ <0x0 0xc9 0 IRQ_TYPE_NONE>,
+ <0x0 0xca 0 IRQ_TYPE_NONE>,
+ <0x0 0xcb 0 IRQ_TYPE_NONE>,
+ <0x0 0xcc 0 IRQ_TYPE_NONE>,
+ <0x0 0xcd 0 IRQ_TYPE_NONE>,
+ <0x0 0xcf 0 IRQ_TYPE_NONE>,
+ <0x0 0xd0 0 IRQ_TYPE_NONE>,
+ <0x0 0xd1 0 IRQ_TYPE_NONE>,
+ <0x0 0xd2 0 IRQ_TYPE_NONE>,
+ <0x0 0xd4 0 IRQ_TYPE_NONE>,
+ <0x0 0xd6 0 IRQ_TYPE_NONE>;
+ interrupt-names = "pm8998_gpio1", "pm8998_gpio2",
+ "pm8998_gpio4", "pm8998_gpio5",
+ "pm8998_gpio6", "pm8998_gpio7",
+ "pm8998_gpio8", "pm8998_gpio9",
+ "pm8998_gpio10", "pm8998_gpio11",
+ "pm8998_gpio12", "pm8998_gpio13",
+ "pm8998_gpio14", "pm8998_gpio16",
+ "pm8998_gpio17", "pm8998_gpio18",
+ "pm8998_gpio19", "pm8998_gpio21",
+ "pm8998_gpio23";
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pm8998-gpio";
-
- gpio@c000 {
- reg = <0xc000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- gpio@c100 {
- reg = <0xc100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
-
- gpio@c200 {
- reg = <0xc200 0x100>;
- qcom,pin-num = <3>;
- status = "disabled";
- };
-
- gpio@c300 {
- reg = <0xc300 0x100>;
- qcom,pin-num = <4>;
- status = "disabled";
- };
-
- gpio@c400 {
- reg = <0xc400 0x100>;
- qcom,pin-num = <5>;
- status = "disabled";
- };
-
- gpio@c500 {
- reg = <0xc500 0x100>;
- qcom,pin-num = <6>;
- status = "disabled";
- };
-
- gpio@c600 {
- reg = <0xc600 0x100>;
- qcom,pin-num = <7>;
- status = "disabled";
- };
-
- gpio@c700 {
- reg = <0xc700 0x100>;
- qcom,pin-num = <8>;
- status = "disabled";
- };
-
- gpio@c800 {
- reg = <0xc800 0x100>;
- qcom,pin-num = <9>;
- status = "disabled";
- };
-
- gpio@c900 {
- reg = <0xc900 0x100>;
- qcom,pin-num = <10>;
- status = "disabled";
- };
-
- gpio@ca00 {
- reg = <0xca00 0x100>;
- qcom,pin-num = <11>;
- status = "disabled";
- };
-
- gpio@cb00 {
- reg = <0xcb00 0x100>;
- qcom,pin-num = <12>;
- status = "disabled";
- };
-
- gpio@cc00 {
- reg = <0xcc00 0x100>;
- qcom,pin-num = <13>;
- status = "disabled";
- };
-
- gpio@cd00 {
- reg = <0xcd00 0x100>;
- qcom,pin-num = <14>;
- status = "disabled";
- };
-
- gpio@ce00 {
- reg = <0xce00 0x100>;
- qcom,pin-num = <15>;
- status = "disabled";
- };
-
- gpio@cf00 {
- reg = <0xcf00 0x100>;
- qcom,pin-num = <16>;
- status = "disabled";
- };
-
- gpio@d000 {
- reg = <0xd000 0x100>;
- qcom,pin-num = <17>;
- status = "disabled";
- };
-
- gpio@d100 {
- reg = <0xd100 0x100>;
- qcom,pin-num = <18>;
- status = "disabled";
- };
-
- gpio@d200 {
- reg = <0xd200 0x100>;
- qcom,pin-num = <19>;
- status = "disabled";
- };
-
- gpio@d300 {
- reg = <0xd300 0x100>;
- qcom,pin-num = <20>;
- status = "disabled";
- };
-
- gpio@d400 {
- reg = <0xd400 0x100>;
- qcom,pin-num = <21>;
- status = "disabled";
- };
-
- gpio@d500 {
- reg = <0xd500 0x100>;
- qcom,pin-num = <22>;
- status = "disabled";
- };
-
- gpio@d600 {
- reg = <0xd600 0x100>;
- qcom,pin-num = <23>;
- status = "disabled";
- };
-
- gpio@d700 {
- reg = <0xd700 0x100>;
- qcom,pin-num = <24>;
- status = "disabled";
- };
-
- gpio@d800 {
- reg = <0xd800 0x100>;
- qcom,pin-num = <25>;
- status = "disabled";
- };
-
- gpio@d900 {
- reg = <0xd900 0x100>;
- qcom,pin-num = <26>;
- status = "disabled";
- };
+ qcom,gpios-disallowed = <3 15 20 22 24 25 26>;
};
pm8998_coincell: qcom,coincell@2800 {
diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
index 1659706..1f27b21 100644
--- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi
@@ -38,97 +38,29 @@
label = "pmi8998_tz";
};
- pmi8998_gpios: gpios {
- compatible = "qcom,qpnp-pin";
+ pmi8998_gpios: pinctrl@c000 {
+ compatible = "qcom,spmi-gpio";
+ reg = <0xc000 0xe00>;
+ interrupts = <0x2 0xc0 0 IRQ_TYPE_NONE>,
+ <0x2 0xc1 0 IRQ_TYPE_NONE>,
+ <0x2 0xc2 0 IRQ_TYPE_NONE>,
+ <0x2 0xc4 0 IRQ_TYPE_NONE>,
+ <0x2 0xc5 0 IRQ_TYPE_NONE>,
+ <0x2 0xc7 0 IRQ_TYPE_NONE>,
+ <0x2 0xc8 0 IRQ_TYPE_NONE>,
+ <0x2 0xc9 0 IRQ_TYPE_NONE>,
+ <0x2 0xca 0 IRQ_TYPE_NONE>,
+ <0x2 0xcb 0 IRQ_TYPE_NONE>,
+ <0x2 0xcd 0 IRQ_TYPE_NONE>;
+ interrupt-names = "pmi8998_gpio1", "pmi8998_gpio2",
+ "pmi8998_gpio3", "pmi8998_gpio5",
+ "pmi8998_gpio6", "pmi8998_gpio8",
+ "pmi8998_gpio9", "pmi8998_gpio10",
+ "pmi8998_gpio11", "pmi8998_gpio12",
+ "pmi8998_gpio14";
gpio-controller;
#gpio-cells = <2>;
- #address-cells = <1>;
- #size-cells = <1>;
- label = "pmi8998-gpio";
-
- gpio@c000 {
- reg = <0xc000 0x100>;
- qcom,pin-num = <1>;
- status = "disabled";
- };
-
- gpio@c100 {
- reg = <0xc100 0x100>;
- qcom,pin-num = <2>;
- status = "disabled";
- };
-
- gpio@c200 {
- reg = <0xc200 0x100>;
- qcom,pin-num = <3>;
- status = "disabled";
- };
-
- gpio@c300 {
- reg = <0xc300 0x100>;
- qcom,pin-num = <4>;
- status = "disabled";
- };
-
- gpio@c400 {
- reg = <0xc400 0x100>;
- qcom,pin-num = <5>;
- status = "disabled";
- };
-
- gpio@c500 {
- reg = <0xc500 0x100>;
- qcom,pin-num = <6>;
- status = "disabled";
- };
-
- gpio@c600 {
- reg = <0xc600 0x100>;
- qcom,pin-num = <7>;
- status = "disabled";
- };
-
- gpio@c700 {
- reg = <0xc700 0x100>;
- qcom,pin-num = <8>;
- status = "disabled";
- };
-
- gpio@c800 {
- reg = <0xc800 0x100>;
- qcom,pin-num = <9>;
- status = "disabled";
- };
-
- gpio@c900 {
- reg = <0xc900 0x100>;
- qcom,pin-num = <10>;
- status = "disabled";
- };
-
- gpio@ca00 {
- reg = <0xca00 0x100>;
- qcom,pin-num = <11>;
- status = "disabled";
- };
-
- gpio@cb00 {
- reg = <0xcb00 0x100>;
- qcom,pin-num = <12>;
- status = "disabled";
- };
-
- gpio@cc00 {
- reg = <0xcc00 0x100>;
- qcom,pin-num = <13>;
- status = "disabled";
- };
-
- gpio@cd00 {
- reg = <0xcd00 0x100>;
- qcom,pin-num = <14>;
- status = "disabled";
- };
+ qcom,gpios-disallowed = <4 7 13>;
};
pmi8998_rradc: rradc@4500 {
@@ -372,7 +304,7 @@
qcom,en-ext-pfet-sc-pro;
qcom,pmic-revid = <&pmi8998_revid>;
qcom,loop-auto-gm-en;
- status = "okay";
+ status = "disabled";
};
flash_led: qcom,leds@d300 {
diff --git a/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi
index a8d559c..4b3fa93 100644
--- a/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm830-pinctrl.dtsi
@@ -11,9 +11,9 @@
*/
&soc {
- tlmm: pinctrl@03800000 {
+ tlmm: pinctrl@03400000 {
compatible = "qcom,sdm830-pinctrl";
- reg = <0x03800000 0xc00000>;
+ reg = <0x03400000 0xc00000>;
interrupts = <0 208 0>;
gpio-controller;
#gpio-cells = <2>;
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-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
index 115c7b8..b66ca94 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi
@@ -27,7 +27,8 @@
reg = <0x170f700c 0x4>,
<0x170f7010 0x4>;
reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
- qcom,clk-div = <27>;
+ qcom,clk-div = <192>;
+ qcom,clk-mult = <10>;
};
sound-tavil {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
index 2d2b264..a51f411 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi
@@ -24,22 +24,38 @@
<0x1380000 0x40000>,
<0x1380000 0x40000>,
<0x1740000 0x40000>,
+ <0x1620000 0x40000>,
<0x1620000 0x40000>;
reg-names = "aggre1_noc-base", "aggre2_noc-base",
"config_noc-base", "dc_noc-base",
"gladiator_noc-base", "mc_virt-base", "mem_noc-base",
- "mmss_noc-base", "system_noc-base";
+ "mmss_noc-base", "system_noc-base", "ipa_virt-base";
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 +63,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 +71,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 +79,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 +87,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 +95,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 +103,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 +111,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 +119,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 +127,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 +135,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 +143,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,15 +151,7 @@
cell-id = <MSM_BUS_BCM_SH5>;
label = "SH5";
qcom,bcm-name = "SH5";
- qcom,drv-id = <2>;
- qcom,bcm-dev;
- };
-
- bcm_mm5: bcm-mm5 {
- 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 +159,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 +167,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 +175,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 +183,14 @@
cell-id = <MSM_BUS_BCM_CN0>;
label = "CN0";
qcom,bcm-name = "CN0";
- qcom,drv-id = <2>;
+ qcom,rscs = <&rsc_apps>;
+ qcom,bcm-dev;
+ };
+
+ bcm_qup0: bcm-qup0 {
+ cell-id = <MSM_BUS_BCM_QUP0>;
+ label = "QUP0";
+ qcom,bcm-name = "QUP0";
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;
};
@@ -382,6 +397,15 @@
clocks = <>;
};
+ fab_ipa_virt: fab-ipa_virt {
+ cell-id = <MSM_BUS_FAB_IPA_VIRT>;
+ label = "fab-ipa_virt";
+ qcom,fab-dev;
+ qcom,base-name = "ipa_virt-base";
+ qcom,bypass-qos-prg;
+ clocks = <>;
+ };
+
fab_mc_virt: fab-mc_virt {
cell-id = <MSM_BUS_FAB_MC_VIRT>;
label = "fab-mc_virt";
@@ -468,6 +492,7 @@
qcom,agg-ports = <1>;
qcom,connections = <&slv_qns_a1noc_snoc>;
qcom,bus-dev = <&fab_aggre1_noc>;
+ qcom,bcms = <&bcm_qup0>;
};
mas_qhm_tsif: mas-qhm-tsif {
@@ -544,6 +569,7 @@
qcom,agg-ports = <1>;
qcom,connections = <&slv_qns_a2noc_snoc>;
qcom,bus-dev = <&fab_aggre2_noc>;
+ qcom,bcms = <&bcm_qup0>;
};
mas_qnm_cnoc: mas-qnm-cnoc {
@@ -575,7 +601,6 @@
qcom,qport = <2>;
qcom,connections = <&slv_qns_a2noc_snoc>;
qcom,bus-dev = <&fab_aggre2_noc>;
- qcom,bcms = <&bcm_ip0>;
};
mas_xm_pcie3_1: mas-xm-pcie3-1 {
@@ -761,6 +786,15 @@
qcom,bus-dev = <&fab_gladiator_noc>;
};
+ mas_ipa_core: mas-ipa-core {
+ cell-id = <MSM_BUS_MASTER_IPA_CORE>;
+ label = "mas-ipa-core";
+ qcom,buswidth = <1>;
+ qcom,agg-ports = <1>;
+ qcom,connections = <&slv_ipa_core>;
+ qcom,bus-dev = <&fab_ipa_virt>;
+ };
+
mas_llcc_mc: mas-llcc-mc {
cell-id = <MSM_BUS_MASTER_LLCC>;
label = "mas-llcc-mc";
@@ -863,7 +897,6 @@
qcom,agg-ports = <1>;
qcom,connections = <&slv_srvc_mnoc>;
qcom,bus-dev = <&fab_mmss_noc>;
- qcom,bcms = <&bcm_mm5>;
};
mas_qxm_camnoc_hf: mas-qxm-camnoc-hf {
@@ -1586,6 +1619,15 @@
qcom,bus-dev = <&fab_gladiator_noc>;
};
+ slv_ipa_core:slv-ipa-core {
+ cell-id = <MSM_BUS_SLAVE_IPA>;
+ label = "slv-ipa-core";
+ qcom,buswidth = <1>;
+ qcom,agg-ports = <1>;
+ qcom,bus-dev = <&fab_ipa_virt>;
+ qcom,bcms = <&bcm_ip0>;
+ };
+
slv_ebi:slv-ebi {
cell-id = <MSM_BUS_SLAVE_EBI_CH0>;
label = "slv-ebi";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
index d47dd36..cd324e6 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-cdp.dtsi
@@ -10,8 +10,123 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/gpio/gpio.h>
+
&soc {
sound-tavil {
qcom,us-euro-gpios = <&tavil_us_euro_sw>;
};
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_home_default
+ &key_vol_up_default
+ &key_cam_snapshot_default
+ &key_cam_focus_default>;
+
+ home {
+ label = "home";
+ gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ cam_snapshot {
+ label = "cam_snapshot";
+ gpios = <&pm8998_gpios 7 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <766>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ cam_focus {
+ label = "cam_focus";
+ gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <528>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
+
+&ufsphy_mem {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_mem {
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm8998_l20>;
+ vccq2-supply = <&pm8998_s4>;
+ vcc-max-microamp = <600000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
+
+&ufsphy_card {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_card {
+ vdd-hba-supply = <&ufs_card_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm8998_l21>;
+ vccq2-supply = <&pm8998_s4>;
+ vcc-max-microamp = <300000>;
+ vccq2-max-microamp = <300000>;
+
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
+
+&pmi8998_flash2 {
+ pinctrl-names = "led_enable", "led_disable";
+ pinctrl-0 = <&flash_led3_front_en>;
+ pinctrl-1 = <&flash_led3_front_dis>;
+};
+
+&pmi8998_torch2 {
+ pinctrl-names = "led_enable", "led_disable";
+ pinctrl-0 = <&flash_led3_front_en>;
+ pinctrl-1 = <&flash_led3_front_dis>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
new file mode 100644
index 0000000..a6efb50
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi
@@ -0,0 +1,287 @@
+/* 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.
+ */
+
+&soc {
+
+ msm_bus: qcom,kgsl-busmon{
+ label = "kgsl-busmon";
+ compatible = "qcom,kgsl-busmon";
+ };
+
+ gpubw: qcom,gpubw {
+ compatible = "qcom,devbw";
+ governor = "bw_vbif";
+ qcom,src-dst-ports = <26 512>;
+ /*
+ * active-only flag is used while registering the bus
+ * governor.It helps release the bus vote when the CPU
+ * subsystem is inactiv3
+ */
+ qcom,active-only;
+ qcom,bw-tbl =
+ < 0 /* off */ >,
+ < 762 /* 100 MHz */ >,
+ < 1144 /* 150 MHz */ >,
+ < 1525 /* 200 MHz */ >,
+ < 2288 /* 300 MHz */ >,
+ < 3143 /* 412 MHz */ >,
+ < 4173 /* 547 MHz */ >,
+ < 5195 /* 681 MHz */ >,
+ < 5859 /* 768 MHz */ >,
+ < 7759 /* 1017 MHz */ >,
+ < 9887 /* 1296 MHz */ >,
+ < 11863 /* 1555 MHz */ >,
+ < 13763 /* 1804 MHz */ >;
+ };
+
+ msm_gpu: qcom,kgsl-3d0@5000000 {
+ label = "kgsl-3d0";
+ compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d";
+ status = "ok";
+ reg = <0x5000000 0x40000>;
+ reg-names = "kgsl_3d0_reg_memory";
+ interrupts = <0 300 0>;
+ interrupt-names = "kgsl_3d0_irq";
+ qcom,id = <0>;
+
+ qcom,chipid = <0x06030000>;
+
+ qcom,initial-pwrlevel = <2>;
+
+ qcom,gpu-quirk-hfi-use-reg;
+ qcom,gpu-quirk-two-pass-use-wfi;
+
+ qcom,idle-timeout = <100000000>; //msecs
+ qcom,no-nap;
+
+ qcom,highest-bank-bit = <15>;
+
+ qcom,min-access-length = <32>;
+
+ qcom,ubwc-mode = <2>;
+
+ qcom,snapshot-size = <1048576>; //bytes
+
+ qcom,gpu-qdss-stm = <0x161c0000 0x40000>; // base addr, size
+
+ qcom,tsens-name = "tsens_tz_sensor12";
+
+ clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK>,
+ <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+ <&clock_gpucc GPU_CC_CXO_CLK>,
+ <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+ <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+
+ clock-names = "core_clk", "iface_clk", "rbbmtimer_clk",
+ "mem_clk", "mem_iface_clk";
+
+ qcom,isense-clk-on-level = <1>;
+
+ /* Bus Scale Settings */
+ qcom,gpubw-dev = <&gpubw>;
+ qcom,bus-control;
+ qcom,msm-bus,name = "grp3d";
+ qcom,msm-bus,num-cases = <13>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 512 0 0>,
+
+ <26 512 0 800000>, // 1 bus=100
+ <26 512 0 1200000>, // 2 bus=150
+ <26 512 0 1600000>, // 3 bus=200
+ <26 512 0 2400000>, // 4 bus=300
+ <26 512 0 3296000>, // 5 bus=412
+ <26 512 0 4376000>, // 6 bus=547
+ <26 512 0 5448000>, // 7 bus=681
+ <26 512 0 6144000>, // 8 bus=768
+ <26 512 0 8136000>, // 9 bus=1017
+ <26 512 0 10368000>, // 10 bus=1296
+ <26 512 0 12440000>, // 11 bus=1555
+ <26 512 0 14432000>; // 12 bus=1804
+
+ /* GDSC regulator names */
+ regulator-names = "vddcx", "vdd";
+ /* GDSC oxili regulators */
+ vddcx-supply = <&gpu_cx_gdsc>;
+ vdd-supply = <&gpu_gx_gdsc>;
+
+ /* GPU related llc slices */
+ cache-slice-names = "gpu", "gpuhtw";
+ cache-slices = <&llcc 12>, <&llcc 11>;
+
+ /* GPU Mempools */
+ qcom,gpu-mempools {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,gpu-mempools";
+
+ /* 4K Page Pool configuration */
+ qcom,gpu-mempool@0 {
+ reg = <0>;
+ qcom,mempool-page-size = <4096>;
+ qcom,mempool-reserved = <2048>;
+ qcom,mempool-allocate;
+ };
+ /* 8K Page Pool configuration */
+ qcom,gpu-mempool@1 {
+ reg = <1>;
+ qcom,mempool-page-size = <8192>;
+ qcom,mempool-reserved = <1024>;
+ qcom,mempool-allocate;
+ };
+ /* 64K Page Pool configuration */
+ qcom,gpu-mempool@2 {
+ reg = <2>;
+ qcom,mempool-page-size = <65536>;
+ qcom,mempool-reserved = <256>;
+ };
+ /* 1M Page Pool configuration */
+ qcom,gpu-mempool@3 {
+ reg = <3>;
+ qcom,mempool-page-size = <1048576>;
+ qcom,mempool-reserved = <32>;
+ };
+ };
+
+ /* Power levels */
+ qcom,gpu-pwrlevels {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ compatible = "qcom,gpu-pwrlevels";
+
+ qcom,gpu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gpu-freq = <548000000>;
+ qcom,bus-freq = <12>;
+ qcom,bus-min = <11>;
+ qcom,bus-max = <12>;
+ };
+
+
+ qcom,gpu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gpu-freq = <425000000>;
+ qcom,bus-freq = <7>;
+ qcom,bus-min = <6>;
+ qcom,bus-max = <8>;
+ };
+
+ qcom,gpu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gpu-freq = <280000000>;
+ qcom,bus-freq = <4>;
+ qcom,bus-min = <3>;
+ qcom,bus-max = <5>;
+ };
+
+ qcom,gpu-pwrlevel@3 {
+ reg = <3>;
+ qcom,gpu-freq = <27000000>;
+ qcom,bus-freq = <0>;
+ qcom,bus-min = <0>;
+ qcom,bus-max = <0>;
+ };
+ };
+
+ };
+
+ kgsl_msm_iommu: qcom,kgsl-iommu {
+ compatible = "qcom,kgsl-smmu-v2";
+
+ reg = <0x05040000 0x10000>;
+ qcom,protect = <0x40000 0x10000>;
+ qcom,micro-mmu-control = <0x6000>;
+
+ clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+ <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+ <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+
+ clock-names = "iface_clk", "mem_clk", "mem_iface_clk";
+
+ qcom,secure_align_mask = <0xfff>;
+ qcom,global_pt;
+
+ gfx3d_user: gfx3d_user {
+ compatible = "qcom,smmu-kgsl-cb";
+ label = "gfx3d_user";
+ iommus = <&kgsl_smmu 0>;
+ qcom,gpu-offset = <0x48000>;
+ };
+
+ gfx3d_secure: gfx3d_secure {
+ compatible = "qcom,smmu-kgsl-cb";
+ iommus = <&kgsl_smmu 2>;
+ };
+ };
+
+ gmu: qcom,gmu {
+ label = "kgsl-gmu";
+ compatible = "qcom,gpu-gmu";
+
+ reg = <0x506a000 0x26000>, <0xb200000 0x300000>;
+ reg-names = "kgsl_gmu_reg", "kgsl_gmu_pdc_reg";
+
+ interrupts = <0 304 0>, <0 305 0>;
+ interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq";
+
+ qcom,msm-bus,name = "cnoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,vectors-KBps =
+ <26 10036 0 0>, // CNOC off
+ <26 10036 0 100>; // CNOC on
+
+ regulator-names = "vddcx", "vdd";
+ vddcx-supply = <&gpu_cx_gdsc>;
+ vdd-supply = <&gpu_gx_gdsc>;
+
+
+ clocks = <&clock_gpucc GPU_CC_CX_GMU_CLK>,
+ <&clock_gcc GCC_GPU_CFG_AHB_CLK>,
+ <&clock_gpucc GPU_CC_CXO_CLK>,
+ <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>,
+ <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>;
+
+ clock-names = "gmu_clk", "ahb_clk", "cxo_clk",
+ "axi_clk", "memnoc_clk";
+
+ qcom,gmu-pwrlevels {
+ compatible = "qcom,gmu-pwrlevels";
+
+ qcom,gmu-pwrlevel@0 {
+ reg = <0>;
+ qcom,gmu-freq = <400000000>;
+ };
+
+ qcom,gmu-pwrlevel@1 {
+ reg = <1>;
+ qcom,gmu-freq = <19200000>;
+ };
+
+ qcom,gmu-pwrlevel@2 {
+ reg = <2>;
+ qcom,gmu-freq = <0>;
+ };
+ };
+
+ gmu_user: gmu_user {
+ compatible = "qcom,smmu-gmu-user-cb";
+ iommus = <&kgsl_smmu 4>;
+ };
+
+ gmu_kernel: gmu_kernel {
+ compatible = "qcom,smmu-gmu-kernel-cb";
+ iommus = <&kgsl_smmu 5>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index cfba6f4..6d61506 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -9,3 +9,109 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+
+#include <dt-bindings/gpio/gpio.h>
+
+&soc {
+ gpio_keys {
+ compatible = "gpio-keys";
+ label = "gpio-keys";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&key_vol_up_default
+ &key_cam_snapshot_default
+ &key_cam_focus_default>;
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ cam_snapshot {
+ label = "cam_snapshot";
+ gpios = <&pm8998_gpios 7 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <766>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+
+ cam_focus {
+ label = "cam_focus";
+ gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>;
+ linux,input-type = <1>;
+ linux,code = <528>;
+ gpio-key,wakeup;
+ debounce-interval = <15>;
+ linux,can-disable;
+ };
+ };
+};
+
+&ufsphy_mem {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_mem {
+ vdd-hba-supply = <&ufs_phy_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm8998_l20>;
+ vccq2-supply = <&pm8998_s4>;
+ vcc-max-microamp = <600000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
+
+&ufsphy_card {
+ compatible = "qcom,ufs-phy-qmp-v3";
+
+ vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+
+ status = "ok";
+};
+
+&ufshc_card {
+ vdd-hba-supply = <&ufs_card_gdsc>;
+ vdd-hba-fixed-regulator;
+ vcc-supply = <&pm8998_l21>;
+ vccq2-supply = <&pm8998_s4>;
+ vcc-max-microamp = <300000>;
+ vccq2-max-microamp = <300000>;
+
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+ status = "ok";
+};
+
+&pmi8998_flash2 {
+ pinctrl-names = "led_enable", "led_disable";
+ pinctrl-0 = <&flash_led3_front_en>;
+ pinctrl-1 = <&flash_led3_front_dis>;
+};
+
+&pmi8998_torch2 {
+ pinctrl-names = "led_enable", "led_disable";
+ pinctrl-0 = <&flash_led3_front_en>;
+ pinctrl-1 = <&flash_led3_front_dis>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
index c5b53b8..f300684 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi
@@ -11,15 +11,79 @@
*/
&soc {
- tlmm: pinctrl@03800000 {
+ tlmm: pinctrl@03400000 {
compatible = "qcom,sdm845-pinctrl";
- reg = <0x03800000 0xc00000>;
+ reg = <0x03400000 0xc00000>;
interrupts = <0 208 0>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+ ufs_dev_reset_assert: ufs_dev_reset_assert {
+ config {
+ pins = "ufs_reset";
+ bias-pull-down; /* default: pull down */
+ /*
+ * UFS_RESET driver strengths are having
+ * different values/steps compared to typical
+ * GPIO drive strengths.
+ *
+ * Following table clarifies:
+ *
+ * HDRV value | UFS_RESET | Typical GPIO
+ * (dec) | (mA) | (mA)
+ * 0 | 0.8 | 2
+ * 1 | 1.55 | 4
+ * 2 | 2.35 | 6
+ * 3 | 3.1 | 8
+ * 4 | 3.9 | 10
+ * 5 | 4.65 | 12
+ * 6 | 5.4 | 14
+ * 7 | 6.15 | 16
+ *
+ * POR value for UFS_RESET HDRV is 3 which means
+ * 3.1mA and we want to use that. Hence just
+ * specify 8mA to "drive-strength" binding and
+ * that should result into writing 3 to HDRV
+ * field.
+ */
+ drive-strength = <8>; /* default: 3.1 mA */
+ output-low; /* active low reset */
+ };
+ };
+
+ ufs_dev_reset_deassert: ufs_dev_reset_deassert {
+ config {
+ pins = "ufs_reset";
+ bias-pull-down; /* default: pull down */
+ /*
+ * default: 3.1 mA
+ * check comments under ufs_dev_reset_assert
+ */
+ drive-strength = <8>;
+ output-high; /* active low reset */
+ };
+ };
+
+ flash_led3_front {
+ flash_led3_front_en: flash_led3_front_en {
+ mux {
+ pins = "gpio21";
+ drive_strength = <2>;
+ output-high;
+ };
+ };
+
+ flash_led3_front_dis: flash_led3_front_dis {
+ mux {
+ pins = "gpio21";
+ drive_strength = <2>;
+ output-low;
+ };
+ };
+ };
+
wcd9xxx_intr {
wcd_intr_default: wcd_intr_default{
mux {
@@ -1111,5 +1175,1145 @@
};
};
};
+
+ /* QUPv3 South SE mappings */
+ /* SE 0 pin mappings */
+ qupv3_se0_i2c_pins: qupv3_se0_i2c_pins {
+ qupv3_se0_i2c_active: qupv3_se0_i2c_active {
+ mux {
+ pins = "gpio0", "gpio1";
+ function = "qup0";
+ };
+
+ config {
+ pins = "gpio0", "gpio1";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se0_i2c_sleep: qupv3_se0_i2c_sleep {
+ mux {
+ pins = "gpio0", "gpio1";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio0", "gpio1";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se0_spi_pins: qupv3_se0_spi_pins {
+ qupv3_se0_spi_active: qupv3_se0_spi_active {
+ mux {
+ pins = "gpio0", "gpio1", "gpio2",
+ "gpio3";
+ function = "qup0";
+ };
+
+ config {
+ pins = "gpio0", "gpio1", "gpio2",
+ "gpio3";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se0_spi_sleep: qupv3_se0_spi_sleep {
+ mux {
+ pins = "gpio0", "gpio1", "gpio2",
+ "gpio3";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio0", "gpio1", "gpio2",
+ "gpio3";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 1 pin mappings */
+ qupv3_se1_i2c_pins: qupv3_se1_i2c_pins {
+ qupv3_se1_i2c_active: qupv3_se1_i2c_active {
+ mux {
+ pins = "gpio17", "gpio18";
+ function = "qup1";
+ };
+
+ config {
+ pins = "gpio17", "gpio18";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep {
+ mux {
+ pins = "gpio17", "gpio18";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio17", "gpio18";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se1_spi_pins: qupv3_se1_spi_pins {
+ qupv3_se1_spi_active: qupv3_se1_spi_active {
+ mux {
+ pins = "gpio17", "gpio18", "gpio19",
+ "gpio20";
+ function = "qup1";
+ };
+
+ config {
+ pins = "gpio17", "gpio18", "gpio19",
+ "gpio20";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se1_spi_sleep: qupv3_se1_spi_sleep {
+ mux {
+ pins = "gpio17", "gpio18", "gpio19",
+ "gpio20";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio17", "gpio18", "gpio19",
+ "gpio20";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 2 pin mappings */
+ qupv3_se2_i2c_pins: qupv3_se2_i2c_pins {
+ qupv3_se2_i2c_active: qupv3_se2_i2c_active {
+ mux {
+ pins = "gpio27", "gpio28";
+ function = "qup2";
+ };
+
+ config {
+ pins = "gpio27", "gpio28";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep {
+ mux {
+ pins = "gpio27", "gpio28";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio27", "gpio28";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se2_spi_pins: qupv3_se2_spi_pins {
+ qupv3_se2_spi_active: qupv3_se2_spi_active {
+ mux {
+ pins = "gpio27", "gpio28", "gpio29",
+ "gpio30";
+ function = "qup2";
+ };
+
+ config {
+ pins = "gpio27", "gpio28", "gpio29",
+ "gpio30";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se2_spi_sleep: qupv3_se2_spi_sleep {
+ mux {
+ pins = "gpio27", "gpio28", "gpio29",
+ "gpio30";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio27", "gpio28", "gpio29",
+ "gpio30";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 3 pin mappings */
+ qupv3_se3_i2c_pins: qupv3_se3_i2c_pins {
+ qupv3_se3_i2c_active: qupv3_se3_i2c_active {
+ mux {
+ pins = "gpio41", "gpio42";
+ function = "qup3";
+ };
+
+ config {
+ pins = "gpio41", "gpio42";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se3_i2c_sleep: qupv3_se3_i2c_sleep {
+ mux {
+ pins = "gpio41", "gpio42";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio41", "gpio42";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se3_spi_pins: qupv3_se3_spi_pins {
+ qupv3_se3_spi_active: qupv3_se3_spi_active {
+ mux {
+ pins = "gpio41", "gpio42", "gpio43",
+ "gpio44";
+ function = "qup3";
+ };
+
+ config {
+ pins = "gpio41", "gpio42", "gpio43",
+ "gpio44";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se3_spi_sleep: qupv3_se3_spi_sleep {
+ mux {
+ pins = "gpio41", "gpio42", "gpio43",
+ "gpio44";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio41", "gpio42", "gpio43",
+ "gpio44";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 4 pin mappings */
+ qupv3_se4_i2c_pins: qupv3_se4_i2c_pins {
+ qupv3_se4_i2c_active: qupv3_se4_i2c_active {
+ mux {
+ pins = "gpio89", "gpio90";
+ function = "qup4";
+ };
+
+ config {
+ pins = "gpio89", "gpio90";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep {
+ mux {
+ pins = "gpio89", "gpio90";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio89", "gpio90";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se4_spi_pins: qupv3_se4_spi_pins {
+ qupv3_se4_spi_active: qupv3_se4_spi_active {
+ mux {
+ pins = "gpio89", "gpio90", "gpio91",
+ "gpio92";
+ function = "qup4";
+ };
+
+ config {
+ pins = "gpio89", "gpio90", "gpio91",
+ "gpio92";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se4_spi_sleep: qupv3_se4_spi_sleep {
+ mux {
+ pins = "gpio89", "gpio90", "gpio91",
+ "gpio92";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio89", "gpio90", "gpio91",
+ "gpio92";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 5 pin mappings */
+ qupv3_se5_i2c_pins: qupv3_se5_i2c_pins {
+ qupv3_se5_i2c_active: qupv3_se5_i2c_active {
+ mux {
+ pins = "gpio85", "gpio86";
+ function = "qup5";
+ };
+
+ config {
+ pins = "gpio85", "gpio86";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep {
+ mux {
+ pins = "gpio85", "gpio86";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio85", "gpio86";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se5_spi_pins: qupv3_se5_spi_pins {
+ qupv3_se5_spi_active: qupv3_se5_spi_active {
+ mux {
+ pins = "gpio85", "gpio86", "gpio87",
+ "gpio88";
+ function = "qup5";
+ };
+
+ config {
+ pins = "gpio85", "gpio86", "gpio87",
+ "gpio88";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se5_spi_sleep: qupv3_se5_spi_sleep {
+ mux {
+ pins = "gpio85", "gpio86", "gpio87",
+ "gpio88";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio85", "gpio86", "gpio87",
+ "gpio88";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 6 pin mappings */
+ qupv3_se6_i2c_pins: qupv3_se6_i2c_pins {
+ qupv3_se6_i2c_active: qupv3_se6_i2c_active {
+ mux {
+ pins = "gpio45", "gpio46";
+ function = "qup6";
+ };
+
+ config {
+ pins = "gpio45", "gpio46";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep {
+ mux {
+ pins = "gpio45", "gpio46";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio45", "gpio46";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se6_4uart_pins: qupv3_se6_4uart_pins {
+ qupv3_se6_4uart_active: qupv3_se6_4uart_active {
+ mux {
+ pins = "gpio45", "gpio46", "gpio47",
+ "gpio48";
+ function = "qup6";
+ };
+
+ config {
+ pins = "gpio45", "gpio46", "gpio47",
+ "gpio48";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se6_4uart_sleep: qupv3_se6_4uart_sleep {
+ mux {
+ pins = "gpio45", "gpio46", "gpio47",
+ "gpio48";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio45", "gpio46", "gpio47",
+ "gpio48";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ qupv3_se6_spi_pins: qupv3_se6_spi_pins {
+ qupv3_se6_spi_active: qupv3_se6_spi_active {
+ mux {
+ pins = "gpio45", "gpio46", "gpio47",
+ "gpio48";
+ function = "qup6";
+ };
+
+ config {
+ pins = "gpio45", "gpio46", "gpio47",
+ "gpio48";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se6_spi_sleep: qupv3_se6_spi_sleep {
+ mux {
+ pins = "gpio45", "gpio46", "gpio47",
+ "gpio48";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio45", "gpio46", "gpio47",
+ "gpio48";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 7 pin mappings */
+ qupv3_se7_i2c_pins: qupv3_se7_i2c_pins {
+ qupv3_se7_i2c_active: qupv3_se7_i2c_active {
+ mux {
+ pins = "gpio93", "gpio94";
+ function = "qup7";
+ };
+
+ config {
+ pins = "gpio93", "gpio94";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep {
+ mux {
+ pins = "gpio93", "gpio94";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio93", "gpio94";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se7_4uart_pins: qupv3_se7_4uart_pins {
+ qupv3_se7_4uart_active: qupv3_se7_4uart_active {
+ mux {
+ pins = "gpio93", "gpio94", "gpio95",
+ "gpio96";
+ function = "qup7";
+ };
+
+ config {
+ pins = "gpio93", "gpio94", "gpio95",
+ "gpio96";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se7_4uart_sleep: qupv3_se7_4uart_sleep {
+ mux {
+ pins = "gpio93", "gpio94", "gpio95",
+ "gpio96";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio93", "gpio94", "gpio95",
+ "gpio96";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ qupv3_se7_spi_pins: qupv3_se7_spi_pins {
+ qupv3_se7_spi_active: qupv3_se7_spi_active {
+ mux {
+ pins = "gpio93", "gpio94", "gpio95",
+ "gpio96";
+ function = "qup7";
+ };
+
+ config {
+ pins = "gpio93", "gpio94", "gpio95",
+ "gpio96";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se7_spi_sleep: qupv3_se7_spi_sleep {
+ mux {
+ pins = "gpio93", "gpio94", "gpio95",
+ "gpio96";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio93", "gpio94", "gpio95",
+ "gpio96";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* QUPv3 North instances */
+ /* SE 8 pin mappings */
+ qupv3_se8_i2c_pins: qupv3_se8_i2c_pins {
+ qupv3_se8_i2c_active: qupv3_se8_i2c_active {
+ mux {
+ pins = "gpio65", "gpio66";
+ function = "qup8";
+ };
+
+ config {
+ pins = "gpio65", "gpio66";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep {
+ mux {
+ pins = "gpio65", "gpio66";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio65", "gpio66";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se8_spi_pins: qupv3_se8_spi_pins {
+ qupv3_se8_spi_active: qupv3_se8_spi_active {
+ mux {
+ pins = "gpio65", "gpio66", "gpio67",
+ "gpio68";
+ function = "qup8";
+ };
+
+ config {
+ pins = "gpio65", "gpio66", "gpio67",
+ "gpio68";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se8_spi_sleep: qupv3_se8_spi_sleep {
+ mux {
+ pins = "gpio65", "gpio66", "gpio67",
+ "gpio68";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio65", "gpio66", "gpio67",
+ "gpio68";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 9 pin mappings */
+ qupv3_se9_i2c_pins: qupv3_se9_i2c_pins {
+ qupv3_se9_i2c_active: qupv3_se9_i2c_active {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "qup9";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se9_i2c_sleep: qupv3_se9_i2c_sleep {
+ mux {
+ pins = "gpio6", "gpio7";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se9_2uart_pins: qupv3_se9_2uart_pins {
+ qupv3_se9_2uart_active: qupv3_se9_2uart_active {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "qup9";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se9_2uart_sleep: qupv3_se9_2uart_sleep {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ qupv3_se9_spi_pins: qupv3_se9_spi_pins {
+ qupv3_se9_spi_active: qupv3_se9_spi_active {
+ mux {
+ pins = "gpio4", "gpio5", "gpio6",
+ "gpio7";
+ function = "qup9";
+ };
+
+ config {
+ pins = "gpio4", "gpio5", "gpio6",
+ "gpio7";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se9_spi_sleep: qupv3_se9_spi_sleep {
+ mux {
+ pins = "gpio4", "gpio5", "gpio6",
+ "gpio7";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio4", "gpio5", "gpio6",
+ "gpio7";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 10 pin mappings */
+ qupv3_se10_i2c_pins: qupv3_se10_i2c_pins {
+ qupv3_se10_i2c_active: qupv3_se10_i2c_active {
+ mux {
+ pins = "gpio55", "gpio56";
+ function = "qup10";
+ };
+
+ config {
+ pins = "gpio55", "gpio56";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep {
+ mux {
+ pins = "gpio55", "gpio56";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio55", "gpio56";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se10_2uart_pins: qupv3_se10_2uart_pins {
+ qupv3_se10_2uart_active: qupv3_se10_2uart_active {
+ mux {
+ pins = "gpio53", "gpio54";
+ function = "qup10";
+ };
+
+ config {
+ pins = "gpio53", "gpio54";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se10_2uart_sleep: qupv3_se10_2uart_sleep {
+ mux {
+ pins = "gpio53", "gpio54";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio53", "gpio54";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ qupv3_se10_spi_pins: qupv3_se10_spi_pins {
+ qupv3_se10_spi_active: qupv3_se10_spi_active {
+ mux {
+ pins = "gpio53", "gpio54", "gpio55",
+ "gpio56";
+ function = "qup10";
+ };
+
+ config {
+ pins = "gpio53", "gpio54", "gpio55",
+ "gpio56";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se10_spi_sleep: qupv3_se10_spi_sleep {
+ mux {
+ pins = "gpio53", "gpio54", "gpio55",
+ "gpio56";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio53", "gpio54", "gpio55",
+ "gpio56";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 11 pin mappings */
+ qupv3_se11_i2c_pins: qupv3_se11_i2c_pins {
+ qupv3_se11_i2c_active: qupv3_se11_i2c_active {
+ mux {
+ pins = "gpio31", "gpio32";
+ function = "qup11";
+ };
+
+ config {
+ pins = "gpio31", "gpio32";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se11_i2c_sleep: qupv3_se11_i2c_sleep {
+ mux {
+ pins = "gpio31", "gpio32";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31", "gpio32";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se11_spi_pins: qupv3_se11_spi_pins {
+ qupv3_se11_spi_active: qupv3_se11_spi_active {
+ mux {
+ pins = "gpio31", "gpio32", "gpio33",
+ "gpio34";
+ function = "qup11";
+ };
+
+ config {
+ pins = "gpio31", "gpio32", "gpio33",
+ "gpio34";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se11_spi_sleep: qupv3_se11_spi_sleep {
+ mux {
+ pins = "gpio31", "gpio32", "gpio33",
+ "gpio34";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31", "gpio32", "gpio33",
+ "gpio34";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 12 pin mappings */
+ qupv3_se12_i2c_pins: qupv3_se12_i2c_pins {
+ qupv3_se12_i2c_active: qupv3_se12_i2c_active {
+ mux {
+ pins = "gpio49", "gpio50";
+ function = "qup12";
+ };
+
+ config {
+ pins = "gpio49", "gpio50";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se12_i2c_sleep: qupv3_se12_i2c_sleep {
+ mux {
+ pins = "gpio49", "gpio50";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio49", "gpio50";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se12_spi_pins: qupv3_se12_spi_pins {
+ qupv3_se12_spi_active: qupv3_se12_spi_active {
+ mux {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ function = "qup12";
+ };
+
+ config {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se12_spi_sleep: qupv3_se12_spi_sleep {
+ mux {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio49", "gpio50", "gpio51",
+ "gpio52";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 13 pin mappings */
+ qupv3_se13_i2c_pins: qupv3_se13_i2c_pins {
+ qupv3_se13_i2c_active: qupv3_se13_i2c_active {
+ mux {
+ pins = "gpio105", "gpio106";
+ function = "qup13";
+ };
+
+ config {
+ pins = "gpio105", "gpio106";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se13_i2c_sleep: qupv3_se13_i2c_sleep {
+ mux {
+ pins = "gpio105", "gpio106";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio105", "gpio106";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se13_spi_pins: qupv3_se13_spi_pins {
+ qupv3_se13_spi_active: qupv3_se13_spi_active {
+ mux {
+ pins = "gpio105", "gpio106", "gpio107",
+ "gpio108";
+ function = "qup13";
+ };
+
+ config {
+ pins = "gpio105", "gpio106", "gpio107",
+ "gpio108";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se13_spi_sleep: qupv3_se13_spi_sleep {
+ mux {
+ pins = "gpio105", "gpio106", "gpio107",
+ "gpio108";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio105", "gpio106", "gpio107",
+ "gpio108";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 14 pin mappings */
+ qupv3_se14_i2c_pins: qupv3_se14_i2c_pins {
+ qupv3_se14_i2c_active: qupv3_se14_i2c_active {
+ mux {
+ pins = "gpio33", "gpio34";
+ function = "qup14";
+ };
+
+ config {
+ pins = "gpio33", "gpio34";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se14_i2c_sleep: qupv3_se14_i2c_sleep {
+ mux {
+ pins = "gpio33", "gpio34";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio33", "gpio34";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se14_spi_pins: qupv3_se14_spi_pins {
+ qupv3_se14_spi_active: qupv3_se14_spi_active {
+ mux {
+ pins = "gpio31", "gpio32", "gpio33",
+ "gpio34";
+ function = "qup14";
+ };
+
+ config {
+ pins = "gpio31", "gpio32", "gpio33",
+ "gpio34";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se14_spi_sleep: qupv3_se14_spi_sleep {
+ mux {
+ pins = "gpio31", "gpio32", "gpio33",
+ "gpio34";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio31", "gpio32", "gpio33",
+ "gpio34";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+
+ /* SE 15 pin mappings */
+ qupv3_se15_i2c_pins: qupv3_se15_i2c_pins {
+ qupv3_se15_i2c_active: qupv3_se15_i2c_active {
+ mux {
+ pins = "gpio81", "gpio82";
+ function = "qup15";
+ };
+
+ config {
+ pins = "gpio81", "gpio82";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se15_i2c_sleep: qupv3_se15_i2c_sleep {
+ mux {
+ pins = "gpio81", "gpio82";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio81", "gpio82";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+ };
+
+ qupv3_se15_spi_pins: qupv3_se15_spi_pins {
+ qupv3_se15_spi_active: qupv3_se15_spi_active {
+ mux {
+ pins = "gpio81", "gpio82", "gpio83",
+ "gpio84";
+ function = "qup15";
+ };
+
+ config {
+ pins = "gpio81", "gpio82", "gpio83",
+ "gpio84";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+
+ qupv3_se15_spi_sleep: qupv3_se15_spi_sleep {
+ mux {
+ pins = "gpio81", "gpio82", "gpio83",
+ "gpio84";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio81", "gpio82", "gpio83",
+ "gpio84";
+ drive-strength = <6>;
+ bias-disable;
+ };
+ };
+ };
+ };
+};
+
+&pm8998_gpios {
+ key_home {
+ key_home_default: key_home_default {
+ pins = "gpio5";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+ };
+
+ key_vol_up {
+ key_vol_up_default: key_vol_up_default {
+ pins = "gpio6";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+ };
+
+ key_cam_snapshot {
+ key_cam_snapshot_default: key_cam_snapshot_default {
+ pins = "gpio7";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
+ };
+
+ key_cam_focus {
+ key_cam_focus_default: key_cam_focus_default {
+ pins = "gpio8";
+ function = "normal";
+ input-enable;
+ bias-pull-up;
+ power-source = <0>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
new file mode 100644
index 0000000..1c31a7a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi
@@ -0,0 +1,632 @@
+/* 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.
+ */
+
+&soc {
+ /* QUPv3 South instances */
+
+ /*
+ * HS UART instances. HS UART usecases can be supported on these
+ * instances only.
+ */
+ qupv3_se6_4uart: qcom,qup_uart@0x898000 {
+ compatible = "qcom,msm-geni-serial-hs", "qcom,msm-geni-uart";
+ reg = <0x898000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se6_4uart_active>;
+ pinctrl-1 = <&qupv3_se6_4uart_sleep>;
+ interrupts = <GIC_SPI 607 0>;
+ status = "disabled";
+ };
+
+ qupv3_se7_4uart: qcom,qup_uart@0x89c000 {
+ compatible = "qcom,msm-geni-serial-hs", "qcom,msm-geni-uart";
+ reg = <0x89c000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se7_4uart_active>;
+ pinctrl-1 = <&qupv3_se7_4uart_sleep>;
+ interrupts = <GIC_SPI 608 0>;
+ status = "disabled";
+ };
+
+ /* I2C */
+ qupv3_se0_i2c: i2c@880000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0x880000 0x4000>;
+ interrupts = <GIC_SPI 601 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se0_i2c_active>;
+ pinctrl-1 = <&qupv3_se0_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se1_i2c: i2c@884000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0x884000 0x4000>;
+ interrupts = <GIC_SPI 602 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se1_i2c_active>;
+ pinctrl-1 = <&qupv3_se1_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se2_i2c: i2c@888000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0x888000 0x4000>;
+ interrupts = <GIC_SPI 603 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se2_i2c_active>;
+ pinctrl-1 = <&qupv3_se2_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se3_i2c: i2c@88c000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0x88c000 0x4000>;
+ interrupts = <GIC_SPI 604 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se3_i2c_active>;
+ pinctrl-1 = <&qupv3_se3_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se4_i2c: i2c@890000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0x890000 0x4000>;
+ interrupts = <GIC_SPI 605 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se4_i2c_active>;
+ pinctrl-1 = <&qupv3_se4_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se5_i2c: i2c@894000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0x894000 0x4000>;
+ interrupts = <GIC_SPI 606 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se5_i2c_active>;
+ pinctrl-1 = <&qupv3_se5_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se6_i2c: i2c@898000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0x898000 0x4000>;
+ interrupts = <GIC_SPI 607 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se6_i2c_active>;
+ pinctrl-1 = <&qupv3_se6_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se7_i2c: i2c@89c000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0x89c000 0x4000>;
+ interrupts = <GIC_SPI 608 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se7_i2c_active>;
+ pinctrl-1 = <&qupv3_se7_i2c_sleep>;
+ status = "disabled";
+ };
+
+ /* SPI */
+ qupv3_se0_spi: spi@880000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x880000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S0_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se0_spi_active>;
+ pinctrl-1 = <&qupv3_se0_spi_sleep>;
+ interrupts = <GIC_SPI 601 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se1_spi: spi@884000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x884000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S1_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se1_spi_active>;
+ pinctrl-1 = <&qupv3_se1_spi_sleep>;
+ interrupts = <GIC_SPI 602 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se2_spi: spi@888000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x888000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S2_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se2_spi_active>;
+ pinctrl-1 = <&qupv3_se2_spi_sleep>;
+ interrupts = <GIC_SPI 603 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se3_spi: spi@88c000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x88c000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S3_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se3_spi_active>;
+ pinctrl-1 = <&qupv3_se3_spi_sleep>;
+ interrupts = <GIC_SPI 604 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se4_spi: spi@890000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x890000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S4_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se4_spi_active>;
+ pinctrl-1 = <&qupv3_se4_spi_sleep>;
+ interrupts = <GIC_SPI 605 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se5_spi: spi@894000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x894000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S5_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se5_spi_active>;
+ pinctrl-1 = <&qupv3_se5_spi_sleep>;
+ interrupts = <GIC_SPI 606 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se6_spi: spi@898000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x898000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S6_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se6_spi_active>;
+ pinctrl-1 = <&qupv3_se6_spi_sleep>;
+ interrupts = <GIC_SPI 607 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se7_spi: spi@89c000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x89c000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP0_S7_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se7_spi_active>;
+ pinctrl-1 = <&qupv3_se7_spi_sleep>;
+ interrupts = <GIC_SPI 608 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ /* QUPv3 North Instances */
+ /* 2-wire UART */
+
+ /* Debug UART Instance for CDP/MTP platform */
+ qupv3_se9_2uart: qcom,qup_uart@0xa84000 {
+ compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart";
+ reg = <0xa84000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se9_2uart_active>;
+ pinctrl-1 = <&qupv3_se9_2uart_sleep>;
+ interrupts = <GIC_SPI 354 0>;
+ status = "disabled";
+ };
+
+ /* Debug UART Instance for RUMI platform */
+ qupv3_se10_2uart: qcom,qup_uart@0xa88000 {
+ compatible = "qcom,msm-geni-console", "qcom,msm-geni-uart";
+ reg = <0xa88000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se10_2uart_active>;
+ pinctrl-1 = <&qupv3_se10_2uart_sleep>;
+ interrupts = <GIC_SPI 355 0>;
+ status = "disabled";
+ };
+
+ /* I2C */
+ qupv3_se8_i2c: i2c@a80000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0xa80000 0x4000>;
+ interrupts = <GIC_SPI 353 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se8_i2c_active>;
+ pinctrl-1 = <&qupv3_se8_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se9_i2c: i2c@a84000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0xa84000 0x4000>;
+ interrupts = <GIC_SPI 354 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se9_i2c_active>;
+ pinctrl-1 = <&qupv3_se9_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se10_i2c: i2c@a88000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0xa88000 0x4000>;
+ interrupts = <GIC_SPI 355 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se10_i2c_active>;
+ pinctrl-1 = <&qupv3_se10_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se11_i2c: i2c@a8c000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0xa8c000 0x4000>;
+ interrupts = <GIC_SPI 356 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se11_i2c_active>;
+ pinctrl-1 = <&qupv3_se11_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se12_i2c: i2c@a90000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0xa90000 0x4000>;
+ interrupts = <GIC_SPI 357 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se12_i2c_active>;
+ pinctrl-1 = <&qupv3_se12_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se13_i2c: i2c@a94000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0xa94000 0x4000>;
+ interrupts = <GIC_SPI 358 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se13_i2c_active>;
+ pinctrl-1 = <&qupv3_se13_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se14_i2c: i2c@a98000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0xa98000 0x4000>;
+ interrupts = <GIC_SPI 359 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se14_i2c_active>;
+ pinctrl-1 = <&qupv3_se14_i2c_sleep>;
+ status = "disabled";
+ };
+
+ qupv3_se15_i2c: i2c@a9c000 {
+ compatible = "qcom,i2c-geni";
+ reg = <0xa9c000 0x4000>;
+ interrupts = <GIC_SPI 360 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se15_i2c_active>;
+ pinctrl-1 = <&qupv3_se15_i2c_sleep>;
+ status = "disabled";
+ };
+
+ /* SPI */
+ qupv3_se8_spi: spi@a80000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xa80000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S0_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se8_spi_active>;
+ pinctrl-1 = <&qupv3_se8_spi_sleep>;
+ interrupts = <GIC_SPI 353 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se9_spi: spi@a84000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xa84000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S1_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se9_spi_active>;
+ pinctrl-1 = <&qupv3_se9_spi_sleep>;
+ interrupts = <GIC_SPI 354 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se10_spi: spi@a88000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xa88000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S2_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se10_spi_active>;
+ pinctrl-1 = <&qupv3_se10_spi_sleep>;
+ interrupts = <GIC_SPI 355 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se11_spi: spi@a8c000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xa8c000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S3_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se11_spi_active>;
+ pinctrl-1 = <&qupv3_se11_spi_sleep>;
+ interrupts = <GIC_SPI 356 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se12_spi: spi@a90000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xa90000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S4_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se12_spi_active>;
+ pinctrl-1 = <&qupv3_se12_spi_sleep>;
+ interrupts = <GIC_SPI 357 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se13_spi: spi@a94000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xa94000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S5_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se13_spi_active>;
+ pinctrl-1 = <&qupv3_se13_spi_sleep>;
+ interrupts = <GIC_SPI 358 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se14_spi: spi@a98000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xa98000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se14_spi_active>;
+ pinctrl-1 = <&qupv3_se14_spi_sleep>;
+ interrupts = <GIC_SPI 359 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+
+ qupv3_se15_spi: spi@a9c000 {
+ compatible = "qcom,spi-geni";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xa9c000 0x4000>;
+ reg-names = "se_phys";
+ clock-names = "se-clk", "m-ahb", "s-ahb";
+ clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qupv3_se15_spi_active>;
+ pinctrl-1 = <&qupv3_se15_spi_sleep>;
+ interrupts = <GIC_SPI 360 0>;
+ spi-max-frequency = <50000000>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
index 67dd934..540f82f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi
@@ -391,7 +391,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l1: regulator-l1 {
regulator-name = "pm8998_l1";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -409,7 +409,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 30000>;
pm8998_l2: regulator-l2 {
regulator-name = "pm8998_l2";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -427,7 +427,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l3: regulator-l3 {
regulator-name = "pm8998_l3";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -458,7 +458,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l5: regulator-l5 {
regulator-name = "pm8998_l5";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -476,7 +476,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l6: regulator-l6 {
regulator-name = "pm8998_l6";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -494,7 +494,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l7: regulator-l7 {
regulator-name = "pm8998_l7";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -512,7 +512,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l8: regulator-l8 {
regulator-name = "pm8998_l8";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -530,7 +530,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l9: regulator-l9 {
regulator-name = "pm8998_l9";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -548,7 +548,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l10: regulator-l10 {
regulator-name = "pm8998_l10";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -566,7 +566,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l11: regulator-l11 {
regulator-name = "pm8998_l11";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -584,7 +584,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l12: regulator-l12 {
regulator-name = "pm8998_l12";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -638,7 +638,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l15: regulator-l15 {
regulator-name = "pm8998_l15";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -656,7 +656,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l16: regulator-l16 {
regulator-name = "pm8998_l16";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -674,7 +674,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l17: regulator-l17 {
regulator-name = "pm8998_l17";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -692,7 +692,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l18: regulator-l18 {
regulator-name = "pm8998_l18";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -710,7 +710,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l19: regulator-l19 {
regulator-name = "pm8998_l19";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -782,7 +782,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l23: regulator-l23 {
regulator-name = "pm8998_l23";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -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>;
@@ -818,7 +819,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l25: regulator-l25 {
regulator-name = "pm8998_l25";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -836,7 +837,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l26: regulator-l26 {
regulator-name = "pm8998_l26";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
@@ -867,7 +868,7 @@
qcom,supported-modes =
<RPMH_REGULATOR_MODE_LDO_LPM
RPMH_REGULATOR_MODE_LDO_HPM>;
- qcom,mode-threshold-currents = <0 10000>;
+ qcom,mode-threshold-currents = <0 1>;
pm8998_l28: regulator-l28 {
regulator-name = "pm8998_l28";
qcom,set = <RPMH_REGULATOR_SET_ALL>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
index 124ed99..80f34bf 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-rumi.dtsi
@@ -17,11 +17,8 @@
vdda-phy-supply = <&pm8998_l1>;
vdda-pll-supply = <&pm8998_l2>;
- vddp-ref-clk-supply = <&pm8998_l26>;
vdda-phy-max-microamp = <44000>;
vdda-pll-max-microamp = <14600>;
- vddp-ref-clk-max-microamp = <100>;
- vddp-ref-clk-always-on;
status = "ok";
};
@@ -38,6 +35,9 @@
vcc-max-microamp = <600000>;
vccq2-max-microamp = <600000>;
+ qcom,vddp-ref-clk-supply = <&pm8998_l26>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
qcom,disable-lpm;
rpm-level = <0>;
spm-level = <0>;
@@ -122,11 +122,8 @@
vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
- vddp-ref-clk-supply = <&pm8998_l2>;
vdda-phy-max-microamp = <62900>;
vdda-pll-max-microamp = <18300>;
- vddp-ref-clk-max-microamp = <100>;
- vddp-ref-clk-always-on;
status = "ok";
};
@@ -142,6 +139,9 @@
vcc-max-microamp = <300000>;
vccq2-max-microamp = <300000>;
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
qcom,disable-lpm;
rpm-level = <0>;
spm-level = <0>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
index 5d81487..2ff9b2f 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi
@@ -23,7 +23,6 @@
#include "dsi-panel-sharp-1080p-cmd.dtsi"
#include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi"
#include "dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi"
-#include "sdm845-pinctrl.dtsi"
&soc {
dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -102,7 +101,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 +124,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 +147,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 +170,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 +193,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 +216,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 +239,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 +262,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>;
@@ -294,3 +293,45 @@
&mdss_mdp {
connectors = <&sde_wb>;
};
+
+&dsi_dual_nt35597_truly_video {
+ qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04];
+ qcom,mdss-dsi-t-clk-post = <0x0D>;
+ qcom,mdss-dsi-t-clk-pre = <0x2D>;
+};
+
+&dsi_dual_nt35597_truly_cmd {
+ qcom,mdss-dsi-panel-timings = [00 1c 07 07 23 21 07 07 05 03 04];
+ qcom,mdss-dsi-t-clk-post = <0x0D>;
+ qcom,mdss-dsi-t-clk-pre = <0x2D>;
+};
+
+&dsi_nt35597_truly_dsc_cmd {
+ qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04];
+ qcom,mdss-dsi-t-clk-post = <0x0b>;
+ qcom,mdss-dsi-t-clk-pre = <0x23>;
+};
+
+&dsi_nt35597_truly_dsc_video {
+ qcom,mdss-dsi-panel-timings = [00 15 05 05 20 1f 05 05 03 03 04];
+ qcom,mdss-dsi-t-clk-post = <0x0b>;
+ qcom,mdss-dsi-t-clk-pre = <0x23>;
+};
+
+&dsi_sharp_4k_dsc_video {
+ qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04];
+ qcom,mdss-dsi-t-clk-post = <0x0a>;
+ qcom,mdss-dsi-t-clk-pre = <0x1e>;
+};
+
+&dsi_sharp_4k_dsc_cmd {
+ qcom,mdss-dsi-panel-timings = [00 12 04 04 1e 1e 04 04 02 03 04];
+ qcom,mdss-dsi-t-clk-post = <0x0a>;
+ qcom,mdss-dsi-t-clk-pre = <0x1e>;
+};
+
+&dsi_dual_sharp_1080_120hz_cmd {
+ qcom,mdss-dsi-panel-timings = [00 24 09 09 26 24 09 09 06 03 04];
+ qcom,mdss-dsi-t-clk-post = <0x0f>;
+ qcom,mdss-dsi-t-clk-pre = <0x36>;
+};
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-usb.dtsi b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
index 7f090ad..1c66f89 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-usb.dtsi
@@ -20,6 +20,7 @@
<0x088ee000 0x400>;
reg-names = "core_base", "ahb2phy_base";
iommus = <&apps_smmu 0x740>;
+ qcom,smmu-s1-bypass;
#address-cells = <1>;
#size-cells = <1>;
ranges;
@@ -76,16 +77,26 @@
vdda33-supply = <&pm8998_l24>;
qcom,vdd-voltage-level = <0 880000 880000>;
qcom,qusb-phy-init-seq =
- /* <value reg_offset> */
- <0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */
- 0x7c 0x18c /* PLL_CLOCK_INVERTERS */
- 0x80 0x2c /* PLL_CMODE */
- 0x0a 0x184 /* PLL_LOCK_DELAY */
- 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */
- 0xa5 0x240 /* TUNE1 */
- 0x09 0x244 /* TUNE2 */
- 0x00 0x220 /* IMP_CTRL1 */
- 0x58 0x224>; /* IMP_CTRL2 */
+ /* <value reg_offset> */
+ <0x23 0x210 /* PWR_CTRL1 */
+ 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */
+ 0x7c 0x18c /* PLL_CLOCK_INVERTERS */
+ 0x80 0x2c /* PLL_CMODE */
+ 0x0a 0x184 /* PLL_LOCK_DELAY */
+ 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */
+ 0x40 0x194 /* PLL_BIAS_CONTROL_1 */
+ 0x20 0x198 /* PLL_BIAS_CONTROL_2 */
+ 0x21 0x214 /* PWR_CTRL2 */
+ 0x00 0x220 /* IMP_CTRL1 */
+ 0x58 0x224 /* IMP_CTRL2 */
+ 0x32 0x240 /* TUNE1 */
+ 0x29 0x244 /* TUNE2 */
+ 0xca 0x248 /* TUNE3 */
+ 0x04 0x24c /* TUNE4 */
+ 0x00 0x250 /* TUNE5 */
+ 0x00 0x23c /* CHG_CTRL2 */
+ 0x22 0x210>; /* PWR_CTRL1 */
+
phy_type= "utmi";
clocks = <&clock_rpmh RPMH_CXO_CLK>,
<&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
@@ -112,6 +123,7 @@
<0x088ee000 0x400>;
reg-names = "core_base", "ahb2phy_base";
iommus = <&apps_smmu 0x760>;
+ qcom,smmu-s1-bypass;
#address-cells = <1>;
#size-cells = <1>;
ranges;
@@ -165,16 +177,26 @@
vdda33-supply = <&pm8998_l24>;
qcom,vdd-voltage-level = <0 880000 880000>;
qcom,qusb-phy-init-seq =
- /* <value reg_offset> */
- <0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */
- 0x7c 0x18c /* PLL_CLOCK_INVERTERS */
- 0x80 0x2c /* PLL_CMODE */
- 0x0a 0x184 /* PLL_LOCK_DELAY */
- 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */
- 0xa5 0x240 /* TUNE1 */
- 0x09 0x244 /* TUNE2 */
- 0x00 0x220 /* IMP_CTRL1 */
- 0x58 0x224>; /* IMP_CTRL2 */
+ /* <value reg_offset> */
+ <0x23 0x210 /* PWR_CTRL1 */
+ 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */
+ 0x7c 0x18c /* PLL_CLOCK_INVERTERS */
+ 0x80 0x2c /* PLL_CMODE */
+ 0x0a 0x184 /* PLL_LOCK_DELAY */
+ 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */
+ 0x40 0x194 /* PLL_BIAS_CONTROL_1 */
+ 0x20 0x198 /* PLL_BIAS_CONTROL_2 */
+ 0x21 0x214 /* PWR_CTRL2 */
+ 0x00 0x220 /* IMP_CTRL1 */
+ 0x58 0x224 /* IMP_CTRL2 */
+ 0x32 0x240 /* TUNE1 */
+ 0x29 0x244 /* TUNE2 */
+ 0xca 0x248 /* TUNE3 */
+ 0x04 0x24c /* TUNE4 */
+ 0x00 0x250 /* TUNE5 */
+ 0x00 0x23c /* CHG_CTRL2 */
+ 0x22 0x210>; /* PWR_CTRL1 */
+
phy_type= "utmi";
clocks = <&clock_rpmh RPMH_CXO_CLK>,
<&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>;
diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
index ed4956f..af88108 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi
@@ -96,13 +96,6 @@
virtual-addr-pool = <0x70800000 0x6f800000>;
};
- firmware_cb {
- compatible = "qcom,msm-vidc,context-bank";
- qcom,fw-context-bank;
- iommus =
- <&apps_smmu 0x10b2>;
- };
-
secure_bitstream_cb {
compatible = "qcom,msm-vidc,context-bank";
label = "venus_sec_bitstream";
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index 5c33436..2136c61 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -346,7 +346,7 @@
alloc-ranges = <0 0x00000000 0 0xffffffff>;
reusable;
alignment = <0 0x400000>;
- size = <0 0x800000>;
+ size = <0 0xc00000>;
};
qseecom_mem: qseecom_region {
@@ -388,6 +388,7 @@
#include "msm-gdsc-sdm845.dtsi"
#include "sdm845-sde.dtsi"
#include "sdm845-sde-display.dtsi"
+#include "sdm845-qupv3.dtsi"
&soc {
#address-cells = <1>;
@@ -552,8 +553,168 @@
< 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 >;
+ };
+
+ cpu_pmu: cpu-pmu {
+ compatible = "arm,armv8-pmuv3";
+ qcom,irq-is-percpu;
+ interrupts = <1 5 4>;
+ };
+
clock_gcc: qcom,gcc@100000 {
- compatible = "qcom,gcc-sdm845";
+ compatible = "qcom,gcc-sdm845", "syscon";
reg = <0x100000 0x1f0000>;
reg-names = "cc_base";
vdd_cx-supply = <&pm8998_s9_level>;
@@ -563,7 +724,7 @@
};
clock_videocc: qcom,videocc@ab00000 {
- compatible = "qcom,video_cc-sdm845";
+ compatible = "qcom,video_cc-sdm845", "syscon";
reg = <0xab00000 0x10000>;
reg-names = "cc_base";
vdd_cx-supply = <&pm8998_s9_level>;
@@ -572,7 +733,7 @@
};
clock_camcc: qcom,camcc@ad00000 {
- compatible = "qcom,cam_cc-sdm845";
+ compatible = "qcom,cam_cc-sdm845", "syscon";
reg = <0xad00000 0x10000>;
reg-names = "cc_base";
vdd_cx-supply = <&pm8998_s9_level>;
@@ -582,7 +743,7 @@
};
clock_dispcc: qcom,dispcc@af00000 {
- compatible = "qcom,dispcc-sdm845";
+ compatible = "qcom,dispcc-sdm845", "syscon";
reg = <0xaf00000 0x100000>;
reg-names = "cc_base";
vdd_cx-supply = <&pm8998_s9_level>;
@@ -590,16 +751,140 @@
#reset-cells = <1>;
};
- clock_gpucc: qcom,gpucc {
- compatible = "qcom,dummycc";
- clock-output-names = "gpucc_clocks";
+ clock_gpucc: qcom,gpucc@5090000 {
+ compatible = "qcom,gpucc-sdm845", "syscon";
+ reg = <0x5090000 0x9000>;
+ reg-names = "cc_base";
+ vdd_cx-supply = <&pm8998_s9_level>;
+ qcom,gpu_cc_gmu_clk_src-opp-handle = <&gmu>;
#clock-cells = <1>;
#reset-cells = <1>;
};
- clock_cpucc: qcom,cpucc {
- compatible = "qcom,dummycc";
- clock-output-names = "cpucc_clocks";
+ clock_gfx: qcom,gfxcc@5090000 {
+ compatible = "qcom,gfxcc-sdm845";
+ reg = <0x5090000 0x9000>;
+ reg-names = "cc_base";
+ vdd_gfx-supply = <&pm8005_s1_level>;
+ vdd_mx-supply = <&pm8998_s6_level>;
+ qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
+
+ clock_cpucc: qcom,cpucc@0x17d41000 {
+ compatible = "qcom,clk-cpu-osm";
+ reg = <0x17d41000 0x1400>,
+ <0x17d43000 0x1400>,
+ <0x17d45800 0x1400>,
+ <0x178d0000 0x1000>,
+ <0x178c0000 0x1000>,
+ <0x178b0000 0x1000>,
+ <0x17d42400 0x0c00>,
+ <0x17d44400 0x0c00>,
+ <0x17d46c00 0x0c00>,
+ <0x17810090 0x8>;
+ reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base",
+ "l3_pll", "pwrcl_pll", "perfcl_pll",
+ "l3_sequencer", "pwrcl_sequencer",
+ "perfcl_sequencer", "apps_itm_ctl";
+
+ vdd-l3-supply = <&apc0_l3_vreg>;
+ vdd-pwrcl-supply = <&apc0_pwrcl_vreg>;
+ vdd-perfcl-supply = <&apc1_perfcl_vreg>;
+
+ qcom,l3-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 422400000 0x50140116 0x00002020 0x1 2 >,
+ < 499200000 0x5014021a 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x501c0422 0x00002020 0x1 5 >,
+ < 729600000 0x501c0526 0x00002020 0x1 6 >,
+ < 806400000 0x501c062a 0x00002222 0x1 7 >;
+
+ qcom,pwrcl-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 422400000 0x50140116 0x00002020 0x1 2 >,
+ < 499200000 0x5014021a 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x501c0422 0x00002020 0x1 5 >,
+ < 748800000 0x501c0527 0x00002020 0x1 6 >,
+ < 825600000 0x401c062b 0x00002222 0x1 7 >,
+ < 902400000 0x4024072f 0x00002626 0x1 8 >,
+ < 979200000 0x40240833 0x00002929 0x1 9 >,
+ < 1056000000 0x402c0937 0x00002c2c 0x1 10 >,
+ < 1132800000 0x402c0a3b 0x00002f2f 0x1 11 >,
+ < 1209600000 0x402c0b3f 0x00003333 0x1 12 >;
+
+ qcom,perfcl-speedbin0-v0 =
+ < 300000000 0x000c000f 0x00002020 0x1 1 >,
+ < 422400000 0x50140116 0x00002020 0x1 2 >,
+ < 499200000 0x5014021a 0x00002020 0x1 3 >,
+ < 576000000 0x5014031e 0x00002020 0x1 4 >,
+ < 652800000 0x501c0422 0x00002020 0x1 5 >,
+ < 729600000 0x501c0526 0x00002020 0x1 6 >,
+ < 806400000 0x501c062a 0x00002222 0x1 7 >,
+ < 883200000 0x4024072b 0x00002525 0x1 8 >,
+ < 960000000 0x40240832 0x00002828 0x1 9 >,
+ < 1036800000 0x40240936 0x00002b2b 0x1 10 >,
+ < 1113600000 0x402c0a3a 0x00002e2e 0x1 11 >,
+ < 1190400000 0x402c0b3e 0x00003232 0x1 12 >;
+
+ qcom,l3-min-cpr-vc-bin0 = <7>;
+ qcom,pwrcl-min-cpr-vc-bin0 = <6>;
+ qcom,perfcl-min-cpr-vc-bin0 = <7>;
+
+ qcom,up-timer =
+ <1000 1000 1000>;
+ qcom,down-timer =
+ <100000 100000 100000>;
+ qcom,pc-override-index =
+ <0 0 0>;
+ qcom,set-ret-inactive;
+ qcom,enable-llm-freq-vote;
+ qcom,llm-freq-up-timer =
+ <1000 1000 1000>;
+ qcom,llm-freq-down-timer =
+ <327675 327675 327675>;
+ qcom,enable-llm-volt-vote;
+ qcom,llm-volt-up-timer =
+ <1000 1000 1000>;
+ qcom,llm-volt-down-timer =
+ <327675 327675 327675>;
+ qcom,cc-reads = <10>;
+ qcom,cc-delay = <5>;
+ qcom,cc-factor = <100>;
+ qcom,osm-clk-rate = <100000000>;
+ qcom,xo-clk-rate = <19200000>;
+
+ qcom,l-val-base =
+ <0x178d0004 0x178c0004 0x178b0004>;
+ qcom,apcs-pll-user-ctl =
+ <0x178d000c 0x178c000c 0x178b000c>;
+ qcom,apcs-pll-min-freq =
+ <0x17d41094 0x17d43094 0x17d45894>;
+ qcom,apm-mode-ctl =
+ <0x0 0x0 0x17d20010>;
+ qcom,apm-status-ctrl =
+ <0x0 0x0 0x17d20000>;
+ qcom,perfcl-isense-addr = <0x17871480>;
+ qcom,l3-mem-acc-addr = <0x17990170 0x17990170 0x17990170>;
+ qcom,pwrcl-mem-acc-addr = <0x17990160 0x17990164 0x17990164>;
+ qcom,perfcl-mem-acc-addr = <0x17990168 0x1799016c 0x1799016c>;
+ qcom,cfg-gfmux-addr =<0x178d0084 0x178c0084 0x178b0084>;
+ qcom,apcs-cbc-addr = <0x178d008c 0x178c008c 0x178b008c>;
+ qcom,apcs-ramp-ctl-addr = <0x17840904 0x17840904 0x17830904>;
+
+ qcom,perfcl-apcs-apm-threshold-voltage = <800000>;
+ qcom,perfcl-apcs-mem-acc-threshold-voltage = <852000>;
+ qcom,boost-fsm-en;
+ qcom,safe-fsm-en;
+ qcom,ps-fsm-en;
+ qcom,droop-fsm-en;
+ qcom,osm-pll-setup;
+
+ clock-names = "xo_ao";
+ clocks = <&clock_rpmh RPMH_CXO_CLK_A>;
#clock-cells = <1>;
#reset-cells = <1>;
};
@@ -611,15 +896,31 @@
mbox-names = "apps";
};
+ clock_debug: qcom,cc-debug@100000 {
+ compatible = "qcom,debugcc-sdm845";
+ qcom,cc-count = <5>;
+ qcom,gcc = <&clock_gcc>;
+ qcom,videocc = <&clock_videocc>;
+ qcom,camcc = <&clock_camcc>;
+ qcom,dispcc = <&clock_dispcc>;
+ qcom,gpucc = <&clock_gpucc>;
+ clock-names = "xo_clk_src";
+ clocks = <&clock_rpmh RPMH_CXO_CLK>;
+ #clock-cells = <1>;
+ };
+
ufsphy_mem: ufsphy_mem@1d87000 {
reg = <0x1d87000 0xda8>; /* PHY regs */
reg-names = "phy_mem";
#phy-cells = <0>;
- /* TODO: add "ref_clk_src" */
- clock-names = "ref_clk",
+ lanes-per-direction = <2>;
+
+ clock-names = "ref_clk_src",
+ "ref_clk",
"ref_aux_clk";
- clocks = <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>,
+ clocks = <&clock_rpmh RPMH_LN_BB_CLK1>,
+ <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>,
<&clock_gcc GCC_UFS_PHY_PHY_AUX_CLK>;
status = "disabled";
@@ -635,13 +936,13 @@
lanes-per-direction = <2>;
dev-ref-clk-freq = <0>; /* 19.2 MHz */
- /* TODO: add "ref_clk" */
clock-names =
"core_clk",
"bus_aggr_clk",
"iface_clk",
"core_clk_unipro",
"core_clk_ice",
+ "ref_clk",
"tx_lane0_sync_clk",
"rx_lane0_sync_clk",
"rx_lane1_sync_clk";
@@ -652,6 +953,7 @@
<&clock_gcc GCC_UFS_PHY_AHB_CLK>,
<&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>,
<&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>,
+ <&clock_rpmh RPMH_LN_BB_CLK1>,
<&clock_gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
<&clock_gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
<&clock_gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
@@ -663,34 +965,46 @@
<75000000 300000000>,
<0 0>,
<0 0>,
+ <0 0>,
<0 0>;
qcom,msm-bus,name = "ufshc_mem";
qcom,msm-bus,num-cases = <22>;
qcom,msm-bus,num-paths = <2>;
qcom,msm-bus,vectors-KBps =
- <95 512 0 0>, <1 650 0 0>, /* No vote */
- <95 512 922 0>, <1 650 1000 0>, /* PWM G1 */
- <95 512 1844 0>, <1 650 1000 0>, /* PWM G2 */
- <95 512 3688 0>, <1 650 1000 0>, /* PWM G3 */
- <95 512 7376 0>, <1 650 1000 0>, /* PWM G4 */
- <95 512 1844 0>, <1 650 1000 0>, /* PWM G1 L2 */
- <95 512 3688 0>, <1 650 1000 0>, /* PWM G2 L2 */
- <95 512 7376 0>, <1 650 1000 0>, /* PWM G3 L2 */
- <95 512 14752 0>, <1 650 1000 0>, /* PWM G4 L2 */
- <95 512 127796 0>, <1 650 1000 0>, /* HS G1 RA */
- <95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */
- <95 512 511181 0>, <1 650 1000 0>, /* HS G3 RA */
- <95 512 255591 0>, <1 650 1000 0>, /* HS G1 RA L2 */
- <95 512 511181 0>, <1 650 1000 0>, /* HS G2 RA L2 */
- <95 512 1022362 0>, <1 650 1000 0>, /* HS G3 RA L2 */
- <95 512 149422 0>, <1 650 1000 0>, /* HS G1 RB */
- <95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */
- <95 512 596378 0>, <1 650 1000 0>, /* HS G3 RB */
- <95 512 298189 0>, <1 650 1000 0>, /* HS G1 RB L2 */
- <95 512 596378 0>, <1 650 1000 0>, /* HS G2 RB L2 */
- <95 512 1192756 0>, <1 650 1000 0>, /* HS G3 RB L2 */
- <95 512 4096000 0>, <1 650 1000 0>; /* Max. bandwidth */
+ /*
+ * During HS G3 UFS runs at nominal voltage corner, vote
+ * higher bandwidth to push other buses in the data path
+ * to run at nominal to achieve max throughput.
+ * 4GBps pushes BIMC to run at nominal.
+ * 200MBps pushes CNOC to run at nominal.
+ * Vote for half of this bandwidth for HS G3 1-lane.
+ * For max bandwidth, vote high enough to push the buses
+ * to run in turbo voltage corner.
+ */
+ <123 512 0 0>, <1 757 0 0>, /* No vote */
+ <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */
+ <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */
+ <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */
+ <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */
+ <123 512 1844 0>, <1 757 1000 0>, /* PWM G1 L2 */
+ <123 512 3688 0>, <1 757 1000 0>, /* PWM G2 L2 */
+ <123 512 7376 0>, <1 757 1000 0>, /* PWM G3 L2 */
+ <123 512 14752 0>, <1 757 1000 0>, /* PWM G4 L2 */
+ <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */
+ <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */
+ <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */
+ <123 512 255591 0>, <1 757 1000 0>, /* HS G1 RA L2 */
+ <123 512 511181 0>, <1 757 1000 0>, /* HS G2 RA L2 */
+ <123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RA L2 */
+ <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */
+ <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */
+ <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */
+ <123 512 298189 0>, <1 757 1000 0>, /* HS G1 RB L2 */
+ <123 512 596378 0>, <1 757 1000 0>, /* HS G2 RB L2 */
+ <123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RB L2 */
+ <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */
+
qcom,bus-vector-names = "MIN",
"PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1",
"PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2",
@@ -700,6 +1014,18 @@
"HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2",
"MAX";
+ /* PM QoS */
+ qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
+ qcom,pm-qos-cpu-group-latency-us = <70 70>;
+ qcom,pm-qos-default-cpu = <0>;
+
+ pinctrl-names = "dev-reset-assert", "dev-reset-deassert";
+ pinctrl-0 = <&ufs_dev_reset_assert>;
+ pinctrl-1 = <&ufs_dev_reset_deassert>;
+
+ resets = <&clock_gcc GCC_UFS_PHY_BCR>;
+ reset-names = "core_reset";
+
status = "disabled";
};
@@ -708,10 +1034,13 @@
reg-names = "phy_mem";
#phy-cells = <0>;
- /* TODO: add "ref_clk_src" */
- clock-names = "ref_clk",
+ lanes-per-direction = <1>;
+
+ clock-names = "ref_clk_src",
+ "ref_clk",
"ref_aux_clk";
- clocks = <&clock_gcc GCC_UFS_CARD_CLKREF_CLK>,
+ clocks = <&clock_rpmh RPMH_LN_BB_CLK1>,
+ <&clock_gcc GCC_UFS_CARD_CLKREF_CLK>,
<&clock_gcc GCC_UFS_CARD_PHY_AUX_CLK>;
status = "disabled";
@@ -727,13 +1056,13 @@
lanes-per-direction = <1>;
dev-ref-clk-freq = <0>; /* 19.2 MHz */
- /* TODO: add "ref_clk" */
clock-names =
"core_clk",
"bus_aggr_clk",
"iface_clk",
"core_clk_unipro",
"core_clk_ice",
+ "ref_clk",
"tx_lane0_sync_clk",
"rx_lane0_sync_clk";
/* TODO: add HW CTL clocks when available */
@@ -743,6 +1072,7 @@
<&clock_gcc GCC_UFS_CARD_AHB_CLK>,
<&clock_gcc GCC_UFS_CARD_UNIPRO_CORE_CLK>,
<&clock_gcc GCC_UFS_CARD_ICE_CORE_CLK>,
+ <&clock_rpmh RPMH_LN_BB_CLK1>,
<&clock_gcc GCC_UFS_CARD_TX_SYMBOL_0_CLK>,
<&clock_gcc GCC_UFS_CARD_RX_SYMBOL_0_CLK>;
freq-table-hz =
@@ -752,27 +1082,41 @@
<37500000 150000000>,
<75000000 300000000>,
<0 0>,
+ <0 0>,
<0 0>;
qcom,msm-bus,name = "ufshc_card";
qcom,msm-bus,num-cases = <9>;
qcom,msm-bus,num-paths = <2>;
qcom,msm-bus,vectors-KBps =
- <95 512 0 0>, <1 650 0 0>, /* No vote */
- <95 512 922 0>, <1 650 1000 0>, /* PWM G1 */
- <95 512 127796 0>, <1 650 1000 0>, /* HS G1 RA */
- <95 512 255591 0>, <1 650 1000 0>, /* HS G2 RA */
- <95 512 511181 0>, <1 650 1000 0>, /* HS G3 RA */
- <95 512 149422 0>, <1 650 1000 0>, /* HS G1 RB */
- <95 512 298189 0>, <1 650 1000 0>, /* HS G2 RB */
- <95 512 596378 0>, <1 650 1000 0>, /* HS G3 RB */
- <95 512 4096000 0>, <1 650 1000 0>; /* Max. bandwidth */
+ <122 512 0 0>, <1 756 0 0>, /* No vote */
+ <122 512 922 0>, <1 756 1000 0>, /* PWM G1 */
+ <122 512 127796 0>, <1 756 1000 0>, /* HS G1 RA */
+ <122 512 255591 0>, <1 756 1000 0>, /* HS G2 RA */
+ <122 512 2097152 0>, <1 756 102400 0>, /* HS G3 RA */
+ <122 512 149422 0>, <1 756 1000 0>, /* HS G1 RB */
+ <122 512 298189 0>, <1 756 1000 0>, /* HS G2 RB */
+ <122 512 2097152 0>, <1 756 102400 0>, /* HS G3 RB */
+ <122 512 7643136 0>, <1 756 307200 0>; /* Max. bandwidth */
qcom,bus-vector-names = "MIN",
"PWM_G1_L1",
"HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1",
"HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1",
"MAX";
+ /* PM QoS */
+ qcom,pm-qos-cpu-groups = <0x0f 0xf0>;
+ qcom,pm-qos-cpu-group-latency-us = <70 70>;
+ qcom,pm-qos-default-cpu = <0>;
+
+ /*
+ * Note: this instance doesn't have control over UFS device
+ * reset
+ */
+
+ resets = <&clock_gcc GCC_UFS_CARD_BCR>;
+ reset-names = "core_reset";
+
status = "disabled";
};
@@ -993,6 +1337,11 @@
qcom,rtb-size = <0x100000>;
};
+ qcom,msm-cdsp-loader {
+ compatible = "qcom,cdsp-loader";
+ qcom,proc-img-to-load = "cdsp";
+ };
+
qcom,msm_fastrpc {
compatible = "qcom,msm-fastrpc-compute";
@@ -1192,10 +1541,12 @@
"l3-scu-faultirq";
};
- qcom,llcc@1300000 {
+ qcom,llcc@1100000 {
compatible = "qcom,llcc-core", "syscon", "simple-mfd";
- reg = <0x1300000 0x50000>;
+ reg = <0x1100000 0x250000>;
reg-names = "llcc_base";
+ qcom,llcc-banks-off = <0x0 0x80000 0x100000 0x180000>;
+ qcom,llcc-broadcast-off = <0x200000>;
llcc: qcom,sdm845-llcc {
compatible = "qcom,sdm845-llcc";
@@ -1263,8 +1614,21 @@
qcom,rx-ring-size = <0x400>;
};
+ qmp_aop: mailbox@1799000c {
+ compatible = "qcom,qmp-mbox";
+ label = "aop";
+ reg = <0xc300000 0x100000>,
+ <0x1799000c 0x4>;
+ reg-names = "msgram", "irq-reg-base";
+ qcom,irq-mask = <0x1>;
+ interrupts = <0 389 1>;
+ mbox_desc_offset = <0x0>;
+ #mbox-cells = <1>;
+ };
+
apps_rsc: mailbox@179e0000 {
compatible = "qcom,tcs-drv";
+ label = "apps_rsc";
reg = <0x179e0000 0x100>, <0x179e0d00 0x3000>;
interrupts = <0 5 0>;
#mbox-cells = <1>;
@@ -1277,6 +1641,7 @@
disp_rsc: mailbox@af20000 {
compatible = "qcom,tcs-drv";
+ label = "display_rsc";
reg = <0xaf20000 0x100>, <0xaf21c00 0x3000>;
interrupts = <0 129 0>;
#mbox-cells = <1>;
@@ -1516,7 +1881,6 @@
qcom,ipa-hw-ver = <13>; /* IPA core version = IPAv3.5.1 */
qcom,ipa-hw-mode = <1>;
qcom,ee = <0>;
- qcom,use-gsi;
qcom,use-ipa-tethering-bridge;
qcom,modem-cfg-emb-pipe-flt;
qcom,ipa-wdi2;
@@ -1671,6 +2035,11 @@
<0x10ae000 0x2000>;
reg-names = "dcc-base", "dcc-ram-base";
};
+
+ qcom,msm-core@780000 {
+ compatible = "qcom,apss-core-ea";
+ reg = <0x780000 0x1000>;
+ };
};
&pcie_0_gdsc {
@@ -1788,3 +2157,4 @@
#include "sdm845-pm.dtsi"
#include "sdm845-pinctrl.dtsi"
#include "sdm845-audio.dtsi"
+#include "sdm845-gpu.dtsi"
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index 2e72456..4a13b7a 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -272,18 +272,21 @@
CONFIG_HW_RANDOM=y
CONFIG_MSM_ADSPRPC=y
CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QCOM_GENI=y
CONFIG_SOUNDWIRE=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
+CONFIG_SPI_QCOM_GENI=y
CONFIG_SPI_SPIDEV=y
CONFIG_SLIMBUS_MSM_NGD=y
CONFIG_SPMI=y
CONFIG_PINCTRL_SDM845=y
CONFIG_PINCTRL_SDM830=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_QPNP_PIN=y
CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_QPNP_FG_GEN3=y
@@ -318,6 +321,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
@@ -402,7 +406,10 @@
CONFIG_MSM_DISPCC_SDM845=y
CONFIG_CLOCK_QPNP_DIV=y
CONFIG_MSM_CLK_RPMH=y
+CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_QMP=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_ARM_SMMU=y
CONFIG_QCOM_LAZY_MAPPING=y
@@ -413,6 +420,8 @@
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
CONFIG_QCOM_SECURE_BUFFER=y
CONFIG_QCOM_EARLY_RANDOM=y
CONFIG_MSM_SMEM=y
@@ -434,8 +443,10 @@
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_ICNSS=y
CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_AVTIMER=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
+CONFIG_APSS_CORE_EA=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
CONFIG_QCOMCCI_HWMON=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 688e130..7333731 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -13,13 +13,11 @@
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
-CONFIG_CGROUPS=y
CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_SCHEDTUNE=y
-CONFIG_CGROUP_SCHED=y
CONFIG_RT_GROUP_SCHED=y
CONFIG_SCHED_HMP=y
CONFIG_SCHED_HMP_CSTATE_AWARE=y
@@ -27,6 +25,7 @@
CONFIG_NAMESPACES=y
# CONFIG_UTS_NS is not set
# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
CONFIG_SCHED_TUNE=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_RD_XZ is not set
@@ -276,26 +275,27 @@
# CONFIG_SERIO_SERPORT is not set
# CONFIG_VT is not set
# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_MSM=y
-CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_DIAG_CHAR=y
CONFIG_HVC_DCC=y
CONFIG_HVC_DCC_SERIALIZE_SMP=y
CONFIG_HW_RANDOM=y
CONFIG_MSM_ADSPRPC=y
CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QCOM_GENI=y
CONFIG_SOUNDWIRE=y
CONFIG_SPI=y
CONFIG_SPI_QUP=y
+CONFIG_SPI_QCOM_GENI=y
CONFIG_SPI_SPIDEV=y
CONFIG_SLIMBUS_MSM_NGD=y
CONFIG_SPMI=y
CONFIG_PINCTRL_SDM845=y
CONFIG_PINCTRL_SDM830=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_QPNP_PIN=y
CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_QPNP_FG_GEN3=y
@@ -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
@@ -422,7 +423,10 @@
CONFIG_MSM_DISPCC_SDM845=y
CONFIG_CLOCK_QPNP_DIV=y
CONFIG_MSM_CLK_RPMH=y
+CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_QMP=y
CONFIG_IOMMU_IO_PGTABLE_FAST=y
CONFIG_ARM_SMMU=y
CONFIG_QCOM_LAZY_MAPPING=y
@@ -436,6 +440,8 @@
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
CONFIG_QCOM_SECURE_BUFFER=y
CONFIG_QCOM_EARLY_RANDOM=y
CONFIG_MSM_SMEM=y
@@ -458,8 +464,10 @@
CONFIG_ICNSS=y
CONFIG_ICNSS_DEBUG=y
CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_AVTIMER=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_PM=y
+CONFIG_APSS_CORE_EA=y
CONFIG_QCOM_DCC_V2=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_ARM_MEMLAT_MON=y
@@ -521,6 +529,8 @@
CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y
CONFIG_WQ_WATCHDOG=y
CONFIG_PANIC_TIMEOUT=5
+CONFIG_PANIC_ON_SCHED_BUG=y
+CONFIG_PANIC_ON_RT_THROTTLING=y
CONFIG_SCHEDSTATS=y
CONFIG_SCHED_STACK_END_CHECK=y
CONFIG_TIMER_STATS=y
@@ -538,7 +548,8 @@
CONFIG_QCOM_RTB=y
CONFIG_QCOM_RTB_SEPARATE_CPUS=y
CONFIG_FUNCTION_TRACER=y
-CONFIG_TRACER_SNAPSHOT=y
+CONFIG_IRQSOFF_TRACER=y
+CONFIG_PREEMPT_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_CPU_FREQ_SWITCH_PROFILER=y
CONFIG_LKDTM=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..852548c 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;
}
/*
@@ -869,8 +867,6 @@
{
unsigned long config_base = 0;
- if (attr->exclude_idle)
- return -EPERM;
if (is_kernel_in_hyp_mode() &&
attr->exclude_kernel != attr->exclude_hv)
return -EINVAL;
@@ -977,11 +973,74 @@
ARRAY_SIZE(pmceid));
}
+static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu)
+{
+ struct pmu_hw_events *hw_events;
+ struct perf_event *event;
+ int idx;
+
+ if (!cpu_pmu)
+ return;
+
+ hw_events = this_cpu_ptr(cpu_pmu->hw_events);
+
+ if (!hw_events)
+ return;
+
+ for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
+
+ if (!test_bit(idx, hw_events->used_mask))
+ continue;
+
+ event = hw_events->events[idx];
+
+ if (!event || !event->attr.exclude_idle ||
+ event->state != PERF_EVENT_STATE_ACTIVE)
+ continue;
+
+ cpu_pmu->pmu.read(event);
+ }
+}
+
+struct arm_pmu_and_idle_nb {
+ struct arm_pmu *cpu_pmu;
+ struct notifier_block perf_cpu_idle_nb;
+};
+
+static int perf_cpu_idle_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct arm_pmu_and_idle_nb *pmu_nb = container_of(nb,
+ struct arm_pmu_and_idle_nb, perf_cpu_idle_nb);
+
+ if (action == IDLE_START)
+ armv8pmu_idle_update(pmu_nb->cpu_pmu);
+
+ return NOTIFY_OK;
+}
+
static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu)
{
- return smp_call_function_any(&cpu_pmu->supported_cpus,
+ int ret;
+ struct arm_pmu_and_idle_nb *pmu_idle_nb;
+
+ pmu_idle_nb = devm_kzalloc(&cpu_pmu->plat_device->dev,
+ sizeof(*pmu_idle_nb), GFP_KERNEL);
+ if (!pmu_idle_nb)
+ return -ENOMEM;
+
+ pmu_idle_nb->cpu_pmu = cpu_pmu;
+ pmu_idle_nb->perf_cpu_idle_nb.notifier_call = perf_cpu_idle_notifier;
+ idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb);
+
+ ret = smp_call_function_any(&cpu_pmu->supported_cpus,
__armv8pmu_probe_pmu,
cpu_pmu, 1);
+
+ if (ret)
+ idle_notifier_unregister(&pmu_idle_nb->perf_cpu_idle_nb);
+
+ return ret;
}
static void armv8_pmu_init(struct arm_pmu *cpu_pmu)
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/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index d8e6635..860c3b6 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -976,7 +976,7 @@
* device, and allocated the default domain for that group.
*/
if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) {
- pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
+ pr_debug("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
dev_name(dev));
return false;
}
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/android/binder.c b/drivers/android/binder.c
index 79902e7..d7eb419 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2830,7 +2830,7 @@
} break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
cmd = BR_TRANSACTION_COMPLETE;
- if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
+ if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
@@ -2872,14 +2872,14 @@
node->has_weak_ref = 0;
}
if (cmd != BR_NOOP) {
- if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
+ if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
- if (put_user_preempt_disabled(node->ptr, (binder_uintptr_t __user *)
+ if (put_user_preempt_disabled(node->ptr, (binder_uintptr_t __user *)
(binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
- if (put_user_preempt_disabled(node->cookie, (binder_uintptr_t __user *)
+ if (put_user_preempt_disabled(node->cookie, (binder_uintptr_t __user *)
(binder_uintptr_t __user *)ptr))
return -EFAULT;
ptr += sizeof(binder_uintptr_t);
@@ -2923,7 +2923,7 @@
cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
else
cmd = BR_DEAD_BINDER;
- if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
+ if (put_user_preempt_disabled(cmd, (uint32_t __user *) ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (put_user_preempt_disabled(death->cookie, (binder_uintptr_t __user *) ptr))
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/base/cpu.c b/drivers/base/cpu.c
index d82ce17..4609244 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -416,6 +416,7 @@
_CPU_ATTR(online, &__cpu_online_mask),
_CPU_ATTR(possible, &__cpu_possible_mask),
_CPU_ATTR(present, &__cpu_present_mask),
+ _CPU_ATTR(core_ctl_isolated, &__cpu_isolated_mask),
};
/*
@@ -651,6 +652,7 @@
&cpu_attrs[0].attr.attr,
&cpu_attrs[1].attr.attr,
&cpu_attrs[2].attr.attr,
+ &cpu_attrs[3].attr.attr,
&dev_attr_kernel_max.attr,
&dev_attr_offline.attr,
&dev_attr_isolated.attr,
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/clk.c b/drivers/clk/clk.c
index 83db1416..ece2f00 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com>
* Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
- * 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 as
@@ -2101,7 +2101,7 @@
/* prevent racing with updates to the clock topology */
clk_prepare_lock();
- if (core->parent == parent)
+ if (core->parent == parent && !(core->flags & CLK_IS_MEASURE))
goto out;
/* verify ops for for multi-parent clks */
@@ -2599,7 +2599,7 @@
.release = seq_release,
};
-static void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
+void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f)
{
if (IS_ERR_OR_NULL(clk))
return;
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index 331e086..f0db049 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -23,6 +23,7 @@
/* Debugfs API to print the enabled clocks */
void clock_debug_print_enabled(void);
+void clk_debug_print_hw(struct clk_core *clk, struct seq_file *f);
#else
/* All these casts to avoid ifdefs in clkdev... */
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..6e13562 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -10,7 +10,7 @@
clk-qcom-y += clk-regmap-divider.o
clk-qcom-y += clk-regmap-mux.o
clk-qcom-y += reset.o clk-voter.o
-clk-qcom-y += clk-dummy.o
+clk-qcom-y += clk-dummy.o clk-debug.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o gdsc-regulator.o
# Keep alphabetically sorted by config
@@ -31,7 +31,8 @@
obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
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_GCC_SDM845) += gcc-sdm845.o debugcc-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
diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c
index c49eddf..a274975 100644
--- a/drivers/clk/qcom/camcc-sdm845.c
+++ b/drivers/clk/qcom/camcc-sdm845.c
@@ -107,9 +107,11 @@
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_fabia_pll_ops,
- VDD_CX_FMAX_MAP2(
- MIN, 19200000,
- LOWER, 600000000),
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
},
},
};
@@ -152,9 +154,11 @@
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_fabia_pll_ops,
- VDD_CX_FMAX_MAP2(
- MIN, 19200000,
- LOW, 808000000),
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
},
},
};
@@ -189,9 +193,11 @@
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_fabia_pll_ops,
- VDD_MX_FMAX_MAP2(
- MIN, 19200000,
- LOWER, 960000000),
+ VDD_MX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
},
},
};
@@ -248,9 +254,11 @@
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_fabia_pll_ops,
- VDD_CX_FMAX_MAP2(
- MIN, 19200000,
- LOWER, 384000000),
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
},
},
};
diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c
index 53f736c..51a5e0b 100644
--- a/drivers/clk/qcom/clk-branch.c
+++ b/drivers/clk/qcom/clk-branch.c
@@ -23,6 +23,7 @@
#include "clk-branch.h"
#include "clk-regmap.h"
+#include "clk-debug.h"
static bool clk_branch_in_hwcg_mode(const struct clk_branch *br)
{
@@ -338,6 +339,7 @@
.recalc_rate = clk_branch2_recalc_rate,
.set_flags = clk_branch_set_flags,
.list_registers = clk_branch2_list_registers,
+ .debug_init = clk_debug_measure_add,
};
EXPORT_SYMBOL_GPL(clk_branch2_ops);
@@ -393,6 +395,7 @@
.disable = clk_gate2_disable,
.is_enabled = clk_is_enabled_regmap,
.list_registers = clk_gate2_list_registers,
+ .debug_init = clk_debug_measure_add,
};
EXPORT_SYMBOL_GPL(clk_gate2_ops);
diff --git a/drivers/clk/qcom/clk-debug.c b/drivers/clk/qcom/clk-debug.c
new file mode 100644
index 0000000..53288f7
--- /dev/null
+++ b/drivers/clk/qcom/clk-debug.c
@@ -0,0 +1,285 @@
+/*
+ * 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/clk.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+
+#include "clk-regmap.h"
+#include "clk-debug.h"
+#include "common.h"
+
+static struct clk_hw *measure;
+
+static DEFINE_SPINLOCK(clk_reg_lock);
+static DEFINE_MUTEX(clk_debug_lock);
+
+#define TCXO_DIV_4_HZ 4800000
+#define SAMPLE_TICKS_1_MS 0x1000
+#define SAMPLE_TICKS_14_MS 0x10000
+
+#define XO_DIV4_CNT_DONE BIT(25)
+#define CNT_EN BIT(20)
+#define MEASURE_CNT BM(24, 0)
+
+/* Sample clock for 'ticks' reference clock ticks. */
+static u32 run_measurement(unsigned int ticks, struct regmap *regmap,
+ u32 ctl_reg, u32 status_reg)
+{
+ u32 regval;
+
+ /* Stop counters and set the XO4 counter start value. */
+ regmap_write(regmap, ctl_reg, ticks);
+
+ regmap_read(regmap, status_reg, ®val);
+
+ /* Wait for timer to become ready. */
+ while ((regval & XO_DIV4_CNT_DONE) != 0) {
+ cpu_relax();
+ regmap_read(regmap, status_reg, ®val);
+ }
+
+ /* Run measurement and wait for completion. */
+ regmap_write(regmap, ctl_reg, (CNT_EN|ticks));
+
+ regmap_read(regmap, status_reg, ®val);
+
+ while ((regval & XO_DIV4_CNT_DONE) == 0) {
+ cpu_relax();
+ regmap_read(regmap, status_reg, ®val);
+ }
+
+ /* Return measured ticks. */
+ regmap_read(regmap, status_reg, ®val);
+ regval &= MEASURE_CNT;
+
+ /* Stop the counters */
+ regmap_write(regmap, ctl_reg, ticks);
+
+ return regval;
+}
+
+/*
+ * Perform a hardware rate measurement for a given clock.
+ * FOR DEBUG USE ONLY: Measurements take ~15 ms!
+ */
+static unsigned long clk_debug_mux_measure_rate(struct clk_hw *hw)
+{
+ unsigned long flags, ret = 0;
+ u32 gcc_xo4_reg, multiplier = 1;
+ u64 raw_count_short, raw_count_full;
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ struct measure_clk_data *data = meas->priv;
+
+ clk_prepare_enable(data->cxo);
+
+ spin_lock_irqsave(&clk_reg_lock, flags);
+
+ /* Enable CXO/4 and RINGOSC branch. */
+ regmap_read(meas->regmap[GCC], data->xo_div4_cbcr, &gcc_xo4_reg);
+ gcc_xo4_reg |= BIT(0);
+ regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
+
+ /*
+ * The ring oscillator counter will not reset if the measured clock
+ * is not running. To detect this, run a short measurement before
+ * the full measurement. If the raw results of the two are the same
+ * then the clock must be off.
+ */
+
+ /* Run a short measurement. (~1 ms) */
+ raw_count_short = run_measurement(SAMPLE_TICKS_1_MS, meas->regmap[GCC],
+ data->ctl_reg, data->status_reg);
+
+ /* Run a full measurement. (~14 ms) */
+ raw_count_full = run_measurement(SAMPLE_TICKS_14_MS, meas->regmap[GCC],
+ data->ctl_reg, data->status_reg);
+
+ gcc_xo4_reg &= ~BIT(0);
+ regmap_write(meas->regmap[GCC], data->xo_div4_cbcr, gcc_xo4_reg);
+
+ /* Return 0 if the clock is off. */
+ if (raw_count_full == raw_count_short)
+ ret = 0;
+ else {
+ /* Compute rate in Hz. */
+ raw_count_full = ((raw_count_full * 10) + 15) * TCXO_DIV_4_HZ;
+ do_div(raw_count_full, ((SAMPLE_TICKS_14_MS * 10) + 35));
+ ret = (raw_count_full * multiplier);
+ }
+
+ spin_unlock_irqrestore(&clk_reg_lock, flags);
+
+ clk_disable_unprepare(data->cxo);
+
+ return ret;
+}
+
+static u8 clk_debug_mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ int i, num_parents = clk_hw_get_num_parents(hw);
+
+ for (i = 0; i < num_parents; i++) {
+ if (!strcmp(meas->parent[i].parents,
+ hw->init->parent_names[i])) {
+ pr_debug("%s: Clock name %s index %d\n", __func__,
+ hw->init->name, i);
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+static int clk_debug_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_debug_mux *meas = to_clk_measure(hw);
+ u32 regval = 0;
+ int dbg_cc = 0;
+
+ dbg_cc = meas->parent[index].dbg_cc;
+
+ if (dbg_cc != GCC) {
+ /* Update the recursive debug mux */
+ regmap_read(meas->regmap[dbg_cc],
+ meas->parent[index].mux_offset, ®val);
+ regval &= ~meas->parent[index].mux_sel_mask <<
+ meas->parent[index].mux_sel_shift;
+ regval |= (meas->parent[index].dbg_cc_mux_sel &
+ meas->parent[index].mux_sel_mask) <<
+ meas->parent[index].mux_sel_shift;
+ regmap_write(meas->regmap[dbg_cc],
+ meas->parent[index].mux_offset, regval);
+
+ regmap_read(meas->regmap[dbg_cc],
+ meas->parent[index].post_div_offset, ®val);
+ regval &= ~meas->parent[index].post_div_mask <<
+ meas->parent[index].post_div_shift;
+ regval |= ((meas->parent[index].post_div_val - 1) &
+ meas->parent[index].post_div_mask) <<
+ meas->parent[index].post_div_shift;
+ regmap_write(meas->regmap[dbg_cc],
+ meas->parent[index].post_div_offset, regval);
+
+ regmap_read(meas->regmap[dbg_cc],
+ meas->parent[index].cbcr_offset, ®val);
+ regval |= BIT(0);
+ regmap_write(meas->regmap[dbg_cc],
+ meas->parent[index].cbcr_offset, regval);
+ }
+
+ /* Update the debug sel for GCC */
+ regmap_read(meas->regmap[GCC], meas->debug_offset, ®val);
+ regval &= ~meas->src_sel_mask << meas->src_sel_shift;
+ regval |= (meas->parent[index].prim_mux_sel & meas->src_sel_mask) <<
+ meas->src_sel_shift;
+ regmap_write(meas->regmap[GCC], meas->debug_offset, regval);
+
+ /* Set the GCC mux's post divider bits */
+ regmap_read(meas->regmap[GCC], meas->post_div_offset, ®val);
+ regval &= ~meas->post_div_mask << meas->post_div_shift;
+ regval |= ((meas->parent[index].prim_mux_div_val - 1) &
+ meas->post_div_mask) << meas->post_div_shift;
+ regmap_write(meas->regmap[GCC], meas->post_div_offset, regval);
+
+ /* Turn on the GCC_DEBUG_CBCR */
+ regmap_read(meas->regmap[GCC], meas->cbcr_offset, ®val);
+ regval |= BIT(0);
+ regmap_write(meas->regmap[GCC], meas->cbcr_offset, regval);
+
+ return 0;
+}
+
+const struct clk_ops clk_debug_mux_ops = {
+ .get_parent = clk_debug_mux_get_parent,
+ .set_parent = clk_debug_mux_set_parent,
+};
+EXPORT_SYMBOL(clk_debug_mux_ops);
+
+static int clk_debug_measure_get(void *data, u64 *val)
+{
+ struct clk_hw *hw = data, *par;
+ struct clk_debug_mux *meas = to_clk_measure(measure);
+ int index;
+ int ret = 0;
+ unsigned long meas_rate, sw_rate;
+
+ mutex_lock(&clk_debug_lock);
+
+ ret = clk_set_parent(measure->clk, hw->clk);
+ if (!ret) {
+ par = measure;
+ index = clk_debug_mux_get_parent(measure);
+ while (par && par != hw) {
+ if (par->init->ops->enable)
+ par->init->ops->enable(par);
+ par = clk_hw_get_parent(par);
+ }
+ *val = clk_debug_mux_measure_rate(measure);
+ if (meas->parent[index].dbg_cc != GCC)
+ *val *= meas->parent[index].post_div_val;
+ *val *= meas->parent[index].prim_mux_div_val;
+ }
+
+ meas_rate = clk_get_rate(hw->clk);
+ par = clk_hw_get_parent(measure);
+ if (!par)
+ return -EINVAL;
+
+ sw_rate = clk_get_rate(par->clk);
+ if (sw_rate && meas_rate >= (sw_rate * 2))
+ *val *= DIV_ROUND_CLOSEST(meas_rate, sw_rate);
+
+ mutex_unlock(&clk_debug_lock);
+
+ return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clk_measure_fops, clk_debug_measure_get,
+ NULL, "%lld\n");
+
+int clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry)
+{
+ if (IS_ERR_OR_NULL(measure)) {
+ pr_err_once("Please check if `measure` clk is registered.\n");
+ return 0;
+ }
+
+ if (clk_set_parent(measure->clk, hw->clk))
+ return 0;
+
+ debugfs_create_file("clk_measure", 0x444, dentry, hw,
+ &clk_measure_fops);
+ return 0;
+}
+EXPORT_SYMBOL(clk_debug_measure_add);
+
+int clk_debug_measure_register(struct clk_hw *hw)
+{
+ if (IS_ERR_OR_NULL(measure)) {
+ if (hw->init->flags & CLK_IS_MEASURE) {
+ measure = hw;
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_debug_measure_register);
+
diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h
new file mode 100644
index 0000000..280704e
--- /dev/null
+++ b/drivers/clk/qcom/clk-debug.h
@@ -0,0 +1,132 @@
+/*
+ * 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 __QCOM_CLK_DEBUG_H__
+#define __QCOM_CLK_DEBUG_H__
+
+#include "../clk.h"
+
+/* Debugfs Measure Clocks */
+
+/**
+ * struct measure_clk_data - Structure of clk measure
+ *
+ * @cxo: XO clock.
+ * @xo_div4_cbcr: offset of debug XO/4 div register.
+ * @ctl_reg: offset of debug control register.
+ * @status_reg: offset of debug status register.
+ * @cbcr_offset: branch register to turn on debug mux.
+ */
+struct measure_clk_data {
+ struct clk *cxo;
+ u32 ctl_reg;
+ u32 status_reg;
+ u32 xo_div4_cbcr;
+};
+
+/**
+ * List of Debug clock controllers.
+ */
+enum debug_cc {
+ GCC,
+ CAM_CC,
+ DISP_CC,
+ GPU_CC,
+ VIDEO_CC,
+ CPU,
+};
+
+/**
+ * struct clk_src - Structure of clock source for debug mux
+ *
+ * @parents: clock name to be used as parent for debug mux.
+ * @prim_mux_sel: debug mux index at global clock controller.
+ * @prim_mux_div_val: PLL post-divider setting for the primary mux.
+ * @dbg_cc: indicates the clock controller for recursive debug
+ * clock controllers.
+ * @dbg_cc_mux_sel: indicates the debug mux index at recursive debug mux.
+ * @mux_sel_mask: indicates the mask for the mux selection.
+ * @mux_sel_shift: indicates the shift required for mux selection.
+ * @post_div_mask: indicates the post div mask to be used at recursive
+ * debug mux.
+ * @post_div_shift: indicates the shift required for post divider
+ * configuration.
+ * @post_div_val: indicates the post div value to be used at recursive
+ * debug mux.
+ * @mux_offset: the debug mux offset.
+ * @post_div_offset: register with post-divider settings for the debug mux.
+ * @cbcr_offset: branch register to turn on debug mux.
+ */
+struct clk_src {
+ const char *parents;
+ int prim_mux_sel;
+ u32 prim_mux_div_val;
+ enum debug_cc dbg_cc;
+ int dbg_cc_mux_sel;
+ u32 mux_sel_mask;
+ u32 mux_sel_shift;
+ u32 post_div_mask;
+ u32 post_div_shift;
+ u32 post_div_val;
+ u32 mux_offset;
+ u32 post_div_offset;
+ u32 cbcr_offset;
+};
+
+#define MUX_SRC_LIST(...) \
+ .parent = (struct clk_src[]){__VA_ARGS__}, \
+ .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__}))
+
+/**
+ * struct clk_debug_mux - Structure of clock debug mux
+ *
+ * @parent: structure of clk_src
+ * @num_parents: number of parents
+ * @regmap: regmaps of debug mux
+ * @priv: private measure_clk_data to be used by debug mux
+ * @debug_offset: debug mux offset.
+ * @post_div_offset: register with post-divider settings for the debug mux.
+ * @cbcr_offset: branch register to turn on debug mux.
+ * @src_sel_mask: indicates the mask to be used for src selection in
+ primary mux.
+ * @src_sel_shift: indicates the shift required for source selection in
+ primary mux.
+ * @post_div_mask: indicates the post div mask to be used for the primary
+ mux.
+ * @post_div_shift: indicates the shift required for post divider
+ selection in primary mux.
+ * @hw: handle between common and hardware-specific interfaces.
+ */
+struct clk_debug_mux {
+ struct clk_src *parent;
+ int num_parents;
+ struct regmap **regmap;
+ void *priv;
+ u32 debug_offset;
+ u32 post_div_offset;
+ u32 cbcr_offset;
+ u32 src_sel_mask;
+ u32 src_sel_shift;
+ u32 post_div_mask;
+ u32 post_div_shift;
+ struct clk_hw hw;
+};
+
+#define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw)
+
+extern const struct clk_ops clk_debug_mux_ops;
+
+int clk_debug_measure_register(struct clk_hw *hw);
+int clk_debug_measure_add(struct clk_hw *hw, struct dentry *dentry);
+
+#endif
diff --git a/drivers/clk/qcom/clk-dummy.c b/drivers/clk/qcom/clk-dummy.c
index e2465c4..3435999 100644
--- a/drivers/clk/qcom/clk-dummy.c
+++ b/drivers/clk/qcom/clk-dummy.c
@@ -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
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#include "common.h"
+#include "clk-debug.h"
#define to_clk_dummy(_hw) container_of(_hw, struct clk_dummy, hw)
@@ -60,6 +61,7 @@
.round_rate = dummy_clk_round_rate,
.recalc_rate = dummy_clk_recalc_rate,
.set_flags = dummy_clk_set_flags,
+ .debug_init = clk_debug_measure_add,
};
EXPORT_SYMBOL_GPL(clk_dummy_ops);
diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c
new file mode 100644
index 0000000..d74db61
--- /dev/null
+++ b/drivers/clk/qcom/debugcc-sdm845.c
@@ -0,0 +1,885 @@
+/*
+ * 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/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "clk-debug.h"
+
+static struct measure_clk_data debug_mux_priv = {
+ .ctl_reg = 0x62024,
+ .status_reg = 0x62028,
+ .xo_div4_cbcr = 0x43008,
+};
+
+static const char *const debug_mux_parent_names[] = {
+ "cam_cc_bps_ahb_clk",
+ "cam_cc_bps_areg_clk",
+ "cam_cc_bps_axi_clk",
+ "cam_cc_bps_clk",
+ "cam_cc_camnoc_atb_clk",
+ "cam_cc_camnoc_axi_clk",
+ "cam_cc_cci_clk",
+ "cam_cc_cpas_ahb_clk",
+ "cam_cc_csi0phytimer_clk",
+ "cam_cc_csi1phytimer_clk",
+ "cam_cc_csi2phytimer_clk",
+ "cam_cc_csiphy0_clk",
+ "cam_cc_csiphy1_clk",
+ "cam_cc_csiphy2_clk",
+ "cam_cc_fd_core_clk",
+ "cam_cc_fd_core_uar_clk",
+ "cam_cc_icp_apb_clk",
+ "cam_cc_icp_atb_clk",
+ "cam_cc_icp_clk",
+ "cam_cc_icp_cti_clk",
+ "cam_cc_icp_ts_clk",
+ "cam_cc_ife_0_axi_clk",
+ "cam_cc_ife_0_clk",
+ "cam_cc_ife_0_cphy_rx_clk",
+ "cam_cc_ife_0_csid_clk",
+ "cam_cc_ife_0_dsp_clk",
+ "cam_cc_ife_1_axi_clk",
+ "cam_cc_ife_1_clk",
+ "cam_cc_ife_1_cphy_rx_clk",
+ "cam_cc_ife_1_csid_clk",
+ "cam_cc_ife_1_dsp_clk",
+ "cam_cc_ife_lite_clk",
+ "cam_cc_ife_lite_cphy_rx_clk",
+ "cam_cc_ife_lite_csid_clk",
+ "cam_cc_ipe_0_ahb_clk",
+ "cam_cc_ipe_0_areg_clk",
+ "cam_cc_ipe_0_axi_clk",
+ "cam_cc_ipe_0_clk",
+ "cam_cc_ipe_1_ahb_clk",
+ "cam_cc_ipe_1_areg_clk",
+ "cam_cc_ipe_1_axi_clk",
+ "cam_cc_ipe_1_clk",
+ "cam_cc_jpeg_clk",
+ "cam_cc_lrme_clk",
+ "cam_cc_mclk0_clk",
+ "cam_cc_mclk1_clk",
+ "cam_cc_mclk2_clk",
+ "cam_cc_mclk3_clk",
+ "cam_cc_soc_ahb_clk",
+ "cam_cc_sys_tmr_clk",
+ "disp_cc_mdss_ahb_clk",
+ "disp_cc_mdss_axi_clk",
+ "disp_cc_mdss_byte0_clk",
+ "disp_cc_mdss_byte0_intf_clk",
+ "disp_cc_mdss_byte1_clk",
+ "disp_cc_mdss_byte1_intf_clk",
+ "disp_cc_mdss_dp_aux_clk",
+ "disp_cc_mdss_dp_crypto_clk",
+ "disp_cc_mdss_dp_link_clk",
+ "disp_cc_mdss_dp_link_intf_clk",
+ "disp_cc_mdss_dp_pixel1_clk",
+ "disp_cc_mdss_dp_pixel_clk",
+ "disp_cc_mdss_esc0_clk",
+ "disp_cc_mdss_esc1_clk",
+ "disp_cc_mdss_mdp_clk",
+ "disp_cc_mdss_mdp_lut_clk",
+ "disp_cc_mdss_pclk0_clk",
+ "disp_cc_mdss_pclk1_clk",
+ "disp_cc_mdss_qdss_at_clk",
+ "disp_cc_mdss_qdss_tsctr_div8_clk",
+ "disp_cc_mdss_rot_clk",
+ "disp_cc_mdss_rscc_ahb_clk",
+ "disp_cc_mdss_rscc_vsync_clk",
+ "disp_cc_mdss_spdm_debug_clk",
+ "disp_cc_mdss_spdm_dp_crypto_clk",
+ "disp_cc_mdss_spdm_dp_pixel1_clk",
+ "disp_cc_mdss_spdm_dp_pixel_clk",
+ "disp_cc_mdss_spdm_mdp_clk",
+ "disp_cc_mdss_spdm_pclk0_clk",
+ "disp_cc_mdss_spdm_pclk1_clk",
+ "disp_cc_mdss_spdm_rot_clk",
+ "disp_cc_mdss_vsync_clk",
+ "gcc_aggre_noc_pcie_tbu_clk",
+ "gcc_aggre_ufs_card_axi_clk",
+ "gcc_aggre_ufs_phy_axi_clk",
+ "gcc_aggre_usb3_prim_axi_clk",
+ "gcc_aggre_usb3_sec_axi_clk",
+ "gcc_boot_rom_ahb_clk",
+ "gcc_camera_ahb_clk",
+ "gcc_camera_axi_clk",
+ "gcc_camera_xo_clk",
+ "gcc_ce1_ahb_clk",
+ "gcc_ce1_axi_clk",
+ "gcc_ce1_clk",
+ "gcc_cfg_noc_usb3_prim_axi_clk",
+ "gcc_cfg_noc_usb3_sec_axi_clk",
+ "gcc_cpuss_ahb_clk",
+ "gcc_cpuss_dvm_bus_clk",
+ "gcc_cpuss_gnoc_clk",
+ "gcc_cpuss_rbcpr_clk",
+ "gcc_ddrss_gpu_axi_clk",
+ "gcc_disp_ahb_clk",
+ "gcc_disp_axi_clk",
+ "gcc_disp_gpll0_clk_src",
+ "gcc_disp_gpll0_div_clk_src",
+ "gcc_disp_xo_clk",
+ "gcc_gp1_clk",
+ "gcc_gp2_clk",
+ "gcc_gp3_clk",
+ "gcc_gpu_cfg_ahb_clk",
+ "gcc_gpu_gpll0_clk_src",
+ "gcc_gpu_gpll0_div_clk_src",
+ "gcc_gpu_memnoc_gfx_clk",
+ "gcc_gpu_snoc_dvm_gfx_clk",
+ "gcc_mss_axis2_clk",
+ "gcc_mss_cfg_ahb_clk",
+ "gcc_mss_gpll0_div_clk_src",
+ "gcc_mss_mfab_axis_clk",
+ "gcc_mss_q6_memnoc_axi_clk",
+ "gcc_mss_snoc_axi_clk",
+ "gcc_pcie_0_aux_clk",
+ "gcc_pcie_0_cfg_ahb_clk",
+ "gcc_pcie_0_mstr_axi_clk",
+ "gcc_pcie_0_pipe_clk",
+ "gcc_pcie_0_slv_axi_clk",
+ "gcc_pcie_0_slv_q2a_axi_clk",
+ "gcc_pcie_1_aux_clk",
+ "gcc_pcie_1_cfg_ahb_clk",
+ "gcc_pcie_1_mstr_axi_clk",
+ "gcc_pcie_1_pipe_clk",
+ "gcc_pcie_1_slv_axi_clk",
+ "gcc_pcie_1_slv_q2a_axi_clk",
+ "gcc_pcie_phy_aux_clk",
+ "gcc_pcie_phy_refgen_clk",
+ "gcc_pdm2_clk",
+ "gcc_pdm_ahb_clk",
+ "gcc_pdm_xo4_clk",
+ "gcc_prng_ahb_clk",
+ "gcc_qmip_camera_ahb_clk",
+ "gcc_qmip_disp_ahb_clk",
+ "gcc_qmip_video_ahb_clk",
+ "gcc_qupv3_wrap0_core_2x_clk",
+ "gcc_qupv3_wrap0_core_clk",
+ "gcc_qupv3_wrap0_s0_clk",
+ "gcc_qupv3_wrap0_s1_clk",
+ "gcc_qupv3_wrap0_s2_clk",
+ "gcc_qupv3_wrap0_s3_clk",
+ "gcc_qupv3_wrap0_s4_clk",
+ "gcc_qupv3_wrap0_s5_clk",
+ "gcc_qupv3_wrap0_s6_clk",
+ "gcc_qupv3_wrap0_s7_clk",
+ "gcc_qupv3_wrap1_core_2x_clk",
+ "gcc_qupv3_wrap1_core_clk",
+ "gcc_qupv3_wrap1_s0_clk",
+ "gcc_qupv3_wrap1_s1_clk",
+ "gcc_qupv3_wrap1_s2_clk",
+ "gcc_qupv3_wrap1_s3_clk",
+ "gcc_qupv3_wrap1_s4_clk",
+ "gcc_qupv3_wrap1_s5_clk",
+ "gcc_qupv3_wrap1_s6_clk",
+ "gcc_qupv3_wrap1_s7_clk",
+ "gcc_qupv3_wrap_0_m_ahb_clk",
+ "gcc_qupv3_wrap_0_s_ahb_clk",
+ "gcc_qupv3_wrap_1_m_ahb_clk",
+ "gcc_qupv3_wrap_1_s_ahb_clk",
+ "gcc_sdcc2_ahb_clk",
+ "gcc_sdcc2_apps_clk",
+ "gcc_sdcc4_ahb_clk",
+ "gcc_sdcc4_apps_clk",
+ "gcc_sys_noc_cpuss_ahb_clk",
+ "gcc_tsif_ahb_clk",
+ "gcc_tsif_inactivity_timers_clk",
+ "gcc_tsif_ref_clk",
+ "gcc_ufs_card_ahb_clk",
+ "gcc_ufs_card_axi_clk",
+ "gcc_ufs_card_ice_core_clk",
+ "gcc_ufs_card_phy_aux_clk",
+ "gcc_ufs_card_rx_symbol_0_clk",
+ "gcc_ufs_card_rx_symbol_1_clk",
+ "gcc_ufs_card_tx_symbol_0_clk",
+ "gcc_ufs_card_unipro_core_clk",
+ "gcc_ufs_phy_ahb_clk",
+ "gcc_ufs_phy_axi_clk",
+ "gcc_ufs_phy_ice_core_clk",
+ "gcc_ufs_phy_phy_aux_clk",
+ "gcc_ufs_phy_rx_symbol_0_clk",
+ "gcc_ufs_phy_rx_symbol_1_clk",
+ "gcc_ufs_phy_tx_symbol_0_clk",
+ "gcc_ufs_phy_unipro_core_clk",
+ "gcc_usb30_prim_master_clk",
+ "gcc_usb30_prim_mock_utmi_clk",
+ "gcc_usb30_prim_sleep_clk",
+ "gcc_usb30_sec_master_clk",
+ "gcc_usb30_sec_mock_utmi_clk",
+ "gcc_usb30_sec_sleep_clk",
+ "gcc_usb3_prim_phy_aux_clk",
+ "gcc_usb3_prim_phy_com_aux_clk",
+ "gcc_usb3_prim_phy_pipe_clk",
+ "gcc_usb3_sec_phy_aux_clk",
+ "gcc_usb3_sec_phy_com_aux_clk",
+ "gcc_usb3_sec_phy_pipe_clk",
+ "gcc_usb_phy_cfg_ahb2phy_clk",
+ "gcc_video_ahb_clk",
+ "gcc_video_axi_clk",
+ "gcc_video_xo_clk",
+ "gpu_cc_acd_cxo_clk",
+ "gpu_cc_ahb_clk",
+ "gpu_cc_crc_ahb_clk",
+ "gpu_cc_cx_apb_clk",
+ "gpu_cc_cx_gfx3d_clk",
+ "gpu_cc_cx_gfx3d_slv_clk",
+ "gpu_cc_cx_gmu_clk",
+ "gpu_cc_cx_qdss_at_clk",
+ "gpu_cc_cx_qdss_trig_clk",
+ "gpu_cc_cx_qdss_tsctr_clk",
+ "gpu_cc_cx_snoc_dvm_clk",
+ "gpu_cc_cxo_aon_clk",
+ "gpu_cc_cxo_clk",
+ "gpu_cc_gx_cxo_clk",
+ "gpu_cc_gx_gmu_clk",
+ "gpu_cc_gx_qdss_tsctr_clk",
+ "gpu_cc_gx_vsense_clk",
+ "gpu_cc_rbcpr_ahb_clk",
+ "gpu_cc_rbcpr_clk",
+ "gpu_cc_sleep_clk",
+ "gpu_cc_spdm_gx_gfx3d_div_clk",
+ "video_cc_apb_clk",
+ "video_cc_at_clk",
+ "video_cc_qdss_trig_clk",
+ "video_cc_qdss_tsctr_div8_clk",
+ "video_cc_vcodec0_axi_clk",
+ "video_cc_vcodec0_core_clk",
+ "video_cc_vcodec1_axi_clk",
+ "video_cc_vcodec1_core_clk",
+ "video_cc_venus_ahb_clk",
+ "video_cc_venus_ctl_axi_clk",
+ "video_cc_venus_ctl_core_clk",
+};
+
+static struct clk_debug_mux gcc_debug_mux = {
+ .priv = &debug_mux_priv,
+ .debug_offset = 0x62008,
+ .post_div_offset = 0x62000,
+ .cbcr_offset = 0x62004,
+ .src_sel_mask = 0x3FF,
+ .src_sel_shift = 0,
+ .post_div_mask = 0xF,
+ .post_div_shift = 0,
+ MUX_SRC_LIST(
+ { "cam_cc_bps_ahb_clk", 0x46, 4, CAM_CC,
+ 0xE, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_bps_areg_clk", 0x46, 4, CAM_CC,
+ 0xD, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_bps_axi_clk", 0x46, 4, CAM_CC,
+ 0xC, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_bps_clk", 0x46, 4, CAM_CC,
+ 0xB, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_camnoc_atb_clk", 0x46, 4, CAM_CC,
+ 0x34, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_camnoc_axi_clk", 0x46, 4, CAM_CC,
+ 0x2D, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_cci_clk", 0x46, 4, CAM_CC,
+ 0x2A, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_cpas_ahb_clk", 0x46, 4, CAM_CC,
+ 0x2C, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_csi0phytimer_clk", 0x46, 4, CAM_CC,
+ 0x5, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_csi1phytimer_clk", 0x46, 4, CAM_CC,
+ 0x7, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_csi2phytimer_clk", 0x46, 4, CAM_CC,
+ 0x9, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_csiphy0_clk", 0x46, 4, CAM_CC,
+ 0x6, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_csiphy1_clk", 0x46, 4, CAM_CC,
+ 0x8, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_csiphy2_clk", 0x46, 4, CAM_CC,
+ 0xA, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_fd_core_clk", 0x46, 4, CAM_CC,
+ 0x28, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_fd_core_uar_clk", 0x46, 4, CAM_CC,
+ 0x29, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_icp_apb_clk", 0x46, 4, CAM_CC,
+ 0x32, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_icp_atb_clk", 0x46, 4, CAM_CC,
+ 0x2F, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_icp_clk", 0x46, 4, CAM_CC,
+ 0x26, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_icp_cti_clk", 0x46, 4, CAM_CC,
+ 0x30, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_icp_ts_clk", 0x46, 4, CAM_CC,
+ 0x31, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_0_axi_clk", 0x46, 4, CAM_CC,
+ 0x1B, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_0_clk", 0x46, 4, CAM_CC,
+ 0x17, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_0_cphy_rx_clk", 0x46, 4, CAM_CC,
+ 0x1A, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_0_csid_clk", 0x46, 4, CAM_CC,
+ 0x19, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_0_dsp_clk", 0x46, 4, CAM_CC,
+ 0x18, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_1_axi_clk", 0x46, 4, CAM_CC,
+ 0x21, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_1_clk", 0x46, 4, CAM_CC,
+ 0x1D, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_1_cphy_rx_clk", 0x46, 4, CAM_CC,
+ 0x20, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_1_csid_clk", 0x46, 4, CAM_CC,
+ 0x1F, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_1_dsp_clk", 0x46, 4, CAM_CC,
+ 0x1E, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_lite_clk", 0x46, 4, CAM_CC,
+ 0x22, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_lite_cphy_rx_clk", 0x46, 4, CAM_CC,
+ 0x24, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ife_lite_csid_clk", 0x46, 4, CAM_CC,
+ 0x23, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ipe_0_ahb_clk", 0x46, 4, CAM_CC,
+ 0x12, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ipe_0_areg_clk", 0x46, 4, CAM_CC,
+ 0x11, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ipe_0_axi_clk", 0x46, 4, CAM_CC,
+ 0x10, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ipe_0_clk", 0x46, 4, CAM_CC,
+ 0xF, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ipe_1_ahb_clk", 0x46, 4, CAM_CC,
+ 0x16, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ipe_1_areg_clk", 0x46, 4, CAM_CC,
+ 0x15, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ipe_1_axi_clk", 0x46, 4, CAM_CC,
+ 0x14, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_ipe_1_clk", 0x46, 4, CAM_CC,
+ 0x13, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_jpeg_clk", 0x46, 4, CAM_CC,
+ 0x25, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_lrme_clk", 0x46, 4, CAM_CC,
+ 0x2B, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_mclk0_clk", 0x46, 4, CAM_CC,
+ 0x1, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_mclk1_clk", 0x46, 4, CAM_CC,
+ 0x2, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_mclk2_clk", 0x46, 4, CAM_CC,
+ 0x3, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_mclk3_clk", 0x46, 4, CAM_CC,
+ 0x4, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_soc_ahb_clk", 0x46, 4, CAM_CC,
+ 0x2E, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "cam_cc_sys_tmr_clk", 0x46, 4, CAM_CC,
+ 0x33, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 },
+ { "disp_cc_mdss_ahb_clk", 0x47, 4, DISP_CC,
+ 0x13, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_axi_clk", 0x47, 4, DISP_CC,
+ 0x14, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_byte0_clk", 0x47, 4, DISP_CC,
+ 0x7, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_byte0_intf_clk", 0x47, 4, DISP_CC,
+ 0x8, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_byte1_clk", 0x47, 4, DISP_CC,
+ 0x9, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_byte1_intf_clk", 0x47, 4, DISP_CC,
+ 0xA, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_dp_aux_clk", 0x47, 4, DISP_CC,
+ 0x12, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_dp_crypto_clk", 0x47, 4, DISP_CC,
+ 0xF, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_dp_link_clk", 0x47, 4, DISP_CC,
+ 0xD, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_dp_link_intf_clk", 0x47, 4, DISP_CC,
+ 0xE, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_dp_pixel1_clk", 0x47, 4, DISP_CC,
+ 0x11, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_dp_pixel_clk", 0x47, 4, DISP_CC,
+ 0x10, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_esc0_clk", 0x47, 4, DISP_CC,
+ 0xB, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_esc1_clk", 0x47, 4, DISP_CC,
+ 0xC, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_mdp_clk", 0x47, 4, DISP_CC,
+ 0x3, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_mdp_lut_clk", 0x47, 4, DISP_CC,
+ 0x5, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_pclk0_clk", 0x47, 4, DISP_CC,
+ 0x1, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_pclk1_clk", 0x47, 4, DISP_CC,
+ 0x2, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_qdss_at_clk", 0x47, 4, DISP_CC,
+ 0x15, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_qdss_tsctr_div8_clk", 0x47, 4, DISP_CC,
+ 0x16, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_rot_clk", 0x47, 4, DISP_CC,
+ 0x4, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_rscc_ahb_clk", 0x47, 4, DISP_CC,
+ 0x17, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_rscc_vsync_clk", 0x47, 4, DISP_CC,
+ 0x18, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_spdm_debug_clk", 0x47, 4, DISP_CC,
+ 0x20, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_spdm_dp_crypto_clk", 0x47, 4, DISP_CC,
+ 0x1D, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_spdm_dp_pixel1_clk", 0x47, 4, DISP_CC,
+ 0x1F, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_spdm_dp_pixel_clk", 0x47, 4, DISP_CC,
+ 0x1E, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_spdm_mdp_clk", 0x47, 4, DISP_CC,
+ 0x1B, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_spdm_pclk0_clk", 0x47, 4, DISP_CC,
+ 0x19, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_spdm_pclk1_clk", 0x47, 4, DISP_CC,
+ 0x1A, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_spdm_rot_clk", 0x47, 4, DISP_CC,
+ 0x1C, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "disp_cc_mdss_vsync_clk", 0x47, 4, DISP_CC,
+ 0x6, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C },
+ { "gcc_aggre_noc_pcie_tbu_clk", 0x2D, 4, GCC,
+ 0x2D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_aggre_ufs_card_axi_clk", 0x11E, 4, GCC,
+ 0x11E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_aggre_ufs_phy_axi_clk", 0x11D, 4, GCC,
+ 0x11D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_aggre_usb3_prim_axi_clk", 0x11B, 4, GCC,
+ 0x11B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_aggre_usb3_sec_axi_clk", 0x11C, 4, GCC,
+ 0x11C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_boot_rom_ahb_clk", 0x94, 4, GCC,
+ 0x94, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_camera_ahb_clk", 0x3A, 4, GCC,
+ 0x3A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_camera_axi_clk", 0x40, 4, GCC,
+ 0x40, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_camera_xo_clk", 0x43, 4, GCC,
+ 0x43, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ce1_ahb_clk", 0xA9, 4, GCC,
+ 0xA9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ce1_axi_clk", 0xA8, 4, GCC,
+ 0xA8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ce1_clk", 0xA7, 4, GCC,
+ 0xA7, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_cfg_noc_usb3_prim_axi_clk", 0x1D, 4, GCC,
+ 0x1D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_cfg_noc_usb3_sec_axi_clk", 0x1E, 4, GCC,
+ 0x1E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_cpuss_ahb_clk", 0xCE, 4, GCC,
+ 0xCE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_cpuss_dvm_bus_clk", 0xD3, 4, GCC,
+ 0xD3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_cpuss_gnoc_clk", 0xCF, 4, GCC,
+ 0xCF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_cpuss_rbcpr_clk", 0xD0, 4, GCC,
+ 0xD0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ddrss_gpu_axi_clk", 0xBB, 4, GCC,
+ 0xBB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_disp_ahb_clk", 0x3B, 4, GCC,
+ 0x3B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_disp_axi_clk", 0x41, 4, GCC,
+ 0x41, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_disp_gpll0_clk_src", 0x4C, 4, GCC,
+ 0x4C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_disp_gpll0_div_clk_src", 0x4D, 4, GCC,
+ 0x4D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_disp_xo_clk", 0x44, 4, GCC,
+ 0x44, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gp1_clk", 0xDE, 4, GCC,
+ 0xDE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gp2_clk", 0xDF, 4, GCC,
+ 0xDF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gp3_clk", 0xE0, 4, GCC,
+ 0xE0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gpu_cfg_ahb_clk", 0x142, 4, GCC,
+ 0x142, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gpu_gpll0_clk_src", 0x148, 4, GCC,
+ 0x148, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gpu_gpll0_div_clk_src", 0x149, 4, GCC,
+ 0x149, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gpu_memnoc_gfx_clk", 0x145, 4, GCC,
+ 0x145, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_gpu_snoc_dvm_gfx_clk", 0x147, 4, GCC,
+ 0x147, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_mss_axis2_clk", 0x12F, 4, GCC,
+ 0x12F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_mss_cfg_ahb_clk", 0x12D, 4, GCC,
+ 0x12D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_mss_gpll0_div_clk_src", 0x133, 4, GCC,
+ 0x133, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_mss_mfab_axis_clk", 0x12E, 4, GCC,
+ 0x12E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_mss_q6_memnoc_axi_clk", 0x135, 4, GCC,
+ 0x135, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_mss_snoc_axi_clk", 0x134, 4, GCC,
+ 0x134, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_0_aux_clk", 0xE5, 4, GCC,
+ 0xE5, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_0_cfg_ahb_clk", 0xE4, 4, GCC,
+ 0xE4, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_0_mstr_axi_clk", 0xE3, 4, GCC,
+ 0xE3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_0_pipe_clk", 0xE6, 4, GCC,
+ 0xE6, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_0_slv_axi_clk", 0xE2, 4, GCC,
+ 0xE2, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_0_slv_q2a_axi_clk", 0xE1, 4, GCC,
+ 0xE1, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_1_aux_clk", 0xEC, 4, GCC,
+ 0xEC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_1_cfg_ahb_clk", 0xEB, 4, GCC,
+ 0xEB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_1_mstr_axi_clk", 0xEA, 4, GCC,
+ 0xEA, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_1_pipe_clk", 0xED, 4, GCC,
+ 0xED, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_1_slv_axi_clk", 0xE9, 4, GCC,
+ 0xE9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_1_slv_q2a_axi_clk", 0xE8, 4, GCC,
+ 0xE8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_phy_aux_clk", 0xEF, 4, GCC,
+ 0xEF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pcie_phy_refgen_clk", 0x160, 4, GCC,
+ 0x160, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pdm2_clk", 0x8E, 4, GCC,
+ 0x8E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pdm_ahb_clk", 0x8C, 4, GCC,
+ 0x8C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_pdm_xo4_clk", 0x8D, 4, GCC,
+ 0x8D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_prng_ahb_clk", 0x8F, 4, GCC,
+ 0x8F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qmip_camera_ahb_clk", 0x3D, 4, GCC,
+ 0x3D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qmip_disp_ahb_clk", 0x3E, 4, GCC,
+ 0x3E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qmip_video_ahb_clk", 0x3C, 4, GCC,
+ 0x3C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_core_2x_clk", 0x77, 4, GCC,
+ 0x77, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_core_clk", 0x76, 4, GCC,
+ 0x76, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_s0_clk", 0x78, 4, GCC,
+ 0x78, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_s1_clk", 0x79, 4, GCC,
+ 0x79, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_s2_clk", 0x7A, 4, GCC,
+ 0x7A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_s3_clk", 0x7B, 4, GCC,
+ 0x7B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_s4_clk", 0x7C, 4, GCC,
+ 0x7C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_s5_clk", 0x7D, 4, GCC,
+ 0x7D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_s6_clk", 0x7E, 4, GCC,
+ 0x7E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap0_s7_clk", 0x7F, 4, GCC,
+ 0x7F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_core_2x_clk", 0x80, 4, GCC,
+ 0x80, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_core_clk", 0x81, 4, GCC,
+ 0x81, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_s0_clk", 0x84, 4, GCC,
+ 0x84, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_s1_clk", 0x85, 4, GCC,
+ 0x85, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_s2_clk", 0x86, 4, GCC,
+ 0x86, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_s3_clk", 0x87, 4, GCC,
+ 0x87, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_s4_clk", 0x88, 4, GCC,
+ 0x88, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_s5_clk", 0x89, 4, GCC,
+ 0x89, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_s6_clk", 0x8A, 4, GCC,
+ 0x8A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap1_s7_clk", 0x8B, 4, GCC,
+ 0x8B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap_0_m_ahb_clk", 0x74, 4, GCC,
+ 0x74, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap_0_s_ahb_clk", 0x75, 4, GCC,
+ 0x75, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap_1_m_ahb_clk", 0x82, 4, GCC,
+ 0x82, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_qupv3_wrap_1_s_ahb_clk", 0x83, 4, GCC,
+ 0x83, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_sdcc2_ahb_clk", 0x71, 4, GCC,
+ 0x71, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_sdcc2_apps_clk", 0x70, 4, GCC,
+ 0x70, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_sdcc4_ahb_clk", 0x73, 4, GCC,
+ 0x73, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_sdcc4_apps_clk", 0x72, 4, GCC,
+ 0x72, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_sys_noc_cpuss_ahb_clk", 0xC, 4, GCC,
+ 0xC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_tsif_ahb_clk", 0x90, 4, GCC,
+ 0x90, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_tsif_inactivity_timers_clk", 0x92, 4, GCC,
+ 0x92, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_tsif_ref_clk", 0x91, 4, GCC,
+ 0x91, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_card_ahb_clk", 0xF1, 4, GCC,
+ 0xF1, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_card_axi_clk", 0xF0, 4, GCC,
+ 0xF0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_card_ice_core_clk", 0xF7, 4, GCC,
+ 0xF7, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_card_phy_aux_clk", 0xF8, 4, GCC,
+ 0xF8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_card_rx_symbol_0_clk", 0xF3, 4, GCC,
+ 0xF3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_card_rx_symbol_1_clk", 0xF9, 4, GCC,
+ 0xF9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_card_tx_symbol_0_clk", 0xF2, 4, GCC,
+ 0xF2, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_card_unipro_core_clk", 0xF6, 4, GCC,
+ 0xF6, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_phy_ahb_clk", 0xFC, 4, GCC,
+ 0xFC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_phy_axi_clk", 0xFB, 4, GCC,
+ 0xFB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_phy_ice_core_clk", 0x102, 4, GCC,
+ 0x102, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_phy_phy_aux_clk", 0x103, 4, GCC,
+ 0x103, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_phy_rx_symbol_0_clk", 0xFE, 4, GCC,
+ 0xFE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_phy_rx_symbol_1_clk", 0x104, 4, GCC,
+ 0x104, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_phy_tx_symbol_0_clk", 0xFD, 4, GCC,
+ 0xFD, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_ufs_phy_unipro_core_clk", 0x101, 4, GCC,
+ 0x101, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb30_prim_master_clk", 0x5F, 4, GCC,
+ 0x5F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb30_prim_mock_utmi_clk", 0x61, 4, GCC,
+ 0x61, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb30_prim_sleep_clk", 0x60, 4, GCC,
+ 0x60, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb30_sec_master_clk", 0x65, 4, GCC,
+ 0x65, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb30_sec_mock_utmi_clk", 0x67, 4, GCC,
+ 0x67, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb30_sec_sleep_clk", 0x66, 4, GCC,
+ 0x66, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb3_prim_phy_aux_clk", 0x62, 4, GCC,
+ 0x62, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb3_prim_phy_com_aux_clk", 0x63, 4, GCC,
+ 0x63, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb3_prim_phy_pipe_clk", 0x64, 4, GCC,
+ 0x64, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb3_sec_phy_aux_clk", 0x68, 4, GCC,
+ 0x68, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb3_sec_phy_com_aux_clk", 0x69, 4, GCC,
+ 0x69, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb3_sec_phy_pipe_clk", 0x6A, 4, GCC,
+ 0x6A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_usb_phy_cfg_ahb2phy_clk", 0x6F, 4, GCC,
+ 0x6F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_video_ahb_clk", 0x39, 4, GCC,
+ 0x39, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_video_axi_clk", 0x3F, 4, GCC,
+ 0x3F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gcc_video_xo_clk", 0x42, 4, GCC,
+ 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 },
+ { "gpu_cc_acd_cxo_clk", 0x144, 4, GPU_CC,
+ 0x1F, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_ahb_clk", 0x144, 4, GPU_CC,
+ 0x11, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_crc_ahb_clk", 0x144, 4, GPU_CC,
+ 0x12, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cx_apb_clk", 0x144, 4, GPU_CC,
+ 0x15, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cx_gfx3d_clk", 0x144, 4, GPU_CC,
+ 0x1A, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cx_gfx3d_slv_clk", 0x144, 4, GPU_CC,
+ 0x1B, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cx_gmu_clk", 0x144, 4, GPU_CC,
+ 0x19, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cx_qdss_at_clk", 0x144, 4, GPU_CC,
+ 0x13, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cx_qdss_trig_clk", 0x144, 4, GPU_CC,
+ 0x18, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cx_qdss_tsctr_clk", 0x144, 4, GPU_CC,
+ 0x14, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cx_snoc_dvm_clk", 0x144, 4, GPU_CC,
+ 0x16, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cxo_aon_clk", 0x144, 4, GPU_CC,
+ 0xB, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_cxo_clk", 0x144, 4, GPU_CC,
+ 0xA, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_gx_cxo_clk", 0x144, 4, GPU_CC,
+ 0xF, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_gx_gmu_clk", 0x144, 4, GPU_CC,
+ 0x10, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_gx_qdss_tsctr_clk", 0x144, 4, GPU_CC,
+ 0xE, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_gx_vsense_clk", 0x144, 4, GPU_CC,
+ 0xD, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_rbcpr_ahb_clk", 0x144, 4, GPU_CC,
+ 0x1D, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_rbcpr_clk", 0x144, 4, GPU_CC,
+ 0x1C, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_sleep_clk", 0x144, 4, GPU_CC,
+ 0x17, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "gpu_cc_spdm_gx_gfx3d_div_clk", 0x144, 4, GPU_CC,
+ 0x1E, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 },
+ { "video_cc_apb_clk", 0x48, 4, VIDEO_CC,
+ 0x8, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_at_clk", 0x48, 4, VIDEO_CC,
+ 0xB, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_qdss_trig_clk", 0x48, 4, VIDEO_CC,
+ 0x7, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_qdss_tsctr_div8_clk", 0x48, 4, VIDEO_CC,
+ 0xA, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_vcodec0_axi_clk", 0x48, 4, VIDEO_CC,
+ 0x5, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_vcodec0_core_clk", 0x48, 4, VIDEO_CC,
+ 0x2, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_vcodec1_axi_clk", 0x48, 4, VIDEO_CC,
+ 0x6, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_vcodec1_core_clk", 0x48, 4, VIDEO_CC,
+ 0x3, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_venus_ahb_clk", 0x48, 4, VIDEO_CC,
+ 0x9, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_venus_ctl_axi_clk", 0x48, 4, VIDEO_CC,
+ 0x4, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ { "video_cc_venus_ctl_core_clk", 0x48, 4, VIDEO_CC,
+ 0x1, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 },
+ ),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_debug_mux",
+ .ops = &clk_debug_mux_ops,
+ .parent_names = debug_mux_parent_names,
+ .num_parents = ARRAY_SIZE(debug_mux_parent_names),
+ .flags = CLK_IS_MEASURE,
+ },
+};
+
+static const struct of_device_id clk_debug_match_table[] = {
+ { .compatible = "qcom,debugcc-sdm845" },
+ {}
+};
+
+static int clk_debug_845_probe(struct platform_device *pdev)
+{
+ struct clk *clk;
+ int ret = 0, count;
+
+ clk = devm_clk_get(&pdev->dev, "xo_clk_src");
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Unable to get xo clock\n");
+ return PTR_ERR(clk);
+ }
+
+ debug_mux_priv.cxo = clk;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,cc-count",
+ &count);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Num of debug clock controller not specified\n");
+ return ret;
+ }
+
+ if (!count) {
+ dev_err(&pdev->dev, "Count of CC cannot be zero\n");
+ return -EINVAL;
+ }
+
+ gcc_debug_mux.regmap = devm_kzalloc(&pdev->dev,
+ sizeof(struct regmap *) * count, GFP_KERNEL);
+ if (!gcc_debug_mux.regmap)
+ return -ENOMEM;
+
+ if (of_get_property(pdev->dev.of_node, "qcom,gcc", NULL)) {
+ gcc_debug_mux.regmap[GCC] =
+ syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "qcom,gcc");
+ if (IS_ERR(gcc_debug_mux.regmap[GCC])) {
+ pr_err("Failed to map qcom,gcc\n");
+ return PTR_ERR(gcc_debug_mux.regmap[GCC]);
+ }
+ }
+
+ if (of_get_property(pdev->dev.of_node, "qcom,dispcc", NULL)) {
+ gcc_debug_mux.regmap[DISP_CC] =
+ syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "qcom,dispcc");
+ if (IS_ERR(gcc_debug_mux.regmap[DISP_CC])) {
+ pr_err("Failed to map qcom,dispcc\n");
+ return PTR_ERR(gcc_debug_mux.regmap[DISP_CC]);
+ }
+ }
+
+ if (of_get_property(pdev->dev.of_node, "qcom,videocc", NULL)) {
+ gcc_debug_mux.regmap[VIDEO_CC] =
+ syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "qcom,videocc");
+ if (IS_ERR(gcc_debug_mux.regmap[VIDEO_CC])) {
+ pr_err("Failed to map qcom,videocc\n");
+ return PTR_ERR(gcc_debug_mux.regmap[VIDEO_CC]);
+ }
+ }
+
+ if (of_get_property(pdev->dev.of_node, "qcom,camcc", NULL)) {
+ gcc_debug_mux.regmap[CAM_CC] =
+ syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "qcom,camcc");
+ if (IS_ERR(gcc_debug_mux.regmap[CAM_CC])) {
+ pr_err("Failed to map qcom,camcc\n");
+ return PTR_ERR(gcc_debug_mux.regmap[CAM_CC]);
+ }
+ }
+
+ if (of_get_property(pdev->dev.of_node, "qcom,gpucc", NULL)) {
+ gcc_debug_mux.regmap[GPU_CC] =
+ syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "qcom,gpucc");
+ if (IS_ERR(gcc_debug_mux.regmap[GPU_CC])) {
+ pr_err("Failed to map qcom,gpucc\n");
+ return PTR_ERR(gcc_debug_mux.regmap[GPU_CC]);
+ }
+ }
+
+ clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "Unable to register GCC debug mux\n");
+ return PTR_ERR(clk);
+ }
+
+ ret = clk_debug_measure_register(&gcc_debug_mux.hw);
+ if (ret)
+ dev_err(&pdev->dev, "Could not register Measure clock\n");
+ else
+ dev_info(&pdev->dev, "Registered debug mux successfully\n");
+
+ return ret;
+}
+
+static struct platform_driver clk_debug_driver = {
+ .probe = clk_debug_845_probe,
+ .driver = {
+ .name = "debugcc-sdm845",
+ .of_match_table = clk_debug_match_table,
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init clk_debug_845_init(void)
+{
+ return platform_driver_register(&clk_debug_driver);
+}
+fs_initcall(clk_debug_845_init);
+
+MODULE_DESCRIPTION("QTI DEBUG CC SDM845 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:debugcc-sdm845");
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index 44c9b48..6b1eca8 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -146,10 +146,11 @@
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_fabia_pll_ops,
- VDD_CX_FMAX_MAP2(
- MIN, 430000000,
- LOW, 860000000
- ),
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
},
},
};
diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c
index 0f6039e..08dce3f 100644
--- a/drivers/clk/qcom/gcc-sdm845.c
+++ b/drivers/clk/qcom/gcc-sdm845.c
@@ -168,6 +168,11 @@
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_fabia_fixed_pll_ops,
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
},
},
};
@@ -207,7 +212,11 @@
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_fabia_fixed_pll_ops,
- VDD_CX_FMAX_MAP1(MIN, 1066000000),
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
},
},
};
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..a8d08b3 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
@@ -90,14 +90,31 @@
}, \
.num_rate_max = VDD_CX_NUM
-#define VDD_MX_FMAX_MAP2(l1, f1, l2, f2) \
+#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 +126,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/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c
index 0e9cf88..8b63979 100644
--- a/drivers/clk/qcom/videocc-sdm845.c
+++ b/drivers/clk/qcom/videocc-sdm845.c
@@ -83,13 +83,11 @@
.parent_names = (const char *[]){ "bi_tcxo" },
.num_parents = 1,
.ops = &clk_fabia_pll_ops,
- VDD_CX_FMAX_MAP5(
- MIN, 200000000,
- LOW, 640000000,
- LOW_L1, 760000000,
- NOMINAL, 1332000000,
- HIGH, 1599000000),
-
+ VDD_CX_FMAX_MAP4(
+ MIN, 615000000,
+ LOW, 1066000000,
+ LOW_L1, 1600000000,
+ NOMINAL, 2000000000),
},
},
};
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/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 96e18162..e2023bd 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -263,4 +263,4 @@
bool "MSM CPUFreq support"
depends on CPU_FREQ
help
- This enables the CPUFreq driver for Qualcomm CPUs.
+ This enables the CPUFreq driver for Qualcomm Technologies, Inc. CPUs.
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/Kconfig b/drivers/devfreq/Kconfig
index 3c02541..6476c5e 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -99,11 +99,11 @@
the mem_latency devfreq governor.
config QCOMCCI_HWMON
- tristate "QCOM CCI Cache monitor hardware"
+ tristate "QTI CCI Cache monitor hardware"
depends on ARCH_QCOM
help
- QCOM CCI has additional PMU counters that can be used to monitor
- cache requests. QCOM CCI hardware monitor device configures these
+ QTI CCI has additional PMU counters that can be used to monitor
+ cache requests. QTI CCI hardware monitor device configures these
registers to monitor cache and inform governor. It can also set an
IRQ when count exceeds a programmable limit.
@@ -205,7 +205,7 @@
clock APIs and don't have any form of status reporting.
config QCOM_DEVFREQ_DEVBW
- bool "QCOM DEVFREQ device for device master <-> slave IB/AB BW voting"
+ bool "Qualcomm Technologies Inc. DEVFREQ device for device master <-> slave IB/AB BW voting"
depends on ARCH_QCOM
select DEVFREQ_GOV_PERFORMANCE
select DEVFREQ_GOV_POWERSAVE
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/edac/qcom_llcc_edac.c b/drivers/edac/qcom_llcc_edac.c
index d469869..6bec860 100644
--- a/drivers/edac/qcom_llcc_edac.c
+++ b/drivers/edac/qcom_llcc_edac.c
@@ -39,6 +39,10 @@
#define DRP_SYN_REG_CNT 8
+#define LLCC_COMMON_STATUS0 0x0003000C
+#define LLCC_LB_CNT_MASK 0xf0000000
+#define LLCC_LB_CNT_SHIFT 28
+
/* single & Double Bit syndrome register offsets */
#define TRP_ECC_SB_ERR_SYN0 0x0002304C
#define TRP_ECC_DB_ERR_SYN0 0x00020370
@@ -97,7 +101,10 @@
struct erp_drvdata {
struct regmap *llcc_map;
+ phys_addr_t *llcc_banks;
u32 ecc_irq;
+ u32 num_banks;
+ u32 b_off;
};
static const struct errors_edac errors[] = {
@@ -108,29 +115,32 @@
};
/* Clear the error interrupt and counter registers */
-static void qcom_llcc_clear_errors(int err_type, struct regmap *llcc_map)
+static void qcom_llcc_clear_errors(int err_type, struct erp_drvdata *drv)
{
switch (err_type) {
case LLCC_DRAM_CE:
case LLCC_DRAM_UE:
/* Clear the interrupt */
- regmap_write(llcc_map, DRP_INTERRUPT_CLEAR, DRP_TRP_INT_CLEAR);
+ regmap_write(drv->llcc_map, drv->b_off + DRP_INTERRUPT_CLEAR,
+ DRP_TRP_INT_CLEAR);
/* Clear the counters */
- regmap_write(llcc_map, DRP_ECC_ERROR_CNTR_CLEAR,
+ regmap_write(drv->llcc_map,
+ drv->b_off + DRP_ECC_ERROR_CNTR_CLEAR,
DRP_TRP_CNT_CLEAR);
break;
case LLCC_TRAM_CE:
case LLCC_TRAM_UE:
- regmap_write(llcc_map, TRP_INTERRUPT_0_CLEAR,
+ regmap_write(drv->llcc_map, drv->b_off + TRP_INTERRUPT_0_CLEAR,
DRP_TRP_INT_CLEAR);
- regmap_write(llcc_map, TRP_ECC_ERROR_CNTR_CLEAR,
- DRP_TRP_CNT_CLEAR);
+ regmap_write(drv->llcc_map,
+ drv->b_off + TRP_ECC_ERROR_CNTR_CLEAR,
+ DRP_TRP_CNT_CLEAR);
break;
}
}
/* Dump syndrome registers for tag Ram Double bit errors */
-static void dump_trp_db_syn_reg(struct regmap *llcc_map)
+static void dump_trp_db_syn_reg(struct erp_drvdata *drv, u32 bank)
{
int i;
int db_err_cnt;
@@ -140,17 +150,20 @@
for (i = 0; i < TRP_SYN_REG_CNT; i++) {
synd_reg = TRP_ECC_DB_ERR_SYN0 + (i * 4);
- regmap_read(llcc_map, synd_reg, &synd_val);
+ regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
+ &synd_val);
edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n",
i, synd_val);
}
- regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &db_err_cnt);
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &db_err_cnt);
db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK);
edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n",
db_err_cnt);
- regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &db_err_ways);
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &db_err_ways);
db_err_ways = (db_err_ways & ECC_DB_ERR_WAYS_MASK);
db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT;
@@ -159,7 +172,7 @@
}
/* Dump syndrome register for tag Ram Single Bit Errors */
-static void dump_trp_sb_syn_reg(struct regmap *llcc_map)
+static void dump_trp_sb_syn_reg(struct erp_drvdata *drv, u32 bank)
{
int i;
int sb_err_cnt;
@@ -169,18 +182,21 @@
for (i = 0; i < TRP_SYN_REG_CNT; i++) {
synd_reg = TRP_ECC_SB_ERR_SYN0 + (i * 4);
- regmap_read(llcc_map, synd_reg, &synd_val);
+ regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
+ &synd_val);
edac_printk(KERN_CRIT, EDAC_LLCC, "TRP_ECC_SYN%d: 0x%8x\n",
i, synd_val);
}
- regmap_read(llcc_map, TRP_ECC_ERROR_STATUS1, &sb_err_cnt);
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS1, &sb_err_cnt);
sb_err_cnt = (sb_err_cnt & ECC_SB_ERR_COUNT_MASK);
sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT;
edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n",
sb_err_cnt);
- regmap_read(llcc_map, TRP_ECC_ERROR_STATUS0, &sb_err_ways);
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[bank] + TRP_ECC_ERROR_STATUS0, &sb_err_ways);
sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK;
edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n",
@@ -188,7 +204,7 @@
}
/* Dump syndrome registers for Data Ram Double bit errors */
-static void dump_drp_db_syn_reg(struct regmap *llcc_map)
+static void dump_drp_db_syn_reg(struct erp_drvdata *drv, u32 bank)
{
int i;
int db_err_cnt;
@@ -198,17 +214,20 @@
for (i = 0; i < DRP_SYN_REG_CNT; i++) {
synd_reg = DRP_ECC_DB_ERR_SYN0 + (i * 4);
- regmap_read(llcc_map, synd_reg, &synd_val);
+ regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
+ &synd_val);
edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n",
i, synd_val);
}
- regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &db_err_cnt);
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &db_err_cnt);
db_err_cnt = (db_err_cnt & ECC_DB_ERR_COUNT_MASK);
edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error count: 0x%4x\n",
db_err_cnt);
- regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &db_err_ways);
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &db_err_ways);
db_err_ways &= ECC_DB_ERR_WAYS_MASK;
db_err_ways >>= ECC_DB_ERR_WAYS_SHIFT;
edac_printk(KERN_CRIT, EDAC_LLCC, "Double-Bit error ways: 0x%4x\n",
@@ -216,7 +235,7 @@
}
/* Dump Syndrome registers for Data Ram Single bit errors*/
-static void dump_drp_sb_syn_reg(struct regmap *llcc_map)
+static void dump_drp_sb_syn_reg(struct erp_drvdata *drv, u32 bank)
{
int i;
int sb_err_cnt;
@@ -226,18 +245,21 @@
for (i = 0; i < DRP_SYN_REG_CNT; i++) {
synd_reg = DRP_ECC_SB_ERR_SYN0 + (i * 4);
- regmap_read(llcc_map, synd_reg, &synd_val);
+ regmap_read(drv->llcc_map, drv->llcc_banks[bank] + synd_reg,
+ &synd_val);
edac_printk(KERN_CRIT, EDAC_LLCC, "DRP_ECC_SYN%d: 0x%8x\n",
i, synd_val);
}
- regmap_read(llcc_map, DRP_ECC_ERROR_STATUS1, &sb_err_cnt);
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS1, &sb_err_cnt);
sb_err_cnt &= ECC_SB_ERR_COUNT_MASK;
sb_err_cnt >>= ECC_SB_ERR_COUNT_SHIFT;
edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error count: 0x%4x\n",
sb_err_cnt);
- regmap_read(llcc_map, DRP_ECC_ERROR_STATUS0, &sb_err_ways);
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[bank] + DRP_ECC_ERROR_STATUS0, &sb_err_ways);
sb_err_ways = sb_err_ways & ECC_SB_ERR_WAYS_MASK;
edac_printk(KERN_CRIT, EDAC_LLCC, "Single-Bit error ways: 0x%4x\n",
@@ -246,24 +268,26 @@
static void dump_syn_reg(struct edac_device_ctl_info *edev_ctl,
- int err_type, struct regmap *llcc_map)
+ int err_type, u32 bank)
{
+ struct erp_drvdata *drv = edev_ctl->pvt_info;
+
switch (err_type) {
case LLCC_DRAM_CE:
- dump_drp_sb_syn_reg(llcc_map);
+ dump_drp_sb_syn_reg(drv, bank);
break;
case LLCC_DRAM_UE:
- dump_drp_db_syn_reg(llcc_map);
+ dump_drp_db_syn_reg(drv, bank);
break;
case LLCC_TRAM_CE:
- dump_trp_sb_syn_reg(llcc_map);
+ dump_trp_sb_syn_reg(drv, bank);
break;
case LLCC_TRAM_UE:
- dump_trp_db_syn_reg(llcc_map);
+ dump_trp_db_syn_reg(drv, bank);
break;
}
- qcom_llcc_clear_errors(err_type, llcc_map);
+ qcom_llcc_clear_errors(err_type, drv);
errors[err_type].func(edev_ctl, 0, 0, errors[err_type].msg);
}
@@ -274,30 +298,36 @@
u32 drp_error;
u32 trp_error;
struct erp_drvdata *drv = edev_ctl->pvt_info;
+ u32 i;
- /* Look for Data RAM errors */
- regmap_read(drv->llcc_map, DRP_INTERRUPT_STATUS, &drp_error);
+ for (i = 0; i < drv->num_banks; i++) {
+ /* Look for Data RAM errors */
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[i] + DRP_INTERRUPT_STATUS, &drp_error);
- if (drp_error & SB_ECC_ERROR) {
- edac_printk(KERN_CRIT, EDAC_LLCC,
- "Single Bit Error detected in Data Ram\n");
- dump_syn_reg(edev_ctl, LLCC_DRAM_CE, drv->llcc_map);
- } else if (drp_error & DB_ECC_ERROR) {
- edac_printk(KERN_CRIT, EDAC_LLCC,
- "Double Bit Error detected in Data Ram\n");
- dump_syn_reg(edev_ctl, LLCC_DRAM_UE, drv->llcc_map);
- }
+ if (drp_error & SB_ECC_ERROR) {
+ edac_printk(KERN_CRIT, EDAC_LLCC,
+ "Single Bit Error detected in Data Ram\n");
+ dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i);
+ } else if (drp_error & DB_ECC_ERROR) {
+ edac_printk(KERN_CRIT, EDAC_LLCC,
+ "Double Bit Error detected in Data Ram\n");
+ dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i);
+ }
- /* Look for Tag RAM errors */
- regmap_read(drv->llcc_map, TRP_INTERRUPT_0_STATUS, &trp_error);
- if (trp_error & SB_ECC_ERROR) {
- edac_printk(KERN_CRIT, EDAC_LLCC,
- "Single Bit Error detected in Tag Ram\n");
- dump_syn_reg(edev_ctl, LLCC_TRAM_CE, drv->llcc_map);
- } else if (trp_error & DB_ECC_ERROR) {
- edac_printk(KERN_CRIT, EDAC_LLCC,
- "Double Bit Error detected in Tag Ram\n");
- dump_syn_reg(edev_ctl, LLCC_TRAM_UE, drv->llcc_map);
+ /* Look for Tag RAM errors */
+ regmap_read(drv->llcc_map,
+ drv->llcc_banks[i] + TRP_INTERRUPT_0_STATUS,
+ &trp_error);
+ if (trp_error & SB_ECC_ERROR) {
+ edac_printk(KERN_CRIT, EDAC_LLCC,
+ "Single Bit Error detected in Tag Ram\n");
+ dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i);
+ } else if (trp_error & DB_ECC_ERROR) {
+ edac_printk(KERN_CRIT, EDAC_LLCC,
+ "Double Bit Error detected in Tag Ram\n");
+ dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i);
+ }
}
}
@@ -319,6 +349,8 @@
struct erp_drvdata *drv;
struct edac_device_ctl_info *edev_ctl;
struct device *dev = &pdev->dev;
+ u32 *banks;
+ u32 i;
/* Allocate edac control info */
edev_ctl = edac_device_alloc_ctl_info(sizeof(*drv), "qcom-llcc", 1,
@@ -358,6 +390,43 @@
}
}
+ /* Find the number of LLC banks supported */
+ regmap_read(drv->llcc_map, LLCC_COMMON_STATUS0,
+ &drv->num_banks);
+
+ drv->num_banks &= LLCC_LB_CNT_MASK;
+ drv->num_banks >>= LLCC_LB_CNT_SHIFT;
+
+ drv->llcc_banks = devm_kzalloc(&pdev->dev,
+ sizeof(phys_addr_t) * drv->num_banks, GFP_KERNEL);
+
+ if (!drv->num_banks) {
+ dev_err(dev, "Cannot allocate memory for llcc_banks\n");
+ return -ENOMEM;
+ }
+
+ banks = devm_kzalloc(&pdev->dev,
+ sizeof(u32) * drv->num_banks, GFP_KERNEL);
+ if (!banks)
+ return -ENOMEM;
+
+ rc = of_property_read_u32_array(dev->parent->of_node,
+ "qcom,llcc-banks-off", banks, drv->num_banks);
+ if (rc) {
+ dev_err(dev, "Cannot read llcc-banks-off property\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(dev->parent->of_node,
+ "qcom,llcc-broadcast-off", &drv->b_off);
+ if (rc) {
+ dev_err(dev, "Cannot read llcc-broadcast-off property\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < drv->num_banks; i++)
+ drv->llcc_banks[i] = banks[i];
+
platform_set_drvdata(pdev, edev_ctl);
rc = edac_device_add_device(edev_ctl);
diff --git a/drivers/esoc/esoc_dev.c b/drivers/esoc/esoc_dev.c
index 39090dc..0c9e428 100644
--- a/drivers/esoc/esoc_dev.c
+++ b/drivers/esoc/esoc_dev.c
@@ -215,7 +215,7 @@
esoc_clink->name);
return -EIO;
}
- put_user(req, (unsigned long __user *)uarg);
+ put_user(req, (unsigned int __user *)uarg);
}
return err;
@@ -227,7 +227,7 @@
err = clink_ops->get_status(&status, esoc_clink);
if (err)
return err;
- put_user(status, (unsigned long __user *)uarg);
+ put_user(status, (unsigned int __user *)uarg);
break;
case ESOC_WAIT_FOR_CRASH:
err = wait_event_interruptible(esoc_udev->evt_wait,
@@ -241,7 +241,7 @@
esoc_clink->name);
return -EIO;
}
- put_user(evt, (unsigned long __user *)uarg);
+ put_user(evt, (unsigned int __user *)uarg);
}
return err;
default:
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.c b/drivers/gpu/drm/msm/msm_drv.c
index 600b250..9d2e95b 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -1065,6 +1065,262 @@
return ret;
}
+static int msm_drm_object_supports_event(struct drm_device *dev,
+ struct drm_msm_event_req *req)
+{
+ int ret = -EINVAL;
+ struct drm_mode_object *arg_obj;
+
+ arg_obj = drm_mode_object_find(dev, req->object_id, req->object_type);
+ if (!arg_obj)
+ return -ENOENT;
+
+ switch (arg_obj->type) {
+ case DRM_MODE_OBJECT_CRTC:
+ case DRM_MODE_OBJECT_CONNECTOR:
+ ret = 0;
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+
+ return ret;
+}
+
+static int msm_register_event(struct drm_device *dev,
+ struct drm_msm_event_req *req, struct drm_file *file, bool en)
+{
+ int ret = -EINVAL;
+ struct msm_drm_private *priv = dev->dev_private;
+ struct msm_kms *kms = priv->kms;
+ struct drm_mode_object *arg_obj;
+
+ arg_obj = drm_mode_object_find(dev, req->object_id, req->object_type);
+ if (!arg_obj)
+ return -ENOENT;
+
+ ret = kms->funcs->register_events(kms, arg_obj, req->event, en);
+ return ret;
+}
+
+static int msm_event_client_count(struct drm_device *dev,
+ struct drm_msm_event_req *req_event, bool locked)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ unsigned long flag = 0;
+ struct msm_drm_event *node;
+ int count = 0;
+
+ if (!locked)
+ spin_lock_irqsave(&dev->event_lock, flag);
+ list_for_each_entry(node, &priv->client_event_list, base.link) {
+ if (node->event.type == req_event->event &&
+ node->info.object_id == req_event->object_id)
+ count++;
+ }
+ if (!locked)
+ spin_unlock_irqrestore(&dev->event_lock, flag);
+
+ return count;
+}
+
+static int msm_ioctl_register_event(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ struct drm_msm_event_req *req_event = data;
+ struct msm_drm_event *client, *node;
+ unsigned long flag = 0;
+ bool dup_request = false;
+ int ret = 0, count = 0;
+
+ ret = msm_drm_object_supports_event(dev, req_event);
+ if (ret) {
+ DRM_ERROR("unsupported event %x object %x object id %d\n",
+ req_event->event, req_event->object_type,
+ req_event->object_id);
+ return ret;
+ }
+
+ spin_lock_irqsave(&dev->event_lock, flag);
+ list_for_each_entry(node, &priv->client_event_list, base.link) {
+ if (node->base.file_priv != file)
+ continue;
+ if (node->event.type == req_event->event &&
+ node->info.object_id == req_event->object_id) {
+ DRM_DEBUG("duplicate request for event %x obj id %d\n",
+ node->event.type, node->info.object_id);
+ dup_request = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flag);
+
+ if (dup_request)
+ return -EALREADY;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
+
+ client->base.file_priv = file;
+ client->base.pid = current->pid;
+ client->base.event = &client->event;
+ client->event.type = req_event->event;
+ memcpy(&client->info, req_event, sizeof(client->info));
+
+ /* Get the count of clients that have registered for event.
+ * Event should be enabled for first client, for subsequent enable
+ * calls add to client list and return.
+ */
+ count = msm_event_client_count(dev, req_event, false);
+ /* Add current client to list */
+ spin_lock_irqsave(&dev->event_lock, flag);
+ list_add_tail(&client->base.link, &priv->client_event_list);
+ spin_unlock_irqrestore(&dev->event_lock, flag);
+
+ if (count)
+ return 0;
+
+ ret = msm_register_event(dev, req_event, file, true);
+ if (ret) {
+ DRM_ERROR("failed to enable event %x object %x object id %d\n",
+ req_event->event, req_event->object_type,
+ req_event->object_id);
+ spin_lock_irqsave(&dev->event_lock, flag);
+ list_del(&client->base.link);
+ spin_unlock_irqrestore(&dev->event_lock, flag);
+ kfree(client);
+ }
+ return ret;
+}
+
+static int msm_ioctl_deregister_event(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct msm_drm_private *priv = dev->dev_private;
+ struct drm_msm_event_req *req_event = data;
+ struct msm_drm_event *client = NULL, *node, *temp;
+ unsigned long flag = 0;
+ int count = 0;
+ bool found = false;
+ int ret = 0;
+
+ ret = msm_drm_object_supports_event(dev, req_event);
+ if (ret) {
+ DRM_ERROR("unsupported event %x object %x object id %d\n",
+ req_event->event, req_event->object_type,
+ req_event->object_id);
+ return ret;
+ }
+
+ spin_lock_irqsave(&dev->event_lock, flag);
+ list_for_each_entry_safe(node, temp, &priv->client_event_list,
+ base.link) {
+ if (node->event.type == req_event->event &&
+ node->info.object_id == req_event->object_id &&
+ node->base.file_priv == file) {
+ client = node;
+ list_del(&client->base.link);
+ found = true;
+ kfree(client);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flag);
+
+ if (!found)
+ return -ENOENT;
+
+ count = msm_event_client_count(dev, req_event, false);
+ if (!count)
+ ret = msm_register_event(dev, req_event, file, false);
+
+ return ret;
+}
+
+void msm_send_crtc_notification(struct drm_crtc *crtc,
+ struct drm_event *event, u8 *payload)
+{
+ struct drm_device *dev = NULL;
+ struct msm_drm_private *priv = NULL;
+ unsigned long flags;
+ struct msm_drm_event *notify, *node;
+ int len = 0, ret;
+
+ if (!crtc || !event || !event->length || !payload) {
+ DRM_ERROR("err param crtc %pK event %pK len %d payload %pK\n",
+ crtc, event, ((event) ? (event->length) : -1),
+ payload);
+ return;
+ }
+ dev = crtc->dev;
+ priv = (dev) ? dev->dev_private : NULL;
+ if (!dev || !priv) {
+ DRM_ERROR("invalid dev %pK priv %pK\n", dev, priv);
+ return;
+ }
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ list_for_each_entry(node, &priv->client_event_list, base.link) {
+ if (node->event.type != event->type ||
+ crtc->base.id != node->info.object_id)
+ continue;
+ len = event->length + sizeof(struct drm_msm_event_resp);
+ if (node->base.file_priv->event_space < len) {
+ DRM_ERROR("Insufficient space to notify\n");
+ continue;
+ }
+ notify = kzalloc(len, GFP_ATOMIC);
+ if (!notify)
+ continue;
+ notify->base.file_priv = node->base.file_priv;
+ notify->base.event = ¬ify->event;
+ notify->base.pid = node->base.pid;
+ notify->event.type = node->event.type;
+ notify->event.length = len;
+ memcpy(¬ify->info, &node->info, sizeof(notify->info));
+ memcpy(notify->data, payload, event->length);
+ ret = drm_event_reserve_init_locked(dev, node->base.file_priv,
+ ¬ify->base, ¬ify->event);
+ if (ret) {
+ kfree(notify);
+ continue;
+ }
+ drm_send_event_locked(dev, ¬ify->base);
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static int msm_release(struct inode *inode, struct file *filp)
+{
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_minor *minor = file_priv->minor;
+ struct drm_device *dev = minor->dev;
+ struct msm_drm_private *priv = dev->dev_private;
+ struct msm_drm_event *node, *temp;
+ u32 count;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ list_for_each_entry_safe(node, temp, &priv->client_event_list,
+ base.link) {
+ if (node->base.file_priv != file_priv)
+ continue;
+ list_del(&node->base.link);
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ count = msm_event_client_count(dev, &node->info, true);
+ if (!count)
+ msm_register_event(dev, &node->info, file_priv, false);
+ kfree(node);
+ spin_lock_irqsave(&dev->event_lock, flags);
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ return drm_release(inode, filp);
+}
+
static const struct drm_ioctl_desc msm_ioctls[] = {
DRM_IOCTL_DEF_DRV(MSM_GET_PARAM, msm_ioctl_get_param, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_GEM_NEW, msm_ioctl_gem_new, DRM_AUTH|DRM_RENDER_ALLOW),
@@ -1075,6 +1331,10 @@
DRM_IOCTL_DEF_DRV(MSM_WAIT_FENCE, msm_ioctl_wait_fence, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(MSM_GEM_MADVISE, msm_ioctl_gem_madvise, DRM_AUTH|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(SDE_WB_CONFIG, sde_wb_config, DRM_UNLOCKED|DRM_AUTH),
+ DRM_IOCTL_DEF_DRV(MSM_REGISTER_EVENT, msm_ioctl_register_event,
+ DRM_UNLOCKED|DRM_CONTROL_ALLOW),
+ DRM_IOCTL_DEF_DRV(MSM_DEREGISTER_EVENT, msm_ioctl_deregister_event,
+ DRM_UNLOCKED|DRM_CONTROL_ALLOW),
};
static const struct vm_operations_struct vm_ops = {
@@ -1086,7 +1346,7 @@
static const struct file_operations fops = {
.owner = THIS_MODULE,
.open = drm_open,
- .release = drm_release,
+ .release = msm_release,
.unlocked_ioctl = drm_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = drm_compat_ioctl,
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b51187d..f2fccd7 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
@@ -371,6 +374,7 @@
struct msm_drm_event {
struct drm_pending_event base;
struct drm_event event;
+ struct drm_msm_event_req info;
u8 data[];
};
@@ -620,6 +624,15 @@
MSM_DSI_CMD_ENCODER_ID = 1,
MSM_DSI_ENCODER_NUM = 2
};
+
+/* *
+ * msm_send_crtc_notification - notify user-space clients of crtc events.
+ * @crtc: crtc that is generating the event.
+ * @event: event that needs to be notified.
+ * @payload: payload for the event.
+ */
+void msm_send_crtc_notification(struct drm_crtc *crtc,
+ struct drm_event *event, u8 *payload);
#ifdef CONFIG_DRM_MSM_DSI
void __init msm_dsi_register(void);
void __exit msm_dsi_unregister(void);
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 4ebbc58..aa1b090 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -83,6 +83,8 @@
void (*preclose)(struct msm_kms *kms, struct drm_file *file);
void (*postclose)(struct msm_kms *kms, struct drm_file *file);
void (*lastclose)(struct msm_kms *kms);
+ int (*register_events)(struct msm_kms *kms,
+ struct drm_mode_object *obj, u32 event, bool en);
/* cleanup: */
void (*destroy)(struct msm_kms *kms);
};
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 9caadca..1f39180 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);
@@ -843,3 +846,9 @@
return ERR_PTR(rc);
}
+
+int sde_connector_register_custom_event(struct sde_kms *kms,
+ struct drm_connector *conn_drm, u32 event, bool val)
+{
+ return -EINVAL;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 0ece0d2..9d36851 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -392,5 +392,16 @@
void sde_connector_unregister_event(struct drm_connector *connector,
uint32_t event_idx);
+/**
+ * sde_connector_register_custom_event - register for async events
+ * @kms: Pointer to sde_kms
+ * @conn_drm: Pointer to drm connector object
+ * @event: Event for which request is being sent
+ * @en: Flag to enable/disable the event
+ * Returns: Zero on success
+ */
+int sde_connector_register_custom_event(struct sde_kms *kms,
+ struct drm_connector *conn_drm, u32 event, bool en);
+
#endif /* _SDE_CONNECTOR_H_ */
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..acb5695 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -37,6 +37,14 @@
#include "sde_power_handle.h"
#include "sde_core_perf.h"
+struct sde_crtc_irq_info {
+ struct sde_irq_callback irq;
+ u32 event;
+ int (*func)(struct drm_crtc *crtc, bool en,
+ struct sde_irq_callback *irq);
+ struct list_head list;
+};
+
/* default input fence timeout, in ms */
#define SDE_CRTC_INPUT_FENCE_TIMEOUT 2000
@@ -51,6 +59,8 @@
#define LEFT_MIXER 0
#define RIGHT_MIXER 1
+#define MISR_BUFF_SIZE 256
+
static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc)
{
struct msm_drm_private *priv;
@@ -68,6 +78,35 @@
return to_sde_kms(priv->kms);
}
+static inline int _sde_crtc_power_enable(struct sde_crtc *sde_crtc, bool enable)
+{
+ struct drm_crtc *crtc;
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
+
+ if (!sde_crtc) {
+ SDE_ERROR("invalid sde crtc\n");
+ return -EINVAL;
+ }
+
+ crtc = &sde_crtc->base;
+ if (!crtc->dev || !crtc->dev->dev_private) {
+ SDE_ERROR("invalid drm device\n");
+ return -EINVAL;
+ }
+
+ priv = crtc->dev->dev_private;
+ if (!priv->kms) {
+ SDE_ERROR("invalid kms\n");
+ return -EINVAL;
+ }
+
+ sde_kms = to_sde_kms(priv->kms);
+
+ return sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
+ enable);
+}
+
static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc)
{
if (!sde_crtc)
@@ -467,12 +506,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 +547,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;
@@ -1086,8 +1135,6 @@
struct drm_device *dev;
struct drm_crtc *crtc;
struct drm_encoder *enc;
- struct msm_drm_private *priv;
- struct sde_kms *sde_kms;
if (!sde_crtc) {
SDE_ERROR("invalid crtc\n");
@@ -1096,17 +1143,11 @@
crtc = &sde_crtc->base;
dev = crtc->dev;
- priv = dev->dev_private;
-
- if (!priv->kms) {
- SDE_ERROR("invalid kms\n");
- return;
- }
- sde_kms = to_sde_kms(priv->kms);
if (enable) {
- sde_power_resource_enable(&priv->phandle,
- sde_kms->core_client, true);
+ if (_sde_crtc_power_enable(sde_crtc, true))
+ return;
+
list_for_each_entry(enc, &dev->mode_config.encoder_list, head) {
if (enc->crtc != crtc)
continue;
@@ -1125,8 +1166,7 @@
sde_encoder_register_vblank_callback(enc, NULL, NULL);
}
- sde_power_resource_enable(&priv->phandle,
- sde_kms->core_client, false);
+ _sde_crtc_power_enable(sde_crtc, false);
}
}
@@ -1263,6 +1303,9 @@
struct sde_crtc *sde_crtc;
struct sde_crtc_state *cstate;
struct drm_encoder *encoder;
+ unsigned long flags;
+ struct sde_crtc_irq_info *node = NULL;
+ int ret;
if (!crtc || !crtc->dev || !crtc->state) {
SDE_ERROR("invalid crtc\n");
@@ -1314,6 +1357,18 @@
memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
sde_crtc->num_mixers = 0;
+
+ spin_lock_irqsave(&sde_crtc->spin_lock, flags);
+ list_for_each_entry(node, &sde_crtc->user_event_list, list) {
+ ret = 0;
+ if (node->func)
+ ret = node->func(crtc, false, &node->irq);
+ if (ret)
+ SDE_ERROR("%s failed to disable event %x\n",
+ sde_crtc->name, node->event);
+ }
+ spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
+
mutex_unlock(&sde_crtc->crtc_lock);
}
@@ -1324,7 +1379,9 @@
struct sde_hw_mixer *lm;
struct drm_display_mode *mode;
struct drm_encoder *encoder;
- int i;
+ unsigned long flags;
+ struct sde_crtc_irq_info *node = NULL;
+ int i, ret;
if (!crtc) {
SDE_ERROR("invalid crtc\n");
@@ -1359,6 +1416,17 @@
lm->cfg.flags = 0;
lm->ops.setup_mixer_out(lm, &lm->cfg);
}
+
+ spin_lock_irqsave(&sde_crtc->spin_lock, flags);
+ list_for_each_entry(node, &sde_crtc->user_event_list, list) {
+ ret = 0;
+ if (node->func)
+ ret = node->func(crtc, true, &node->irq);
+ if (ret)
+ SDE_ERROR("%s failed to enable event %x\n",
+ sde_crtc->name, node->event);
+ }
+ spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
}
struct plane_state {
@@ -1723,9 +1791,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);
@@ -2001,7 +2081,108 @@
return single_open(file, _sde_debugfs_status_show, inode->i_private);
}
-#define DEFINE_SDE_DEBUGFS_SEQ_FOPS(__prefix) \
+static ssize_t _sde_crtc_misr_setup(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_mixer *m;
+ int i = 0, rc;
+ char buf[MISR_BUFF_SIZE + 1];
+ u32 frame_count, enable;
+ size_t buff_copy;
+
+ if (!file || !file->private_data)
+ return -EINVAL;
+
+ sde_crtc = file->private_data;
+ buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
+ if (copy_from_user(buf, user_buf, buff_copy)) {
+ SDE_ERROR("buffer copy failed\n");
+ return -EINVAL;
+ }
+
+ buf[buff_copy] = 0; /* end of string */
+
+ if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
+ return -EINVAL;
+
+ rc = _sde_crtc_power_enable(sde_crtc, true);
+ if (rc)
+ return rc;
+
+ mutex_lock(&sde_crtc->crtc_lock);
+ sde_crtc->misr_enable = enable;
+ for (i = 0; i < sde_crtc->num_mixers; ++i) {
+ m = &sde_crtc->mixers[i];
+ if (!m->hw_lm)
+ continue;
+
+ m->hw_lm->ops.setup_misr(m->hw_lm, enable, frame_count);
+ }
+ mutex_unlock(&sde_crtc->crtc_lock);
+ _sde_crtc_power_enable(sde_crtc, false);
+
+ return count;
+}
+
+static ssize_t _sde_crtc_misr_read(struct file *file,
+ char __user *user_buff, size_t count, loff_t *ppos)
+{
+ struct sde_crtc *sde_crtc;
+ struct sde_crtc_mixer *m;
+ int i = 0, rc;
+ ssize_t len = 0;
+ char buf[MISR_BUFF_SIZE + 1] = {'\0'};
+
+ if (*ppos)
+ return 0;
+
+ if (!file || !file->private_data)
+ return -EINVAL;
+
+ sde_crtc = file->private_data;
+ rc = _sde_crtc_power_enable(sde_crtc, true);
+ if (rc)
+ return rc;
+
+ mutex_lock(&sde_crtc->crtc_lock);
+ if (!sde_crtc->misr_enable) {
+ len += snprintf(buf + len, MISR_BUFF_SIZE - len,
+ "disabled\n");
+ goto buff_check;
+ }
+
+ for (i = 0; i < sde_crtc->num_mixers; ++i) {
+ m = &sde_crtc->mixers[i];
+ if (!m->hw_lm)
+ continue;
+
+ len += snprintf(buf + len, MISR_BUFF_SIZE - len, "lm idx:%d\n",
+ m->hw_lm->idx - LM_0);
+ len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
+ m->hw_lm->ops.collect_misr(m->hw_lm));
+ }
+
+buff_check:
+ if (count <= len) {
+ len = 0;
+ goto end;
+ }
+
+ if (copy_to_user(user_buff, buf, len)) {
+ len = -EFAULT;
+ goto end;
+ }
+
+ *ppos += len; /* increase offset */
+
+end:
+ mutex_unlock(&sde_crtc->crtc_lock);
+ _sde_crtc_power_enable(sde_crtc, false);
+ return len;
+}
+
+#define DEFINE_SDE_DEBUGFS_SEQ_FOPS(__prefix) \
static int __prefix ## _open(struct inode *inode, struct file *file) \
{ \
return single_open(file, __prefix ## _show, inode->i_private); \
@@ -2021,7 +2202,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",
@@ -2042,6 +2223,11 @@
.llseek = seq_lseek,
.release = single_release,
};
+ static const struct file_operations debugfs_misr_fops = {
+ .open = simple_open,
+ .read = _sde_crtc_misr_read,
+ .write = _sde_crtc_misr_setup,
+ };
if (!crtc)
return -EINVAL;
@@ -2064,6 +2250,8 @@
sde_crtc->debugfs_root,
&sde_crtc->base,
&sde_crtc_debugfs_state_fops);
+ debugfs_create_file("misr_data", 0644, sde_crtc->debugfs_root,
+ sde_crtc, &debugfs_misr_fops);
return 0;
}
@@ -2241,6 +2429,7 @@
atomic_set(&sde_crtc->frame_pending, 0);
INIT_LIST_HEAD(&sde_crtc->frame_event_list);
+ INIT_LIST_HEAD(&sde_crtc->user_event_list);
for (i = 0; i < ARRAY_SIZE(sde_crtc->frame_events); i++) {
INIT_LIST_HEAD(&sde_crtc->frame_events[i].list);
list_add(&sde_crtc->frame_events[i].list,
@@ -2284,3 +2473,9 @@
SDE_DEBUG("%s: successfully initialized crtc\n", sde_crtc->name);
return crtc;
}
+
+int sde_crtc_register_custom_event(struct sde_kms *kms,
+ struct drm_crtc *crtc_drm, u32 event, bool val)
+{
+ return -EINVAL;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index f389196..5934405 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -136,6 +136,7 @@
* @event_cache : Local cache of event worker structures
* @event_free_list : List of available event structures
* @event_lock : Spinlock around event handling code
+ * @misr_enable : boolean entry indicates misr enable/disable status.
*/
struct sde_crtc {
struct drm_crtc base;
@@ -169,6 +170,7 @@
struct list_head dirty_list;
struct list_head ad_dirty;
struct list_head ad_active;
+ struct list_head user_event_list;
struct mutex crtc_lock;
@@ -183,6 +185,7 @@
struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT];
struct list_head event_free_list;
spinlock_t event_lock;
+ bool misr_enable;
};
#define to_sde_crtc(x) container_of(x, struct sde_crtc, base)
@@ -316,16 +319,20 @@
void sde_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
/**
+ * sde_crtc_register_custom_event - api for enabling/disabling crtc event
+ * @kms: Pointer to sde_kms
+ * @crtc_drm: Pointer to crtc object
+ * @event: Event that client is interested
+ * @en: Flag to enable/disable the event
+ */
+int sde_crtc_register_custom_event(struct sde_kms *kms,
+ struct drm_crtc *crtc_drm, u32 event, bool en);
+
+/**
* sde_crtc_get_intf_mode - get 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..7ab4f8d 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"
@@ -57,6 +57,8 @@
#define MAX_CHANNELS_PER_ENC 2
+#define MISR_BUFF_SIZE 256
+
/**
* struct sde_encoder_virt - virtual encoder. Container of one or more physical
* encoders. Virtual encoder manages one "logical" display. Physical
@@ -90,6 +92,7 @@
* @crtc_frame_event: callback event
* @frame_done_timeout: frame done timeout in Hz
* @frame_done_timer: watchdog timer for frame done event
+ * @misr_enable: misr enable/disable status
*/
struct sde_encoder_virt {
struct drm_encoder base;
@@ -120,6 +123,7 @@
struct sde_rsc_client *rsc_client;
struct msm_display_info disp_info;
bool rsc_state_update;
+ bool misr_enable;
};
#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
@@ -131,6 +135,36 @@
return (comp_info->comp_type == MSM_DISPLAY_COMPRESSION_DSC);
}
+static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc,
+ bool enable)
+{
+ struct drm_encoder *drm_enc;
+ struct msm_drm_private *priv;
+ struct sde_kms *sde_kms;
+
+ if (!sde_enc) {
+ SDE_ERROR("invalid sde enc\n");
+ return -EINVAL;
+ }
+
+ drm_enc = &sde_enc->base;
+ if (!drm_enc->dev || !drm_enc->dev->dev_private) {
+ SDE_ERROR("drm device invalid\n");
+ return -EINVAL;
+ }
+
+ priv = drm_enc->dev->dev_private;
+ if (!priv->kms) {
+ SDE_ERROR("invalid kms\n");
+ return -EINVAL;
+ }
+
+ sde_kms = to_sde_kms(priv->kms);
+
+ return sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
+ enable);
+}
+
void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
struct sde_encoder_hw_resources *hw_res,
struct drm_connector_state *conn_state)
@@ -706,8 +740,6 @@
static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
{
struct sde_encoder_virt *sde_enc = NULL;
- struct msm_drm_private *priv;
- struct sde_kms *sde_kms;
int i = 0;
int ret = 0;
@@ -723,13 +755,13 @@
}
sde_enc = to_sde_encoder_virt(drm_enc);
- priv = drm_enc->dev->dev_private;
- sde_kms = to_sde_kms(priv->kms);
SDE_DEBUG_ENC(sde_enc, "\n");
SDE_EVT32(DRMID(drm_enc));
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true);
+ ret = _sde_encoder_power_enable(sde_enc, true);
+ if (ret)
+ return;
sde_enc->cur_master = NULL;
@@ -810,7 +842,7 @@
sde_rm_release(&sde_kms->rm, drm_enc);
- sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
+ _sde_encoder_power_enable(sde_enc, false);
}
static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
@@ -1389,105 +1421,108 @@
return single_open(file, _sde_encoder_status_show, inode->i_private);
}
-static void _sde_set_misr_params(struct sde_encoder_phys *phys, u32 enable,
- u32 frame_count)
-{
- int j;
-
- if (!phys->misr_map)
- return;
-
- phys->misr_map->enable = enable;
-
- if (frame_count <= SDE_CRC_BATCH_SIZE)
- phys->misr_map->frame_count = frame_count;
- else if (frame_count <= 0)
- phys->misr_map->frame_count = 0;
- else
- phys->misr_map->frame_count = SDE_CRC_BATCH_SIZE;
-
- if (!enable) {
- phys->misr_map->last_idx = 0;
- phys->misr_map->frame_count = 0;
- for (j = 0; j < SDE_CRC_BATCH_SIZE; j++)
- phys->misr_map->crc_value[j] = 0;
- }
-}
-
-static ssize_t _sde_encoder_misr_set(struct file *file,
+static ssize_t _sde_encoder_misr_setup(struct file *file,
const char __user *user_buf, size_t count, loff_t *ppos)
{
struct sde_encoder_virt *sde_enc;
- struct drm_encoder *drm_enc;
- int i = 0;
- char buf[10];
- u32 enable, frame_count;
+ int i = 0, rc;
+ char buf[MISR_BUFF_SIZE + 1];
+ size_t buff_copy;
+ u32 frame_count, enable;
- drm_enc = file->private_data;
- sde_enc = to_sde_encoder_virt(drm_enc);
+ if (!file || !file->private_data)
+ return -EINVAL;
- if (copy_from_user(buf, user_buf, count))
- return -EFAULT;
+ sde_enc = file->private_data;
- buf[count] = 0; /* end of string */
+ buff_copy = min_t(size_t, count, MISR_BUFF_SIZE);
+ if (copy_from_user(buf, user_buf, buff_copy))
+ return -EINVAL;
+
+ buf[buff_copy] = 0; /* end of string */
if (sscanf(buf, "%u %u", &enable, &frame_count) != 2)
- return -EFAULT;
+ return -EINVAL;
+
+ rc = _sde_encoder_power_enable(sde_enc, true);
+ if (rc)
+ return rc;
mutex_lock(&sde_enc->enc_lock);
+ sde_enc->misr_enable = enable;
for (i = 0; i < sde_enc->num_phys_encs; i++) {
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- if (!phys || !phys->misr_map || !phys->ops.setup_misr)
+ if (!phys || !phys->ops.setup_misr)
continue;
- _sde_set_misr_params(phys, enable, frame_count);
- phys->ops.setup_misr(phys, phys->misr_map);
+ phys->ops.setup_misr(phys, enable, frame_count);
}
mutex_unlock(&sde_enc->enc_lock);
+ _sde_encoder_power_enable(sde_enc, false);
+
return count;
}
-static ssize_t _sde_encoder_misr_read(
- struct file *file,
- char __user *buff, size_t count, loff_t *ppos)
+static ssize_t _sde_encoder_misr_read(struct file *file,
+ char __user *user_buff, size_t count, loff_t *ppos)
{
struct sde_encoder_virt *sde_enc;
- struct drm_encoder *drm_enc;
- int i = 0, j = 0, len = 0;
- char buf[512] = {'\0'};
+ int i = 0, len = 0;
+ char buf[MISR_BUFF_SIZE + 1] = {'\0'};
+ int rc;
if (*ppos)
return 0;
- drm_enc = file->private_data;
- sde_enc = to_sde_encoder_virt(drm_enc);
+ if (!file || !file->private_data)
+ return -EINVAL;
+
+ sde_enc = file->private_data;
+
+ rc = _sde_encoder_power_enable(sde_enc, true);
+ if (rc)
+ return rc;
mutex_lock(&sde_enc->enc_lock);
- for (i = 0; i < sde_enc->num_phys_encs; i++) {
- struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
- struct sde_misr_params *misr_map;
-
- if (!phys || !phys->misr_map)
- continue;
-
- misr_map = phys->misr_map;
-
- len += snprintf(buf+len, sizeof(buf), "INTF%d\n", i);
- for (j = 0; j < SDE_CRC_BATCH_SIZE; j++)
- len += snprintf(buf+len, sizeof(buf), "%x\n",
- misr_map->crc_value[j]);
+ if (!sde_enc->misr_enable) {
+ len += snprintf(buf + len, MISR_BUFF_SIZE - len,
+ "disabled\n");
+ goto buff_check;
+ } else if (sde_enc->disp_info.capabilities &
+ ~MSM_DISPLAY_CAP_VID_MODE) {
+ len += snprintf(buf + len, MISR_BUFF_SIZE - len,
+ "unsupported\n");
+ goto buff_check;
}
- if (len < 0 || len >= sizeof(buf))
- return 0;
+ for (i = 0; i < sde_enc->num_phys_encs; i++) {
+ struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
+ if (!phys || !phys->ops.collect_misr)
+ continue;
- if ((count < sizeof(buf)) || copy_to_user(buff, buf, len))
- return -EFAULT;
+ len += snprintf(buf + len, MISR_BUFF_SIZE - len,
+ "Intf idx:%d\n", phys->intf_idx - INTF_0);
+ len += snprintf(buf + len, MISR_BUFF_SIZE - len, "0x%x\n",
+ phys->ops.collect_misr(phys));
+ }
+
+buff_check:
+ if (count <= len) {
+ len = 0;
+ goto end;
+ }
+
+ if (copy_to_user(user_buff, buf, len)) {
+ len = -EFAULT;
+ goto end;
+ }
*ppos += len; /* increase offset */
- mutex_unlock(&sde_enc->enc_lock);
+end:
+ mutex_unlock(&sde_enc->enc_lock);
+ _sde_encoder_power_enable(sde_enc, false);
return len;
}
@@ -1507,7 +1542,7 @@
static const struct file_operations debugfs_misr_fops = {
.open = simple_open,
.read = _sde_encoder_misr_read,
- .write = _sde_encoder_misr_set,
+ .write = _sde_encoder_misr_setup,
};
char name[SDE_NAME_SIZE];
@@ -1534,7 +1569,7 @@
sde_enc->debugfs_root, sde_enc, &debugfs_status_fops);
debugfs_create_file("misr_data", 0644,
- sde_enc->debugfs_root, drm_enc, &debugfs_misr_fops);
+ sde_enc->debugfs_root, sde_enc, &debugfs_misr_fops);
return 0;
}
@@ -1857,7 +1892,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;
}
@@ -1896,10 +1931,6 @@
if (ret)
return ret;
}
-
- if (phys && phys->ops.collect_misr)
- if (phys->misr_map && phys->misr_map->enable)
- phys->ops.collect_misr(phys, phys->misr_map);
}
return ret;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 7aa9a29..da155b0 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) */
@@ -148,9 +147,8 @@
bool (*needs_single_flush)(struct sde_encoder_phys *phys_enc);
void (*setup_misr)(struct sde_encoder_phys *phys_encs,
- struct sde_misr_params *misr_map);
- void (*collect_misr)(struct sde_encoder_phys *phys_enc,
- struct sde_misr_params *misr_map);
+ bool enable, u32 frame_count);
+ u32 (*collect_misr)(struct sde_encoder_phys *phys_enc);
void (*hw_reset)(struct sde_encoder_phys *phys_enc);
};
@@ -184,7 +182,6 @@
* @hw_pp: Hardware interface to the ping pong registers
* @sde_kms: Pointer to the sde_kms top level
* @cached_mode: DRM mode cached at mode_set time, acted on in enable
- * @misr_map: Interface for setting and collecting MISR data
* @enabled: Whether the encoder has enabled and running a mode
* @split_role: Role to play in a split-panel configuration
* @intf_mode: Interface mode
@@ -213,7 +210,6 @@
struct sde_hw_pingpong *hw_pp;
struct sde_kms *sde_kms;
struct drm_display_mode cached_mode;
- struct sde_misr_params *misr_map;
enum sde_enc_split_role split_role;
enum sde_intf_mode intf_mode;
enum sde_intf intf_idx;
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 82d32dc..39dfd5d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -830,23 +830,29 @@
}
static void sde_encoder_phys_vid_setup_misr(struct sde_encoder_phys *phys_enc,
- struct sde_misr_params *misr_map)
+ bool enable, u32 frame_count)
{
- struct sde_encoder_phys_vid *vid_enc =
- to_sde_encoder_phys_vid(phys_enc);
+ struct sde_encoder_phys_vid *vid_enc;
- if (vid_enc && vid_enc->hw_intf && vid_enc->hw_intf->ops.setup_misr)
- vid_enc->hw_intf->ops.setup_misr(vid_enc->hw_intf, misr_map);
+ if (!phys_enc)
+ return;
+ vid_enc = to_sde_encoder_phys_vid(phys_enc);
+
+ if (vid_enc->hw_intf && vid_enc->hw_intf->ops.setup_misr)
+ vid_enc->hw_intf->ops.setup_misr(vid_enc->hw_intf,
+ enable, frame_count);
}
-static void sde_encoder_phys_vid_collect_misr(struct sde_encoder_phys *phys_enc,
- struct sde_misr_params *misr_map)
+static u32 sde_encoder_phys_vid_collect_misr(struct sde_encoder_phys *phys_enc)
{
- struct sde_encoder_phys_vid *vid_enc =
- to_sde_encoder_phys_vid(phys_enc);
+ struct sde_encoder_phys_vid *vid_enc;
- if (vid_enc && vid_enc->hw_intf && vid_enc->hw_intf->ops.collect_misr)
- vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf, misr_map);
+ if (!phys_enc)
+ return 0;
+ vid_enc = to_sde_encoder_phys_vid(phys_enc);
+
+ return vid_enc->hw_intf && vid_enc->hw_intf->ops.collect_misr ?
+ vid_enc->hw_intf->ops.collect_misr(vid_enc->hw_intf) : 0;
}
static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops)
@@ -919,13 +925,6 @@
goto fail;
}
- phys_enc->misr_map = kzalloc(sizeof(struct sde_misr_params),
- GFP_KERNEL);
- if (!phys_enc->misr_map) {
- ret = -ENOMEM;
- goto fail;
- }
-
SDE_DEBUG_VIDENC(vid_enc, "\n");
sde_encoder_phys_vid_init_ops(&phys_enc->ops);
diff --git a/drivers/gpu/drm/msm/sde/sde_formats.c b/drivers/gpu/drm/msm/sde/sde_formats.c
index 00b6c85..01d0d20 100644
--- a/drivers/gpu/drm/msm/sde/sde_formats.c
+++ b/drivers/gpu/drm/msm/sde/sde_formats.c
@@ -134,217 +134,217 @@
static const struct sde_format sde_format_map[] = {
INTERLEAVED_RGB_FMT(ARGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XBGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRA8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRX8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBX8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
false, 4, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGB888,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
false, 3, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGR888,
0, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 3, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGB565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, 0, 3,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ARGB1555,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR1555,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA5551,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRA5551,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB1555,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XBGR1555,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBX5551,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRX5551,
COLOR_ALPHA_1BIT, COLOR_5BIT, COLOR_5BIT, COLOR_5BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ARGB4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRA4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XBGR4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBX4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRX4444,
COLOR_ALPHA_4BIT, COLOR_4BIT, COLOR_4BIT, COLOR_4BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 2, 0,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRA1010102,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBA1010102,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ABGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(ARGB2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XRGB2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
+ C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
false, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(BGRX1010102,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C1_B_Cb, C0_G_Y, C2_R_Cr, C3_ALPHA, 4,
+ C3_ALPHA, C2_R_Cr, C0_G_Y, C1_B_Cb, 4,
false, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(XBGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
+ C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
INTERLEAVED_RGB_FMT(RGBX1010102,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
- C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
+ C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr, 4,
false, 4, SDE_FORMAT_FLAG_DX,
SDE_FETCH_LINEAR, 1),
@@ -492,31 +492,31 @@
* the data will be passed by user-space.
*/
static const struct sde_format sde_format_map_ubwc[] = {
- INTERLEAVED_RGB_FMT(RGB565,
+ INTERLEAVED_RGB_FMT(BGR565,
0, COLOR_5BIT, COLOR_6BIT, COLOR_5BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, 0, 3,
false, 2, SDE_FORMAT_FLAG_COMPRESSED,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBA8888,
+ INTERLEAVED_RGB_FMT(ABGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_COMPRESSED,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBX8888,
+ INTERLEAVED_RGB_FMT(XBGR8888,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
false, 4, SDE_FORMAT_FLAG_COMPRESSED,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBA1010102,
+ INTERLEAVED_RGB_FMT(ABGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
SDE_FETCH_UBWC, 2),
- INTERLEAVED_RGB_FMT(RGBX1010102,
+ INTERLEAVED_RGB_FMT(XBGR2101010,
COLOR_8BIT, COLOR_8BIT, COLOR_8BIT, COLOR_8BIT,
C2_R_Cr, C0_G_Y, C1_B_Cb, C3_ALPHA, 4,
true, 4, SDE_FORMAT_FLAG_DX | SDE_FORMAT_FLAG_COMPRESSED,
@@ -590,11 +590,11 @@
static int _sde_format_get_media_color_ubwc(const struct sde_format *fmt)
{
static const struct sde_media_color_map sde_media_ubwc_map[] = {
- {DRM_FORMAT_RGBA8888, COLOR_FMT_RGBA8888_UBWC},
- {DRM_FORMAT_RGBX8888, COLOR_FMT_RGBA8888_UBWC},
- {DRM_FORMAT_RGBA1010102, COLOR_FMT_RGBA1010102_UBWC},
- {DRM_FORMAT_RGBX1010102, COLOR_FMT_RGBA1010102_UBWC},
- {DRM_FORMAT_RGB565, COLOR_FMT_RGB565_UBWC},
+ {DRM_FORMAT_ABGR8888, COLOR_FMT_RGBA8888_UBWC},
+ {DRM_FORMAT_XBGR8888, COLOR_FMT_RGBA8888_UBWC},
+ {DRM_FORMAT_ABGR2101010, COLOR_FMT_RGBA1010102_UBWC},
+ {DRM_FORMAT_XBGR2101010, COLOR_FMT_RGBA1010102_UBWC},
+ {DRM_FORMAT_BGR565, COLOR_FMT_RGB565_UBWC},
};
int color_fmt = -1;
int i;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h
index 354b892..cdb3450 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog_format.h
@@ -16,17 +16,17 @@
{DRM_FORMAT_ARGB8888, 0},
{DRM_FORMAT_ABGR8888, 0},
{DRM_FORMAT_RGBA8888, 0},
- {DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_BGRA8888, 0},
{DRM_FORMAT_XRGB8888, 0},
{DRM_FORMAT_RGBX8888, 0},
{DRM_FORMAT_BGRX8888, 0},
{DRM_FORMAT_XBGR8888, 0},
- {DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_RGB888, 0},
{DRM_FORMAT_BGR888, 0},
{DRM_FORMAT_RGB565, 0},
- {DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_BGR565, 0},
{DRM_FORMAT_ARGB1555, 0},
{DRM_FORMAT_ABGR1555, 0},
@@ -52,16 +52,16 @@
{DRM_FORMAT_ABGR8888, 0},
{DRM_FORMAT_RGBA8888, 0},
{DRM_FORMAT_BGRX8888, 0},
- {DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_BGRA8888, 0},
{DRM_FORMAT_XRGB8888, 0},
{DRM_FORMAT_XBGR8888, 0},
{DRM_FORMAT_RGBX8888, 0},
- {DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_RGB888, 0},
{DRM_FORMAT_BGR888, 0},
{DRM_FORMAT_RGB565, 0},
- {DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_BGR565, 0},
{DRM_FORMAT_ARGB1555, 0},
{DRM_FORMAT_ABGR1555, 0},
@@ -113,14 +113,14 @@
static const struct sde_format_extended wb2_formats[] = {
{DRM_FORMAT_RGB565, 0},
- {DRM_FORMAT_RGB565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_BGR565, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_RGB888, 0},
{DRM_FORMAT_ARGB8888, 0},
{DRM_FORMAT_RGBA8888, 0},
- {DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_ABGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_XRGB8888, 0},
{DRM_FORMAT_RGBX8888, 0},
- {DRM_FORMAT_RGBX8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
+ {DRM_FORMAT_XBGR8888, DRM_FORMAT_MOD_QCOM_COMPRESSED},
{DRM_FORMAT_ARGB1555, 0},
{DRM_FORMAT_RGBA5551, 0},
{DRM_FORMAT_XRGB1555, 0},
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.c b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
index d96e49a..1f17378 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.c
@@ -67,12 +67,6 @@
#define INTF_MISR_CTRL 0x180
#define INTF_MISR_SIGNATURE 0x184
-#define MISR_FRAME_COUNT_MASK 0xFF
-#define MISR_CTRL_ENABLE BIT(8)
-#define MISR_CTRL_STATUS BIT(9)
-#define MISR_CTRL_STATUS_CLEAR BIT(10)
-#define INTF_MISR_CTRL_FREE_RUN_MASK BIT(31)
-
static struct sde_intf_cfg *_intf_offset(enum sde_intf intf,
struct sde_mdss_cfg *m,
void __iomem *addr,
@@ -270,48 +264,28 @@
}
}
-static void sde_hw_intf_set_misr(struct sde_hw_intf *intf,
- struct sde_misr_params *misr_map)
+static void sde_hw_intf_setup_misr(struct sde_hw_intf *intf,
+ bool enable, u32 frame_count)
{
struct sde_hw_blk_reg_map *c = &intf->hw;
u32 config = 0;
- if (!misr_map)
- return;
-
SDE_REG_WRITE(c, INTF_MISR_CTRL, MISR_CTRL_STATUS_CLEAR);
- /* Clear data */
+ /* clear misr data */
wmb();
- if (misr_map->enable) {
- config = (MISR_FRAME_COUNT_MASK & 1) |
- (MISR_CTRL_ENABLE);
+ if (enable)
+ config = (frame_count & MISR_FRAME_COUNT_MASK) |
+ MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK;
- SDE_REG_WRITE(c, INTF_MISR_CTRL, config);
- } else {
- SDE_REG_WRITE(c, INTF_MISR_CTRL, 0);
- }
+ SDE_REG_WRITE(c, INTF_MISR_CTRL, config);
}
-static void sde_hw_intf_collect_misr(struct sde_hw_intf *intf,
- struct sde_misr_params *misr_map)
+static u32 sde_hw_intf_collect_misr(struct sde_hw_intf *intf)
{
struct sde_hw_blk_reg_map *c = &intf->hw;
- if (!misr_map)
- return;
-
- if (misr_map->enable) {
- if (misr_map->last_idx < misr_map->frame_count &&
- misr_map->last_idx < SDE_CRC_BATCH_SIZE)
- misr_map->crc_value[misr_map->last_idx] =
- SDE_REG_READ(c, INTF_MISR_SIGNATURE);
- }
-
- misr_map->enable =
- misr_map->enable & (misr_map->last_idx <= SDE_CRC_BATCH_SIZE);
-
- misr_map->last_idx++;
+ return SDE_REG_READ(c, INTF_MISR_SIGNATURE);
}
static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
@@ -321,7 +295,7 @@
ops->setup_prg_fetch = sde_hw_intf_setup_prg_fetch;
ops->get_status = sde_hw_intf_get_status;
ops->enable_timing = sde_hw_intf_enable_timing_engine;
- ops->setup_misr = sde_hw_intf_set_misr;
+ ops->setup_misr = sde_hw_intf_setup_misr;
ops->collect_misr = sde_hw_intf_collect_misr;
if (cap & BIT(SDE_INTF_ROT_START))
ops->setup_rot_start = sde_hw_intf_setup_rot_start;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_intf.h b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
index c6428ca..d24e83a 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_intf.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_intf.h
@@ -19,24 +19,6 @@
struct sde_hw_intf;
-/* Batch size of frames for collecting MISR data */
-#define SDE_CRC_BATCH_SIZE 16
-
-/**
- * struct sde_misr_params : Interface for getting and setting MISR data
- * Assumption is these functions will be called after clocks are enabled
- * @ enable : enables/disables MISR
- * @ frame_count : represents number of frames for which MISR is enabled
- * @ last_idx: number of frames for which MISR data is collected
- * @ crc_value: stores the collected MISR data
- */
-struct sde_misr_params {
- bool enable;
- u32 frame_count;
- u32 last_idx;
- u32 crc_value[SDE_CRC_BATCH_SIZE];
-};
-
/* intf timing settings */
struct intf_timing_params {
u32 width; /* active width */
@@ -98,10 +80,9 @@
struct intf_status *status);
void (*setup_misr)(struct sde_hw_intf *intf,
- struct sde_misr_params *misr_map);
+ bool enable, u32 frame_count);
- void (*collect_misr)(struct sde_hw_intf *intf,
- struct sde_misr_params *misr_map);
+ u32 (*collect_misr)(struct sde_hw_intf *intf);
};
struct sde_hw_intf {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 520c7b1..7780c5b 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -33,6 +33,9 @@
#define LM_BLEND0_FG_ALPHA 0x04
#define LM_BLEND0_BG_ALPHA 0x08
+#define LM_MISR_CTRL 0x310
+#define LM_MISR_SIGNATURE 0x314
+
static struct sde_lm_cfg *_lm_offset(enum sde_lm mixer,
struct sde_mdss_cfg *m,
void __iomem *addr,
@@ -224,6 +227,30 @@
SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, val);
}
+static void sde_hw_lm_setup_misr(struct sde_hw_mixer *ctx,
+ bool enable, u32 frame_count)
+{
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+ u32 config = 0;
+
+ SDE_REG_WRITE(c, LM_MISR_CTRL, MISR_CTRL_STATUS_CLEAR);
+ /* clear misr data */
+ wmb();
+
+ if (enable)
+ config = (frame_count & MISR_FRAME_COUNT_MASK) |
+ MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK;
+
+ SDE_REG_WRITE(c, LM_MISR_CTRL, config);
+}
+
+static u32 sde_hw_lm_collect_misr(struct sde_hw_mixer *ctx)
+{
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+
+ return SDE_REG_READ(c, LM_MISR_SIGNATURE);
+}
+
static void _setup_mixer_ops(struct sde_mdss_cfg *m,
struct sde_hw_lm_ops *ops,
unsigned long features)
@@ -236,6 +263,8 @@
ops->setup_alpha_out = sde_hw_lm_setup_color3;
ops->setup_border_color = sde_hw_lm_setup_border_color;
ops->setup_gc = sde_hw_lm_gc;
+ ops->setup_misr = sde_hw_lm_setup_misr;
+ ops->collect_misr = sde_hw_lm_collect_misr;
if (test_bit(SDE_DIM_LAYER, &features)) {
ops->setup_dim_layer = sde_hw_lm_setup_dim_layer;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.h b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
index 1ef36ac..45c0fc9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.h
@@ -79,6 +79,13 @@
* @ctx: Pointer to layer mixer context
*/
void (*clear_dim_layer)(struct sde_hw_mixer *ctx);
+
+ /* setup_misr: enables/disables MISR in HW register */
+ void (*setup_misr)(struct sde_hw_mixer *ctx,
+ bool enable, u32 frame_count);
+
+ /* collect_misr: reads and stores MISR data from HW register */
+ u32 (*collect_misr)(struct sde_hw_mixer *ctx);
};
struct sde_hw_mixer {
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_util.h b/drivers/gpu/drm/msm/sde/sde_hw_util.h
index 008b657..c1bfb79 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_util.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_util.h
@@ -47,6 +47,12 @@
#define SDE_REG_WRITE(c, off, val) sde_reg_write(c, off, val, #off)
#define SDE_REG_READ(c, off) sde_reg_read(c, off)
+#define MISR_FRAME_COUNT_MASK 0xFF
+#define MISR_CTRL_ENABLE BIT(8)
+#define MISR_CTRL_STATUS BIT(9)
+#define MISR_CTRL_STATUS_CLEAR BIT(10)
+#define INTF_MISR_CTRL_FREE_RUN_MASK BIT(31)
+
void *sde_hw_util_get_dir(void);
void sde_hw_csc_setup(struct sde_hw_blk_reg_map *c,
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index ef2c80e..b6a9f42 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -81,7 +81,8 @@
static int sde_kms_hw_init(struct msm_kms *kms);
static int _sde_kms_mmu_destroy(struct sde_kms *sde_kms);
-
+static int _sde_kms_register_events(struct msm_kms *kms,
+ struct drm_mode_object *obj, u32 event, bool en);
bool sde_is_custom_client(void)
{
return sdecustom;
@@ -1231,6 +1232,7 @@
.get_format = sde_get_msm_format,
.round_pixclk = sde_kms_round_pixclk,
.destroy = sde_kms_destroy,
+ .register_events = _sde_kms_register_events,
};
/* the caller api needs to turn on clock before calling it */
@@ -1596,3 +1598,32 @@
return &sde_kms->base;
}
+
+static int _sde_kms_register_events(struct msm_kms *kms,
+ struct drm_mode_object *obj, u32 event, bool en)
+{
+ int ret = 0;
+ struct drm_crtc *crtc = NULL;
+ struct drm_connector *conn = NULL;
+ struct sde_kms *sde_kms = NULL;
+
+ if (!kms || !obj) {
+ SDE_ERROR("invalid argument kms %pK obj %pK\n", kms, obj);
+ return -EINVAL;
+ }
+
+ sde_kms = to_sde_kms(kms);
+ switch (obj->type) {
+ case DRM_MODE_OBJECT_CRTC:
+ crtc = obj_to_crtc(obj);
+ ret = sde_crtc_register_custom_event(sde_kms, crtc, event, en);
+ break;
+ case DRM_MODE_OBJECT_CONNECTOR:
+ conn = obj_to_connector(obj);
+ ret = sde_connector_register_custom_event(sde_kms, conn, event,
+ en);
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c
index 2eb947d..0be17e4 100644
--- a/drivers/gpu/drm/msm/sde/sde_plane.c
+++ b/drivers/gpu/drm/msm/sde/sde_plane.c
@@ -769,8 +769,6 @@
psde->pipe_cfg.horz_decimation);
scale_cfg->src_height[i] = DECIMATED_DIMENSION(src_h,
psde->pipe_cfg.vert_decimation);
- if (SDE_FORMAT_IS_YUV(fmt))
- scale_cfg->src_width[i] &= ~0x1;
if (i == SDE_SSPP_COMP_1_2 || i == SDE_SSPP_COMP_2) {
scale_cfg->src_width[i] /= chroma_subsmpl_h;
scale_cfg->src_height[i] /= chroma_subsmpl_v;
@@ -1201,6 +1199,7 @@
psde->pipe_cfg.src_rect.y = 0;
psde->pipe_cfg.src_rect.w = psde->pipe_cfg.dst_rect.w;
psde->pipe_cfg.src_rect.h = psde->pipe_cfg.dst_rect.h;
+ _sde_plane_setup_scaler(psde, fmt, 0);
if (psde->pipe_hw->ops.setup_format)
psde->pipe_hw->ops.setup_format(psde->pipe_hw,
@@ -1212,7 +1211,6 @@
&psde->pipe_cfg,
pstate->multirect_index);
- _sde_plane_setup_scaler(psde, fmt, 0);
if (psde->pipe_hw->ops.setup_pe)
psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
&psde->pixel_ext);
@@ -1500,6 +1498,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)
@@ -2294,6 +2294,8 @@
psde->pipe_cfg.src_rect = src;
psde->pipe_cfg.dst_rect = dst;
+ _sde_plane_setup_scaler(psde, fmt, pstate);
+
/* check for color fill */
psde->color_fill = (uint32_t)sde_plane_get_property(pstate,
PLANE_PROP_COLOR_FILL);
@@ -2306,7 +2308,6 @@
pstate->multirect_index);
}
- _sde_plane_setup_scaler(psde, fmt, pstate);
if (psde->pipe_hw->ops.setup_pe)
psde->pipe_hw->ops.setup_pe(psde->pipe_hw,
&psde->pixel_ext);
diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c
index 697b7f7..9977d10 100644
--- a/drivers/gpu/drm/msm/sde_dbg.c
+++ b/drivers/gpu/drm/msm/sde_dbg.c
@@ -2436,7 +2436,7 @@
struct sde_dbg_reg_base **blk_arr;
u32 blk_len;
- if (!sde_evtlog_is_enabled(sde_dbg_base.evtlog, SDE_EVTLOG_DEFAULT))
+ if (!sde_evtlog_is_enabled(sde_dbg_base.evtlog, SDE_EVTLOG_ALWAYS))
return;
if (queue_work && work_pending(&sde_dbg_base.dump_work))
@@ -2558,6 +2558,82 @@
.write = sde_evtlog_dump_write,
};
+/*
+ * sde_evtlog_filter_show - read callback for evtlog filter
+ * @s: pointer to seq_file object
+ * @data: pointer to private data
+ */
+static int sde_evtlog_filter_show(struct seq_file *s, void *data)
+{
+ struct sde_dbg_evtlog *evtlog;
+ char buffer[64];
+ int i;
+
+ if (!s || !s->private)
+ return -EINVAL;
+
+ evtlog = s->private;
+
+ for (i = 0; !sde_evtlog_get_filter(
+ evtlog, i, buffer, ARRAY_SIZE(buffer)); ++i)
+ seq_printf(s, "*%s*\n", buffer);
+ return 0;
+}
+
+/*
+ * sde_evtlog_filter_open - debugfs open handler for evtlog filter
+ * @inode: debugfs inode
+ * @file: file handle
+ * Returns: zero on success
+ */
+static int sde_evtlog_filter_open(struct inode *inode, struct file *file)
+{
+ if (!file)
+ return -EINVAL;
+
+ return single_open(file, sde_evtlog_filter_show, inode->i_private);
+}
+
+/*
+ * sde_evtlog_filter_write - write callback for evtlog filter
+ * @file: pointer to file structure
+ * @user_buf: pointer to incoming user data
+ * @count: size of incoming user buffer
+ * @ppos: pointer to file offset
+ */
+static ssize_t sde_evtlog_filter_write(struct file *file,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char *tmp_filter = NULL;
+ ssize_t rc = 0;
+
+ if (count > 0) {
+ /* copy user provided string and null terminate it */
+ tmp_filter = kzalloc(count + 1, GFP_KERNEL);
+ if (!tmp_filter)
+ rc = -ENOMEM;
+ else if (copy_from_user(tmp_filter, user_buf, count))
+ rc = -EFAULT;
+ }
+
+ /* update actual filter configuration on success */
+ if (!rc) {
+ sde_evtlog_set_filter(sde_dbg_base.evtlog, tmp_filter);
+ rc = count;
+ }
+ kfree(tmp_filter);
+
+ return rc;
+}
+
+static const struct file_operations sde_evtlog_filter_fops = {
+ .open = sde_evtlog_filter_open,
+ .write = sde_evtlog_filter_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
/**
* sde_dbg_reg_base_release - release allocated reg dump file private data
* @inode: debugfs inode
@@ -2799,12 +2875,14 @@
&sde_evtlog_fops);
debugfs_create_u32("enable", 0644, sde_dbg_base.root,
&(sde_dbg_base.evtlog->enable));
+ debugfs_create_file("filter", 0644, sde_dbg_base.root,
+ sde_dbg_base.evtlog,
+ &sde_evtlog_filter_fops);
debugfs_create_u32("panic", 0644, sde_dbg_base.root,
&sde_dbg_base.panic_on_err);
debugfs_create_u32("reg_dump", 0644, sde_dbg_base.root,
&sde_dbg_base.enable_reg_dump);
-
if (dbg->dbgbus_sde.entries) {
dbg->dbgbus_sde.cmn.name = DBGBUS_NAME_SDE;
snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
diff --git a/drivers/gpu/drm/msm/sde_dbg.h b/drivers/gpu/drm/msm/sde_dbg.h
index 7a940f4..4344eb8 100644
--- a/drivers/gpu/drm/msm/sde_dbg.h
+++ b/drivers/gpu/drm/msm/sde_dbg.h
@@ -24,9 +24,10 @@
#define SDE_DBG_DUMP_DATA_LIMITER (NULL)
enum sde_dbg_evtlog_flag {
- SDE_EVTLOG_DEFAULT = BIT(0),
+ SDE_EVTLOG_CRITICAL = BIT(0),
SDE_EVTLOG_IRQ = BIT(1),
- SDE_EVTLOG_ALL = BIT(7)
+ SDE_EVTLOG_VERBOSE = BIT(2),
+ SDE_EVTLOG_ALWAYS = -1
};
enum sde_dbg_dump_flag {
@@ -35,7 +36,7 @@
};
#ifdef CONFIG_DRM_SDE_EVTLOG_DEBUG
-#define SDE_EVTLOG_DEFAULT_ENABLE 1
+#define SDE_EVTLOG_DEFAULT_ENABLE SDE_EVTLOG_CRITICAL
#else
#define SDE_EVTLOG_DEFAULT_ENABLE 0
#endif
@@ -72,6 +73,9 @@
int pid;
};
+/**
+ * @filter_list: Linked list of currently active filter strings
+ */
struct sde_dbg_evtlog {
struct sde_dbg_evtlog_log logs[SDE_EVTLOG_ENTRY];
u32 first;
@@ -80,6 +84,7 @@
u32 next;
u32 enable;
spinlock_t spin_lock;
+ struct list_head filter_list;
};
extern struct sde_dbg_evtlog *sde_dbg_base_evtlog;
@@ -89,7 +94,15 @@
* ... - variable arguments
*/
#define SDE_EVT32(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \
- __LINE__, SDE_EVTLOG_DEFAULT, ##__VA_ARGS__, \
+ __LINE__, SDE_EVTLOG_ALWAYS, ##__VA_ARGS__, \
+ SDE_EVTLOG_DATA_LIMITER)
+
+/**
+ * SDE_EVT32_VERBOSE - Write a list of 32bit values for verbose event logging
+ * ... - variable arguments
+ */
+#define SDE_EVT32_VERBOSE(...) sde_evtlog_log(sde_dbg_base_evtlog, __func__, \
+ __LINE__, SDE_EVTLOG_VERBOSE, ##__VA_ARGS__, \
SDE_EVTLOG_DATA_LIMITER)
/**
@@ -244,6 +257,24 @@
const char *range_name, u32 offset_start, u32 offset_end,
uint32_t xin_id);
+/**
+ * sde_evtlog_set_filter - update evtlog filtering
+ * @evtlog: pointer to evtlog
+ * @filter: pointer to optional function name filter, set to NULL to disable
+ */
+void sde_evtlog_set_filter(struct sde_dbg_evtlog *evtlog, char *filter);
+
+/**
+ * sde_evtlog_get_filter - query configured evtlog filters
+ * @evtlog: pointer to evtlog
+ * @index: filter index to retrieve
+ * @buf: pointer to output filter buffer
+ * @bufsz: size of output filter buffer
+ * Returns: zero if a filter string was returned
+ */
+int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index,
+ char *buf, size_t bufsz);
+
#else
static inline struct sde_dbg_evtlog *sde_evtlog_init(void)
{
@@ -275,7 +306,7 @@
return 0;
}
-void sde_dbg_init_dbg_buses(u32 hwversion)
+static inline void sde_dbg_init_dbg_buses(u32 hwversion)
{
}
@@ -285,7 +316,7 @@
return 0;
}
-int sde_dbg_debugfs_register(struct dentry *debugfs_root)
+static inline int sde_dbg_debugfs_register(struct dentry *debugfs_root)
{
return 0;
}
@@ -310,6 +341,17 @@
{
}
+static inline void sde_evtlog_set_filter(
+ struct sde_dbg_evtlog *evtlog, char *filter)
+{
+}
+
+static inline int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog,
+ int index, char *buf, size_t bufsz)
+{
+ return -EINVAL;
+}
+
#endif /* defined(CONFIG_DEBUG_FS) */
diff --git a/drivers/gpu/drm/msm/sde_dbg_evtlog.c b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
index 759bdab..699396f 100644
--- a/drivers/gpu/drm/msm/sde_dbg_evtlog.c
+++ b/drivers/gpu/drm/msm/sde_dbg_evtlog.c
@@ -23,13 +23,40 @@
#include "sde_dbg.h"
#include "sde_trace.h"
+#define SDE_EVTLOG_FILTER_STRSIZE 64
+
+struct sde_evtlog_filter {
+ struct list_head list;
+ char filter[SDE_EVTLOG_FILTER_STRSIZE];
+};
+
+static bool _sde_evtlog_is_filtered_no_lock(
+ struct sde_dbg_evtlog *evtlog, const char *str)
+{
+ struct sde_evtlog_filter *filter_node;
+ bool rc;
+
+ if (!str)
+ return true;
+
+ /*
+ * Filter the incoming string IFF the list is not empty AND
+ * a matching entry is not in the list.
+ */
+ rc = !list_empty(&evtlog->filter_list);
+ list_for_each_entry(filter_node, &evtlog->filter_list, list)
+ if (strnstr(str, filter_node->filter,
+ SDE_EVTLOG_FILTER_STRSIZE - 1)) {
+ rc = false;
+ break;
+ }
+
+ return rc;
+}
+
bool sde_evtlog_is_enabled(struct sde_dbg_evtlog *evtlog, u32 flag)
{
- if (!evtlog)
- return false;
-
- return (flag & evtlog->enable) ||
- (flag == SDE_EVTLOG_ALL && evtlog->enable);
+ return evtlog && (evtlog->enable & flag);
}
void sde_evtlog_log(struct sde_dbg_evtlog *evtlog, const char *name, int line,
@@ -47,6 +74,10 @@
return;
spin_lock_irqsave(&evtlog->spin_lock, flags);
+
+ if (_sde_evtlog_is_filtered_no_lock(evtlog, name))
+ goto exit;
+
log = &evtlog->logs[evtlog->curr];
log->time = ktime_to_us(ktime_get());
log->name = name;
@@ -70,27 +101,20 @@
trace_sde_evtlog(name, line, i > 0 ? log->data[0] : 0,
i > 1 ? log->data[1] : 0);
-
+exit:
spin_unlock_irqrestore(&evtlog->spin_lock, flags);
}
/* always dump the last entries which are not dumped yet */
static bool _sde_evtlog_dump_calc_range(struct sde_dbg_evtlog *evtlog)
{
- bool need_dump = true;
- unsigned long flags;
-
if (!evtlog)
return false;
- spin_lock_irqsave(&evtlog->spin_lock, flags);
-
evtlog->first = evtlog->next;
- if (evtlog->last == evtlog->first) {
- need_dump = false;
- goto dump_exit;
- }
+ if (evtlog->last == evtlog->first)
+ return false;
if (evtlog->last < evtlog->first) {
evtlog->first %= SDE_EVTLOG_ENTRY;
@@ -99,16 +123,14 @@
}
if ((evtlog->last - evtlog->first) > SDE_EVTLOG_PRINT_ENTRY) {
- pr_warn("evtlog buffer overflow before dump: %d\n",
- evtlog->last - evtlog->first);
+ pr_info("evtlog skipping %d entries, last=%d\n",
+ evtlog->last - evtlog->first - SDE_EVTLOG_PRINT_ENTRY,
+ evtlog->last - 1);
evtlog->first = evtlog->last - SDE_EVTLOG_PRINT_ENTRY;
}
evtlog->next = evtlog->first + 1;
-dump_exit:
- spin_unlock_irqrestore(&evtlog->spin_lock, flags);
-
- return need_dump;
+ return true;
}
ssize_t sde_evtlog_dump_to_buffer(struct sde_dbg_evtlog *evtlog,
@@ -122,16 +144,15 @@
if (!evtlog || !evtlog_buf)
return 0;
+ spin_lock_irqsave(&evtlog->spin_lock, flags);
+
/* update markers, exit if nothing to print */
if (!_sde_evtlog_dump_calc_range(evtlog))
- return 0;
-
- spin_lock_irqsave(&evtlog->spin_lock, flags);
+ goto exit;
log = &evtlog->logs[evtlog->first % SDE_EVTLOG_ENTRY];
- prev_log = &evtlog->logs[(evtlog->first - 1) %
- SDE_EVTLOG_ENTRY];
+ prev_log = &evtlog->logs[(evtlog->first - 1) % SDE_EVTLOG_ENTRY];
off = snprintf((evtlog_buf + off), (evtlog_buf_size - off), "%s:%-4d",
log->name, log->line);
@@ -150,7 +171,7 @@
"%x ", log->data[i]);
off += snprintf((evtlog_buf + off), (evtlog_buf_size - off), "\n");
-
+exit:
spin_unlock_irqrestore(&evtlog->spin_lock, flags);
return off;
@@ -178,10 +199,109 @@
spin_lock_init(&evtlog->spin_lock);
evtlog->enable = SDE_EVTLOG_DEFAULT_ENABLE;
+ INIT_LIST_HEAD(&evtlog->filter_list);
+
return evtlog;
}
+int sde_evtlog_get_filter(struct sde_dbg_evtlog *evtlog, int index,
+ char *buf, size_t bufsz)
+{
+ struct sde_evtlog_filter *filter_node;
+ unsigned long flags;
+ int rc = -EFAULT;
+
+ if (!evtlog || !buf || !bufsz || index < 0)
+ return -EINVAL;
+
+ spin_lock_irqsave(&evtlog->spin_lock, flags);
+ list_for_each_entry(filter_node, &evtlog->filter_list, list) {
+ if (index--)
+ continue;
+
+ /* don't care about return value */
+ (void)strlcpy(buf, filter_node->filter, bufsz);
+ rc = 0;
+ break;
+ }
+ spin_unlock_irqrestore(&evtlog->spin_lock, flags);
+
+ return rc;
+}
+
+void sde_evtlog_set_filter(struct sde_dbg_evtlog *evtlog, char *filter)
+{
+ struct sde_evtlog_filter *filter_node, *tmp;
+ struct list_head free_list;
+ unsigned long flags;
+ char *flt;
+
+ if (!evtlog)
+ return;
+
+ INIT_LIST_HEAD(&free_list);
+
+ /*
+ * Clear active filter list and cache filter_nodes locally
+ * to reduce memory fragmentation.
+ */
+ spin_lock_irqsave(&evtlog->spin_lock, flags);
+ list_for_each_entry_safe(filter_node, tmp, &evtlog->filter_list, list) {
+ list_del_init(&filter_node->list);
+ list_add_tail(&filter_node->list, &free_list);
+ }
+ spin_unlock_irqrestore(&evtlog->spin_lock, flags);
+
+ /*
+ * Parse incoming filter request string and build up a new
+ * filter list. New filter nodes are taken from the local
+ * free list, if available, and allocated from the system
+ * heap once the free list is empty.
+ */
+ while (filter && (flt = strsep(&filter, "|\r\n\t ")) != NULL) {
+ if (!*flt)
+ continue;
+
+ if (list_empty(&free_list)) {
+ filter_node = kzalloc(sizeof(*filter_node), GFP_KERNEL);
+ if (!filter_node)
+ break;
+
+ INIT_LIST_HEAD(&filter_node->list);
+ } else {
+ filter_node = list_first_entry(&free_list,
+ struct sde_evtlog_filter, list);
+ list_del_init(&filter_node->list);
+ }
+
+ /* don't care if copy truncated */
+ (void)strlcpy(filter_node->filter, flt,
+ SDE_EVTLOG_FILTER_STRSIZE);
+
+ spin_lock_irqsave(&evtlog->spin_lock, flags);
+ list_add_tail(&filter_node->list, &evtlog->filter_list);
+ spin_unlock_irqrestore(&evtlog->spin_lock, flags);
+ }
+
+ /*
+ * Free any unused filter_nodes back to the system.
+ */
+ list_for_each_entry_safe(filter_node, tmp, &free_list, list) {
+ list_del(&filter_node->list);
+ kfree(filter_node);
+ }
+}
+
void sde_evtlog_destroy(struct sde_dbg_evtlog *evtlog)
{
+ struct sde_evtlog_filter *filter_node, *tmp;
+
+ if (!evtlog)
+ return;
+
+ list_for_each_entry_safe(filter_node, tmp, &evtlog->filter_list, list) {
+ list_del(&filter_node->list);
+ kfree(filter_node);
+ }
kfree(evtlog);
}
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/a6xx_reg.h b/drivers/gpu/msm/a6xx_reg.h
index 7cdd2b2..2709aca 100644
--- a/drivers/gpu/msm/a6xx_reg.h
+++ b/drivers/gpu/msm/a6xx_reg.h
@@ -621,6 +621,48 @@
#define A6XX_VBIF_PERF_PWR_CNT_HIGH1 0x3119
#define A6XX_VBIF_PERF_PWR_CNT_HIGH2 0x311a
+/* CX_DBGC_CFG registers */
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_A 0x18400
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_B 0x18401
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_C 0x18402
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_D 0x18403
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLT 0x18404
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLT_TRACEEN_SHIFT 0x0
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLT_GRANU_SHIFT 0xC
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLT_SEGT_SHIFT 0x1C
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLM 0x18405
+#define A6XX_CX_DBGC_CFG_DBGBUS_CNTLM_ENABLE_SHIFT 0x18
+#define A6XX_CX_DBGC_CFG_DBGBUS_IVTL_0 0x18408
+#define A6XX_CX_DBGC_CFG_DBGBUS_IVTL_1 0x18409
+#define A6XX_CX_DBGC_CFG_DBGBUS_IVTL_2 0x1840A
+#define A6XX_CX_DBGC_CFG_DBGBUS_IVTL_3 0x1840B
+#define A6XX_CX_DBGC_CFG_DBGBUS_MASKL_0 0x1840C
+#define A6XX_CX_DBGC_CFG_DBGBUS_MASKL_1 0x1840D
+#define A6XX_CX_DBGC_CFG_DBGBUS_MASKL_2 0x1840E
+#define A6XX_CX_DBGC_CFG_DBGBUS_MASKL_3 0x1840F
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_0 0x18410
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_1 0x18411
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL0_SHIFT 0x0
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL1_SHIFT 0x4
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL2_SHIFT 0x8
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL3_SHIFT 0xC
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL4_SHIFT 0x10
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL5_SHIFT 0x14
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL6_SHIFT 0x18
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL7_SHIFT 0x1C
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL8_SHIFT 0x0
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL9_SHIFT 0x4
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL10_SHIFT 0x8
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL11_SHIFT 0xC
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL12_SHIFT 0x10
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL13_SHIFT 0x14
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL14_SHIFT 0x18
+#define A6XX_CX_DBGC_CFG_DBGBUS_BYTEL15_SHIFT 0x1C
+#define A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF1 0x1842F
+#define A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2 0x18430
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_PING_INDEX_SHIFT 0x0
+#define A6XX_CX_DBGC_CFG_DBGBUS_SEL_PING_BLK_SEL_SHIFT 0x8
+
/* GMU control registers */
#define A6XX_GMU_GX_SPTPRAC_POWER_CONTROL 0x1A881
#define A6XX_GMU_CM3_ITCM_START 0x1B400
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index f0d8746..68d7653 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -1854,6 +1854,30 @@
status = 0;
}
break;
+ case KGSL_PROP_DEVICE_QTIMER:
+ {
+ struct kgsl_qtimer_prop qtimerprop = {0};
+ struct kgsl_memdesc *qtimer_desc =
+ kgsl_mmu_get_qtimer_global_entry(device);
+
+ if (sizebytes != sizeof(qtimerprop)) {
+ status = -EINVAL;
+ break;
+ }
+
+ if (qtimer_desc) {
+ qtimerprop.gpuaddr = qtimer_desc->gpuaddr;
+ qtimerprop.size = qtimer_desc->size;
+ }
+
+ if (copy_to_user(value, &qtimerprop,
+ sizeof(qtimerprop))) {
+ status = -EFAULT;
+ break;
+ }
+ status = 0;
+ }
+ break;
case KGSL_PROP_MMU_ENABLE:
{
/* Report MMU only if we can handle paged memory */
@@ -3039,6 +3063,7 @@
.regulator_disable_poll = adreno_regulator_disable_poll,
.clk_set_options = adreno_clk_set_options,
.gpu_model = adreno_gpu_model,
+ .stop_fault_timer = adreno_dispatcher_stop_fault_timer,
};
static struct platform_driver adreno_platform_driver = {
diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c
index 0211a17..54d4bf7 100644
--- a/drivers/gpu/msm/adreno_a6xx.c
+++ b/drivers/gpu/msm/adreno_a6xx.c
@@ -899,6 +899,72 @@
}
/*
+ * a6xx_hm_sptprac_enable() - Turn on HM and SPTPRAC
+ * @device: Pointer to KGSL device
+ */
+static int a6xx_hm_sptprac_enable(struct kgsl_device *device)
+{
+ int ret = 0;
+ struct gmu_device *gmu = &device->gmu;
+
+ /* If GMU does not control HM we must */
+ if (gmu->idle_level < GPU_HW_IFPC) {
+ ret = a6xx_hm_enable(ADRENO_DEVICE(device));
+ if (ret) {
+ dev_err(&gmu->pdev->dev, "Failed to power on GPU HM\n");
+ return ret;
+ }
+ }
+
+ /* If GMU does not control SPTPRAC we must */
+ if (gmu->idle_level < GPU_HW_SPTP_PC) {
+ ret = a6xx_sptprac_enable(ADRENO_DEVICE(device));
+ if (ret) {
+ a6xx_hm_disable(ADRENO_DEVICE(device));
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * a6xx_hm_sptprac_disable() - Turn off SPTPRAC and HM
+ * @device: Pointer to KGSL device
+ */
+static int a6xx_hm_sptprac_disable(struct kgsl_device *device)
+{
+ int ret = 0;
+ struct gmu_device *gmu = &device->gmu;
+
+ /* If GMU does not control SPTPRAC we must */
+ if (gmu->idle_level < GPU_HW_SPTP_PC)
+ a6xx_sptprac_disable(ADRENO_DEVICE(device));
+
+ /* If GMU does not control HM we must */
+ if (gmu->idle_level < GPU_HW_IFPC) {
+ ret = a6xx_hm_disable(ADRENO_DEVICE(device));
+ if (ret)
+ dev_err(&gmu->pdev->dev, "Failed to power off GPU HM\n");
+ }
+
+ return ret;
+}
+
+/*
+ * a6xx_hm_sptprac_control() - Turn HM and SPTPRAC on or off
+ * @device: Pointer to KGSL device
+ * @on: True to turn on or false to turn off
+ */
+static int a6xx_hm_sptprac_control(struct kgsl_device *device, bool on)
+{
+ if (on)
+ return a6xx_hm_sptprac_enable(device);
+ else
+ return a6xx_hm_sptprac_disable(device);
+}
+
+/*
* a6xx_gfx_rail_on() - request GMU to power GPU at given OPP.
* @device: Pointer to KGSL device
*
@@ -976,7 +1042,7 @@
{
struct gmu_device *gmu = &device->gmu;
struct device *dev = &gmu->pdev->dev;
- int ret;
+ int ret = 0;
if (device->state != KGSL_STATE_INIT &&
device->state != KGSL_STATE_SUSPEND) {
@@ -1002,26 +1068,11 @@
0xFFFFFFFF))
goto error_rsc;
- /* If GMU does not control HM we must */
- if (gmu->idle_level < GPU_HW_IFPC) {
- ret = a6xx_hm_enable(ADRENO_DEVICE(device));
- if (ret) {
- dev_err(dev, "Failed to power on GPU HM\n");
- return ret;
- }
- }
-
- /* If GMU does not control SPTP we must */
- if (gmu->idle_level < GPU_HW_SPTP_PC) {
- ret = a6xx_sptprac_enable(ADRENO_DEVICE(device));
- if (ret) {
- a6xx_hm_disable(ADRENO_DEVICE(device));
- return ret;
- }
- }
+ /* Turn on the HM and SPTP head switches */
+ ret = a6xx_hm_sptprac_control(device, true);
}
- return 0;
+ return ret;
error_rsc:
dev_err(dev, "GPU RSC sequence stuck in waking up GPU\n");
@@ -1031,19 +1082,10 @@
static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device)
{
struct gmu_device *gmu = &device->gmu;
- struct device *dev = &gmu->pdev->dev;
- int val, ret;
+ int val, ret = 0;
- /* If GMU does not control SPTP we must */
- if (gmu->idle_level < GPU_HW_SPTP_PC)
- a6xx_sptprac_disable(ADRENO_DEVICE(device));
-
- /* If GMU does not control HM we must */
- if (gmu->idle_level < GPU_HW_IFPC) {
- ret = a6xx_hm_disable(ADRENO_DEVICE(device));
- if (ret)
- dev_err(dev, "Failed to power off GPU HM\n");
- }
+ /* Turn off the SPTP and HM head switches */
+ ret = a6xx_hm_sptprac_control(device, false);
/* RSC sleep sequence */
_regwrite(gmu->pdc_reg_virt, PDC_GPU_TIMESTAMP_UNIT1_EN_DRV0, 1);
@@ -1069,7 +1111,7 @@
/* FIXME: v2 has different procedure to trigger sequence */
- return 0;
+ return ret;
}
/*
@@ -1083,30 +1125,16 @@
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
struct gmu_device *gmu = &device->gmu;
struct gmu_memdesc *mem_addr = gmu->hfi_mem;
- struct device *dev = &gmu->pdev->dev;
int ret, i;
a6xx_gmu_power_config(device);
- /* If GMU does not control HM then we must */
- if (gmu->idle_level < GPU_HW_IFPC) {
- ret = a6xx_hm_enable(adreno_dev);
- if (ret) {
- dev_err(dev, "Failed to power on GPU HM\n");
- return ret;
- }
- }
-
- /* If GMU does not control SPTP then we must */
- if (gmu->idle_level < GPU_HW_SPTP_PC) {
- ret = a6xx_sptprac_enable(adreno_dev);
- if (ret) {
- a6xx_hm_disable(adreno_dev);
- return ret;
- }
- }
-
if (boot_state == GMU_COLD_BOOT || boot_state == GMU_RESET) {
+ /* Turn on the HM and SPTP head switches */
+ ret = a6xx_hm_sptprac_control(device, true);
+ if (ret)
+ return ret;
+
/* Turn on TCM retention */
kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1);
diff --git a/drivers/gpu/msm/adreno_a6xx_snapshot.c b/drivers/gpu/msm/adreno_a6xx_snapshot.c
index 12485a8..e501a68 100644
--- a/drivers/gpu/msm/adreno_a6xx_snapshot.c
+++ b/drivers/gpu/msm/adreno_a6xx_snapshot.c
@@ -342,6 +342,13 @@
{ A6XX_DBGBUS_TPL1_3, 0x100, },
};
+static void __iomem *a6xx_cx_dbgc;
+static const struct adreno_debugbus_block a6xx_cx_dbgc_debugbus_blocks[] = {
+ { A6XX_DBGBUS_VBIF, 0x100, },
+ { A6XX_DBGBUS_GMU, 0x100, },
+ { A6XX_DBGBUS_CX, 0x100, },
+};
+
#define A6XX_NUM_SHADER_BANKS 3
#define A6XX_SHADER_STATETYPE_SHIFT 8
@@ -904,6 +911,100 @@
return size;
}
+static void _cx_dbgc_regread(unsigned int offsetwords, unsigned int *value)
+{
+ void __iomem *reg;
+
+ if (WARN((offsetwords < A6XX_CX_DBGC_CFG_DBGBUS_SEL_A) ||
+ (offsetwords > A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2),
+ "Read beyond CX_DBGC block: 0x%x\n", offsetwords))
+ return;
+
+ reg = a6xx_cx_dbgc +
+ ((offsetwords - A6XX_CX_DBGC_CFG_DBGBUS_SEL_A) << 2);
+ *value = __raw_readl(reg);
+
+ /*
+ * ensure this read finishes before the next one.
+ * i.e. act like normal readl()
+ */
+ rmb();
+}
+
+static void _cx_dbgc_regwrite(unsigned int offsetwords, unsigned int value)
+{
+ void __iomem *reg;
+
+ if (WARN((offsetwords < A6XX_CX_DBGC_CFG_DBGBUS_SEL_A) ||
+ (offsetwords > A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2),
+ "Write beyond CX_DBGC block: 0x%x\n", offsetwords))
+ return;
+
+ reg = a6xx_cx_dbgc +
+ ((offsetwords - A6XX_CX_DBGC_CFG_DBGBUS_SEL_A) << 2);
+
+ /*
+ * ensure previous writes post before this one,
+ * i.e. act like normal writel()
+ */
+ wmb();
+ __raw_writel(value, reg);
+}
+
+/* a6xx_cx_dbgc_debug_bus_read() - Read data from trace bus */
+static void a6xx_cx_debug_bus_read(struct kgsl_device *device,
+ unsigned int block_id, unsigned int index, unsigned int *val)
+{
+ unsigned int reg;
+
+ reg = (block_id << A6XX_CX_DBGC_CFG_DBGBUS_SEL_PING_BLK_SEL_SHIFT) |
+ (index << A6XX_CX_DBGC_CFG_DBGBUS_SEL_PING_INDEX_SHIFT);
+
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_SEL_A, reg);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_SEL_B, reg);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_SEL_C, reg);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_SEL_D, reg);
+
+ _cx_dbgc_regread(A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2, val);
+ val++;
+ _cx_dbgc_regread(A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF1, val);
+}
+
+/*
+ * a6xx_snapshot_cx_dbgc_debugbus_block() - Capture debug data for a gpu
+ * block from the CX DBGC block
+ */
+static size_t a6xx_snapshot_cx_dbgc_debugbus_block(struct kgsl_device *device,
+ u8 *buf, size_t remain, void *priv)
+{
+ struct kgsl_snapshot_debugbus *header =
+ (struct kgsl_snapshot_debugbus *)buf;
+ struct adreno_debugbus_block *block = priv;
+ int i;
+ unsigned int *data = (unsigned int *)(buf + sizeof(*header));
+ unsigned int dwords;
+ size_t size;
+
+ dwords = block->dwords;
+
+ /* For a6xx each debug bus data unit is 2 DWRODS */
+ size = (dwords * sizeof(unsigned int) * 2) + sizeof(*header);
+
+ if (remain < size) {
+ SNAPSHOT_ERR_NOMEM(device, "DEBUGBUS");
+ return 0;
+ }
+
+ header->id = block->block_id;
+ header->count = dwords * 2;
+
+ for (i = 0; i < dwords; i++)
+ a6xx_cx_debug_bus_read(device, block->block_id, i,
+ &data[i*2]);
+
+ return size;
+}
+
/* a6xx_snapshot_debugbus() - Capture debug bus data */
static void a6xx_snapshot_debugbus(struct kgsl_device *device,
struct kgsl_snapshot *snapshot)
@@ -947,12 +1048,67 @@
kgsl_regwrite(device, A6XX_DBGC_CFG_DBGBUS_MASKL_2, 0);
kgsl_regwrite(device, A6XX_DBGC_CFG_DBGBUS_MASKL_3, 0);
+ a6xx_cx_dbgc = ioremap(device->reg_phys +
+ (A6XX_CX_DBGC_CFG_DBGBUS_SEL_A << 2),
+ (A6XX_CX_DBGC_CFG_DBGBUS_TRACE_BUF2 -
+ A6XX_CX_DBGC_CFG_DBGBUS_SEL_A + 1) << 2);
+
+ if (a6xx_cx_dbgc) {
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_CNTLT,
+ (0xf << A6XX_DBGC_CFG_DBGBUS_CNTLT_SEGT_SHIFT) |
+ (0x4 << A6XX_DBGC_CFG_DBGBUS_CNTLT_GRANU_SHIFT) |
+ (0x20 << A6XX_DBGC_CFG_DBGBUS_CNTLT_TRACEEN_SHIFT));
+
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_CNTLM,
+ 0xf << A6XX_CX_DBGC_CFG_DBGBUS_CNTLM_ENABLE_SHIFT);
+
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_IVTL_0, 0);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_IVTL_1, 0);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_IVTL_2, 0);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_IVTL_3, 0);
+
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_0,
+ (0 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL0_SHIFT) |
+ (1 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL1_SHIFT) |
+ (2 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL2_SHIFT) |
+ (3 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL3_SHIFT) |
+ (4 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL4_SHIFT) |
+ (5 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL5_SHIFT) |
+ (6 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL6_SHIFT) |
+ (7 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL7_SHIFT));
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_BYTEL_1,
+ (8 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL8_SHIFT) |
+ (9 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL9_SHIFT) |
+ (10 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL10_SHIFT) |
+ (11 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL11_SHIFT) |
+ (12 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL12_SHIFT) |
+ (13 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL13_SHIFT) |
+ (14 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL14_SHIFT) |
+ (15 << A6XX_CX_DBGC_CFG_DBGBUS_BYTEL15_SHIFT));
+
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_MASKL_0, 0);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_MASKL_1, 0);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_MASKL_2, 0);
+ _cx_dbgc_regwrite(A6XX_CX_DBGC_CFG_DBGBUS_MASKL_3, 0);
+ } else
+ KGSL_DRV_ERR(device, "Unable to ioremap CX_DBGC_CFG block\n");
+
for (i = 0; i < ARRAY_SIZE(a6xx_dbgc_debugbus_blocks); i++) {
kgsl_snapshot_add_section(device,
KGSL_SNAPSHOT_SECTION_DEBUGBUS,
snapshot, a6xx_snapshot_dbgc_debugbus_block,
(void *) &a6xx_dbgc_debugbus_blocks[i]);
}
+
+ if (a6xx_cx_dbgc) {
+ for (i = 0; i < ARRAY_SIZE(a6xx_cx_dbgc_debugbus_blocks); i++) {
+ kgsl_snapshot_add_section(device,
+ KGSL_SNAPSHOT_SECTION_DEBUGBUS,
+ snapshot, a6xx_snapshot_cx_dbgc_debugbus_block,
+ (void *) &a6xx_cx_dbgc_debugbus_blocks[i]);
+ }
+ iounmap(a6xx_cx_dbgc);
+ }
}
static size_t a6xx_snapshot_dump_gmu_registers(struct kgsl_device *device,
diff --git a/drivers/gpu/msm/adreno_compat.c b/drivers/gpu/msm/adreno_compat.c
index d86a0c6..5a8d587 100644
--- a/drivers/gpu/msm/adreno_compat.c
+++ b/drivers/gpu/msm/adreno_compat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, 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
@@ -113,6 +113,30 @@
status = 0;
}
break;
+ case KGSL_PROP_DEVICE_QTIMER:
+ {
+ struct kgsl_qtimer_prop qtimerprop = {0};
+ struct kgsl_memdesc *qtimer_desc =
+ kgsl_mmu_get_qtimer_global_entry(device);
+
+ if (sizebytes != sizeof(qtimerprop)) {
+ status = -EINVAL;
+ break;
+ }
+
+ if (qtimer_desc) {
+ qtimerprop.gpuaddr = qtimer_desc->gpuaddr;
+ qtimerprop.size = qtimer_desc->size;
+ }
+
+ if (copy_to_user(value, &qtimerprop,
+ sizeof(qtimerprop))) {
+ status = -EFAULT;
+ break;
+ }
+ status = 0;
+ }
+ break;
default:
/*
* Call the adreno_getproperty to check if the property type
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 3fa38fa..ed5b714 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -208,6 +208,9 @@
if (!kgsl_state_is_awake(KGSL_DEVICE(adreno_dev)))
goto ret;
+ if (adreno_rb_empty(adreno_dev->cur_rb))
+ goto ret;
+
/* only check rbbm status to determine if GPU is idle */
adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS, ®_rbbm_status);
@@ -2055,12 +2058,25 @@
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
+ * In the very unlikely case that the power is off, do nothing - the
+ * state will be reset on power up and everybody will be happy
+ */
+
+ if (!kgsl_state_is_awake(device) && (fault & ADRENO_SOFT_FAULT)) {
+ /* Clear the existing register values */
+ memset(adreno_ft_regs_val, 0,
+ adreno_ft_regs_num * sizeof(unsigned int));
+ return 0;
+ }
+
+ /*
+ * 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 +2102,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);
@@ -2508,7 +2524,7 @@
if (!fault_detect_read_compare(adreno_dev)) {
adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT);
adreno_dispatcher_schedule(KGSL_DEVICE(adreno_dev));
- } else {
+ } else if (dispatcher->inflight > 0) {
mod_timer(&dispatcher->fault_timer,
jiffies + msecs_to_jiffies(_fault_timer_interval));
}
@@ -2553,6 +2569,20 @@
}
/**
+ * adreno_dispatcher_stop_fault_timer() - stop the dispatcher fault timer
+ * @device: pointer to the KGSL device structure
+ *
+ * Stop the dispatcher fault timer
+ */
+void adreno_dispatcher_stop_fault_timer(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
+
+ del_timer_sync(&dispatcher->fault_timer);
+}
+
+/**
* adreno_dispatcher_close() - close the dispatcher
* @adreno_dev: pointer to the adreno device structure
*
diff --git a/drivers/gpu/msm/adreno_dispatch.h b/drivers/gpu/msm/adreno_dispatch.h
index cb9106f..72545db 100644
--- a/drivers/gpu/msm/adreno_dispatch.h
+++ b/drivers/gpu/msm/adreno_dispatch.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -108,6 +108,7 @@
int adreno_dispatcher_idle(struct adreno_device *adreno_dev);
void adreno_dispatcher_irq_fault(struct adreno_device *adreno_dev);
void adreno_dispatcher_stop(struct adreno_device *adreno_dev);
+void adreno_dispatcher_stop_fault_timer(struct kgsl_device *device);
int adreno_dispatcher_queue_cmds(struct kgsl_device_private *dev_priv,
struct kgsl_context *context, struct kgsl_drawobj *drawobj[],
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/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index b4725c1..bf31c00 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -178,6 +178,7 @@
const char *name, struct clk *clk);
void (*gpu_model)(struct kgsl_device *device, char *str,
size_t bufsz);
+ void (*stop_fault_timer)(struct kgsl_device *device);
};
struct kgsl_ioctl {
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index cfd5cd1..0325db8 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -113,6 +113,7 @@
static int global_pt_count;
uint64_t global_pt_alloc;
static struct kgsl_memdesc gpu_qdss_desc;
+static struct kgsl_memdesc gpu_qtimer_desc;
void kgsl_print_global_pt_entries(struct seq_file *s)
{
@@ -272,6 +273,50 @@
kgsl_sharedmem_free(&gpu_qdss_desc);
}
+struct kgsl_memdesc *kgsl_iommu_get_qtimer_global_entry(void)
+{
+ return &gpu_qtimer_desc;
+}
+
+static void kgsl_setup_qtimer_desc(struct kgsl_device *device)
+{
+ int result = 0;
+ uint32_t gpu_qtimer_entry[2];
+
+ if (!of_find_property(device->pdev->dev.of_node,
+ "qcom,gpu-qtimer", NULL))
+ return;
+
+ if (of_property_read_u32_array(device->pdev->dev.of_node,
+ "qcom,gpu-qtimer", gpu_qtimer_entry, 2)) {
+ KGSL_CORE_ERR("Failed to read gpu qtimer dts entry\n");
+ return;
+ }
+
+ gpu_qtimer_desc.flags = 0;
+ gpu_qtimer_desc.priv = 0;
+ gpu_qtimer_desc.physaddr = gpu_qtimer_entry[0];
+ gpu_qtimer_desc.size = gpu_qtimer_entry[1];
+ gpu_qtimer_desc.pagetable = NULL;
+ gpu_qtimer_desc.ops = NULL;
+ gpu_qtimer_desc.dev = device->dev->parent;
+ gpu_qtimer_desc.hostptr = NULL;
+
+ result = memdesc_sg_dma(&gpu_qtimer_desc, gpu_qtimer_desc.physaddr,
+ gpu_qtimer_desc.size);
+ if (result) {
+ KGSL_CORE_ERR("memdesc_sg_dma failed: %d\n", result);
+ return;
+ }
+
+ kgsl_mmu_add_global(device, &gpu_qtimer_desc, "gpu-qtimer");
+}
+
+static inline void kgsl_cleanup_qtimer_desc(struct kgsl_mmu *mmu)
+{
+ kgsl_iommu_remove_global(mmu, &gpu_qtimer_desc);
+ kgsl_sharedmem_free(&gpu_qtimer_desc);
+}
static inline void _iommu_sync_mmu_pc(bool lock)
{
@@ -1452,6 +1497,7 @@
kgsl_iommu_remove_global(mmu, &iommu->setstate);
kgsl_sharedmem_free(&iommu->setstate);
kgsl_cleanup_qdss_desc(mmu);
+ kgsl_cleanup_qtimer_desc(mmu);
}
static int _setstate_alloc(struct kgsl_device *device,
@@ -1523,6 +1569,7 @@
kgsl_iommu_add_global(mmu, &iommu->setstate, "setstate");
kgsl_setup_qdss_desc(device);
+ kgsl_setup_qtimer_desc(device);
done:
if (status)
@@ -2671,6 +2718,7 @@
.mmu_remove_global = kgsl_iommu_remove_global,
.mmu_getpagetable = kgsl_iommu_getpagetable,
.mmu_get_qdss_global_entry = kgsl_iommu_get_qdss_global_entry,
+ .mmu_get_qtimer_global_entry = kgsl_iommu_get_qtimer_global_entry,
.probe = kgsl_iommu_probe,
};
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index 9e516e1..8ea4492 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -617,6 +617,18 @@
}
EXPORT_SYMBOL(kgsl_mmu_get_qdss_global_entry);
+struct kgsl_memdesc *kgsl_mmu_get_qtimer_global_entry(
+ struct kgsl_device *device)
+{
+ struct kgsl_mmu *mmu = &device->mmu;
+
+ if (MMU_OP_VALID(mmu, mmu_get_qtimer_global_entry))
+ return mmu->mmu_ops->mmu_get_qtimer_global_entry();
+
+ return NULL;
+}
+EXPORT_SYMBOL(kgsl_mmu_get_qtimer_global_entry);
+
/*
* NOMMU definitions - NOMMU really just means that the MMU is kept in pass
* through and the GPU directly accesses physical memory. Used in debug mode
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index 0f9f486..56bb317 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -83,6 +83,7 @@
struct kgsl_pagetable * (*mmu_getpagetable)(struct kgsl_mmu *mmu,
unsigned long name);
struct kgsl_memdesc* (*mmu_get_qdss_global_entry)(void);
+ struct kgsl_memdesc* (*mmu_get_qtimer_global_entry)(void);
};
struct kgsl_mmu_pt_ops {
@@ -233,6 +234,9 @@
struct kgsl_memdesc *kgsl_mmu_get_qdss_global_entry(struct kgsl_device *device);
+struct kgsl_memdesc *kgsl_mmu_get_qtimer_global_entry(
+ struct kgsl_device *device);
+
int kgsl_mmu_sparse_dummy_map(struct kgsl_pagetable *pagetable,
struct kgsl_memdesc *memdesc, uint64_t offset, uint64_t size);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 4d38794..b3e2b6a 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -2621,6 +2621,7 @@
return -EBUSY;
}
+ device->ftbl->stop_fault_timer(device);
kgsl_pwrscale_midframe_timer_cancel(device);
/*
diff --git a/drivers/gpu/msm/kgsl_pwrscale.c b/drivers/gpu/msm/kgsl_pwrscale.c
index fc5f5a8..07a54d9 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.c
+++ b/drivers/gpu/msm/kgsl_pwrscale.c
@@ -14,6 +14,7 @@
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
+#include <linux/devfreq_cooling.h>
#include "kgsl.h"
#include "kgsl_pwrscale.h"
@@ -530,7 +531,8 @@
struct kgsl_pwrctrl *pwr;
struct kgsl_pwrlevel *pwr_level;
int level, i;
- unsigned long cur_freq;
+ unsigned long cur_freq, rec_freq;
+ struct dev_pm_opp *opp;
if (device == NULL)
return -ENODEV;
@@ -549,16 +551,31 @@
return 0;
}
+ /*
+ * Thermal framework might have disabled/enabled OPP entries
+ * for mitigation. So find the recommended frequency matching
+ * the available opp entries
+ */
+ rcu_read_lock();
+ rec_freq = *freq;
+ opp = devfreq_recommended_opp(dev, &rec_freq, flags);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ return PTR_ERR(opp);
+ }
+ rec_freq = dev_pm_opp_get_freq(opp);
+ rcu_read_unlock();
+
mutex_lock(&device->mutex);
cur_freq = kgsl_pwrctrl_active_freq(pwr);
level = pwr->active_pwrlevel;
pwr_level = &pwr->pwrlevels[level];
/* If the governor recommends a new frequency, update it here */
- if (*freq != cur_freq) {
+ if (rec_freq != cur_freq) {
level = pwr->max_pwrlevel;
for (i = pwr->min_pwrlevel; i >= pwr->max_pwrlevel; i--)
- if (*freq <= pwr->pwrlevels[i].gpu_freq) {
+ if (rec_freq <= pwr->pwrlevels[i].gpu_freq) {
if (pwr->thermal_cycle == CYCLE_ACTIVE)
level = _thermal_adjust(pwr, i);
else
@@ -963,6 +980,10 @@
}
pwrscale->devfreqptr = devfreq;
+ pwrscale->cooling_dev = of_devfreq_cooling_register(
+ device->pdev->dev.of_node, devfreq);
+ if (IS_ERR(pwrscale->cooling_dev))
+ pwrscale->cooling_dev = NULL;
pwrscale->gpu_profile.bus_devfreq = NULL;
if (data->bus.num) {
@@ -1025,6 +1046,8 @@
pwrscale = &device->pwrscale;
if (!pwrscale->devfreqptr)
return;
+ if (pwrscale->cooling_dev)
+ devfreq_cooling_unregister(pwrscale->cooling_dev);
kgsl_pwrscale_midframe_timer_cancel(device);
flush_workqueue(pwrscale->devfreq_wq);
diff --git a/drivers/gpu/msm/kgsl_pwrscale.h b/drivers/gpu/msm/kgsl_pwrscale.h
index e3d3dc7..7e906a0 100644
--- a/drivers/gpu/msm/kgsl_pwrscale.h
+++ b/drivers/gpu/msm/kgsl_pwrscale.h
@@ -90,6 +90,7 @@
* @history - History of power events with timestamps and durations
* @popp_level - Current level of POPP mitigation
* @popp_state - Control state for POPP, on/off, recently pushed, etc
+ * @cooling_dev - Thermal cooling device handle
*/
struct kgsl_pwrscale {
struct devfreq *devfreqptr;
@@ -111,6 +112,7 @@
struct kgsl_pwr_history history[KGSL_PWREVENT_MAX];
int popp_level;
unsigned long popp_state;
+ struct thermal_cooling_device *cooling_dev;
};
int kgsl_pwrscale_init(struct device *dev, const char *governor);
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/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index d7b4363..58e8850 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -173,7 +173,7 @@
u32 m_param = 0;
u32 m_cmd = 0;
- m_param |= (stretch ? STOP_STRETCH : ~(STOP_STRETCH));
+ m_param |= (stretch ? STOP_STRETCH : 0);
m_param |= ((msgs[i].addr & 0x7F) << SLV_ADDR_SHFT);
gi2c->cur = &msgs[i];
diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c
index 302cf14..e412230 100644
--- a/drivers/iio/adc/qcom-rradc.c
+++ b/drivers/iio/adc/qcom-rradc.c
@@ -163,12 +163,16 @@
#define FG_ADC_RR_DIE_TEMP_SLOPE 2
#define FG_ADC_RR_DIE_TEMP_OFFSET_MILLI_DEGC 25000
-#define FAB_ID_GF 0x30
-#define FAB_ID_SMIC 0x11
#define FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV 1303168
#define FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C 3784
#define FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV 1338433
#define FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C 3655
+#define FG_ADC_RR_CHG_TEMP_660_GF_OFFSET_UV 1309001
+#define FG_RR_CHG_TEMP_660_GF_SLOPE_UV_PER_C 3403
+#define FG_ADC_RR_CHG_TEMP_660_SMIC_OFFSET_UV 1295898
+#define FG_RR_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C 3596
+#define FG_ADC_RR_CHG_TEMP_660_MGNA_OFFSET_UV 1314779
+#define FG_RR_CHG_TEMP_660_MGNA_SLOPE_UV_PER_C 3496
#define FG_ADC_RR_CHG_TEMP_OFFSET_MILLI_DEGC 25000
#define FG_ADC_RR_CHG_THRESHOLD_SCALE 4
@@ -388,23 +392,70 @@
return 0;
}
+static int rradc_get_660_fab_coeff(struct rradc_chip *chip,
+ int64_t *offset, int64_t *slope)
+{
+ switch (chip->pmic_fab_id->fab_id) {
+ case PM660_FAB_ID_GF:
+ *offset = FG_ADC_RR_CHG_TEMP_660_GF_OFFSET_UV;
+ *slope = FG_RR_CHG_TEMP_660_GF_SLOPE_UV_PER_C;
+ break;
+ case PM660_FAB_ID_TSMC:
+ *offset = FG_ADC_RR_CHG_TEMP_660_SMIC_OFFSET_UV;
+ *slope = FG_RR_CHG_TEMP_660_SMIC_SLOPE_UV_PER_C;
+ break;
+ default:
+ *offset = FG_ADC_RR_CHG_TEMP_660_MGNA_OFFSET_UV;
+ *slope = FG_RR_CHG_TEMP_660_MGNA_SLOPE_UV_PER_C;
+ }
+
+ return 0;
+}
+
+static int rradc_get_8998_fab_coeff(struct rradc_chip *chip,
+ int64_t *offset, int64_t *slope)
+{
+ switch (chip->pmic_fab_id->fab_id) {
+ case PMI8998_FAB_ID_GF:
+ *offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV;
+ *slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C;
+ break;
+ case PMI8998_FAB_ID_SMIC:
+ *offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV;
+ *slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int rradc_post_process_chg_temp_hot(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u16 adc_code,
int *result_millidegc)
{
int64_t uv = 0, offset = 0, slope = 0;
+ int rc = 0;
if (chip->revid_dev_node) {
- switch (chip->pmic_fab_id->fab_id) {
- case FAB_ID_GF:
- offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV;
- slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C;
+ switch (chip->pmic_fab_id->pmic_subtype) {
+ case PM660_SUBTYPE:
+ rc = rradc_get_660_fab_coeff(chip, &offset, &slope);
+ if (rc < 0) {
+ pr_err("Unable to get fab id coefficients\n");
+ return -EINVAL;
+ }
break;
- case FAB_ID_SMIC:
- offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV;
- slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
+ case PMI8998_SUBTYPE:
+ rc = rradc_get_8998_fab_coeff(chip, &offset, &slope);
+ if (rc < 0) {
+ pr_err("Unable to get fab id coefficients\n");
+ return -EINVAL;
+ }
break;
default:
+ pr_err("No PMIC subtype found\n");
return -EINVAL;
}
} else {
@@ -444,18 +495,26 @@
int *result_millidegc)
{
int64_t uv = 0, offset = 0, slope = 0;
+ int rc = 0;
if (chip->revid_dev_node) {
- switch (chip->pmic_fab_id->fab_id) {
- case FAB_ID_GF:
- offset = FG_ADC_RR_CHG_TEMP_GF_OFFSET_UV;
- slope = FG_ADC_RR_CHG_TEMP_GF_SLOPE_UV_PER_C;
+ switch (chip->pmic_fab_id->pmic_subtype) {
+ case PM660_SUBTYPE:
+ rc = rradc_get_660_fab_coeff(chip, &offset, &slope);
+ if (rc < 0) {
+ pr_err("Unable to get fab id coefficients\n");
+ return -EINVAL;
+ }
break;
- case FAB_ID_SMIC:
- offset = FG_ADC_RR_CHG_TEMP_SMIC_OFFSET_UV;
- slope = FG_ADC_RR_CHG_TEMP_SMIC_SLOPE_UV_PER_C;
+ case PMI8998_SUBTYPE:
+ rc = rradc_get_8998_fab_coeff(chip, &offset, &slope);
+ if (rc < 0) {
+ pr_err("Unable to get fab id coefficients\n");
+ return -EINVAL;
+ }
break;
default:
+ pr_err("No PMIC subtype found\n");
return -EINVAL;
}
} else {
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..34df44c 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)
@@ -3988,14 +3946,38 @@
IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init);
IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init);
+#define TCU_HW_VERSION_HLOS1 (0x18)
+
#define DEBUG_SID_HALT_REG 0x0
#define DEBUG_SID_HALT_VAL (0x1 << 16)
+#define DEBUG_SID_HALT_SID_MASK 0x3ff
+
+#define DEBUG_VA_ADDR_REG 0x8
+
+#define DEBUG_TXN_TRIGG_REG 0x18
+#define DEBUG_TXN_AXPROT_SHIFT 6
+#define DEBUG_TXN_AXCACHE_SHIFT 2
+#define DEBUG_TRX_WRITE (0x1 << 1)
+#define DEBUG_TXN_READ (0x0 << 1)
+#define DEBUG_TXN_TRIGGER 0x1
#define DEBUG_SR_HALT_ACK_REG 0x20
#define DEBUG_SR_HALT_ACK_VAL (0x1 << 1)
+#define DEBUG_SR_ECATS_RUNNING_VAL (0x1 << 0)
+
+#define DEBUG_PAR_REG 0x28
+#define DEBUG_PAR_PA_MASK ((0x1ULL << 36) - 1)
+#define DEBUG_PAR_PA_SHIFT 12
+#define DEBUG_PAR_FAULT_VAL 0x1
#define TBU_DBG_TIMEOUT_US 30000
+struct qsmmuv500_archdata {
+ struct list_head tbus;
+ void __iomem *tcu_base;
+ u32 version;
+};
+
struct qsmmuv500_tbu_device {
struct list_head list;
struct device *dev;
@@ -4004,6 +3986,8 @@
void __iomem *status_reg;
struct arm_smmu_power_resources *pwr;
+ u32 sid_start;
+ u32 num_sids;
/* Protects halt count */
spinlock_t halt_lock;
@@ -4013,10 +3997,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 +4008,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 +4017,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 +4085,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 +4097,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,13 +4106,27 @@
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);
}
}
+static struct qsmmuv500_tbu_device *qsmmuv500_find_tbu(
+ struct arm_smmu_device *smmu, u32 sid)
+{
+ struct qsmmuv500_tbu_device *tbu = NULL;
+ struct qsmmuv500_archdata *data = smmu->archdata;
+
+ list_for_each_entry(tbu, &data->tbus, list) {
+ if (tbu->sid_start <= sid &&
+ sid < tbu->sid_start + tbu->num_sids)
+ break;
+ }
+ return tbu;
+}
+
static void qsmmuv500_device_reset(struct arm_smmu_device *smmu)
{
int i, ret;
@@ -4147,6 +4145,187 @@
qsmmuv500_tbu_power_off_all(smmu);
}
+static int qsmmuv500_ecats_lock(struct arm_smmu_domain *smmu_domain,
+ struct qsmmuv500_tbu_device *tbu,
+ unsigned long *flags)
+{
+ struct arm_smmu_device *smmu = tbu->smmu;
+ struct qsmmuv500_archdata *data = smmu->archdata;
+ u32 val;
+
+ spin_lock_irqsave(&smmu->atos_lock, *flags);
+ /* The status register is not accessible on version 1.0 */
+ if (data->version == 0x01000000)
+ return 0;
+
+ if (readl_poll_timeout_atomic(tbu->status_reg,
+ val, (val == 0x1), 0,
+ TBU_DBG_TIMEOUT_US)) {
+ dev_err(tbu->dev, "ECATS hw busy!\n");
+ spin_unlock_irqrestore(&smmu->atos_lock, *flags);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void qsmmuv500_ecats_unlock(struct arm_smmu_domain *smmu_domain,
+ struct qsmmuv500_tbu_device *tbu,
+ unsigned long *flags)
+{
+ struct arm_smmu_device *smmu = tbu->smmu;
+ struct qsmmuv500_archdata *data = smmu->archdata;
+
+ /* The status register is not accessible on version 1.0 */
+ if (data->version != 0x01000000)
+ writel_relaxed(0, tbu->status_reg);
+ spin_unlock_irqrestore(&smmu->atos_lock, *flags);
+}
+
+/*
+ * Zero means failure.
+ */
+static phys_addr_t qsmmuv500_iova_to_phys(
+ struct iommu_domain *domain, dma_addr_t iova, u32 sid)
+{
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+ struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
+ struct qsmmuv500_tbu_device *tbu;
+ int ret;
+ phys_addr_t phys = 0;
+ u64 val, fsr;
+ unsigned long flags;
+ void __iomem *cb_base;
+ u32 sctlr_orig, sctlr;
+ int needs_redo = 0;
+
+ cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ tbu = qsmmuv500_find_tbu(smmu, sid);
+ if (!tbu)
+ return 0;
+
+ ret = arm_smmu_power_on(tbu->pwr);
+ if (ret)
+ return 0;
+
+ /*
+ * Disable client transactions & wait for existing operations to
+ * complete.
+ */
+ ret = qsmmuv500_tbu_halt(tbu);
+ if (ret)
+ goto out_power_off;
+
+ /* Only one concurrent atos operation */
+ ret = qsmmuv500_ecats_lock(smmu_domain, tbu, &flags);
+ if (ret)
+ goto out_resume;
+
+ /*
+ * We can be called from an interrupt handler with FSR already set
+ * so terminate the faulting transaction prior to starting ecats.
+ * No new racing faults can occur since we in the halted state.
+ * ECATS can trigger the fault interrupt, so disable it temporarily
+ * and check for an interrupt manually.
+ */
+ fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
+ if (fsr & FSR_FAULT) {
+ writel_relaxed(fsr, cb_base + ARM_SMMU_CB_FSR);
+ writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME);
+ }
+ sctlr_orig = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR);
+ sctlr = sctlr_orig & ~(SCTLR_CFCFG | SCTLR_CFIE);
+ writel_relaxed(sctlr, cb_base + ARM_SMMU_CB_SCTLR);
+
+redo:
+ /* Set address and stream-id */
+ val = readq_relaxed(tbu->base + DEBUG_SID_HALT_REG);
+ val |= sid & DEBUG_SID_HALT_SID_MASK;
+ writeq_relaxed(val, tbu->base + DEBUG_SID_HALT_REG);
+ writeq_relaxed(iova, tbu->base + DEBUG_VA_ADDR_REG);
+
+ /*
+ * Write-back Read and Write-Allocate
+ * Priviledged, nonsecure, data transaction
+ * Read operation.
+ */
+ val = 0xF << DEBUG_TXN_AXCACHE_SHIFT;
+ val |= 0x3 << DEBUG_TXN_AXPROT_SHIFT;
+ val |= DEBUG_TXN_TRIGGER;
+ writeq_relaxed(val, tbu->base + DEBUG_TXN_TRIGG_REG);
+
+ ret = 0;
+ if (readl_poll_timeout_atomic(tbu->base + DEBUG_SR_HALT_ACK_REG,
+ val, !(val & DEBUG_SR_ECATS_RUNNING_VAL),
+ 0, TBU_DBG_TIMEOUT_US)) {
+ dev_err(tbu->dev, "ECATS translation timed out!\n");
+ }
+
+ fsr = readl_relaxed(cb_base + ARM_SMMU_CB_FSR);
+ if (fsr & FSR_FAULT) {
+ dev_err(tbu->dev, "ECATS generated a fault interrupt! FSR = %llx\n",
+ val);
+ ret = -EINVAL;
+
+ writel_relaxed(val, cb_base + ARM_SMMU_CB_FSR);
+ /*
+ * Clear pending interrupts
+ * Barrier required to ensure that the FSR is cleared
+ * before resuming SMMU operation
+ */
+ wmb();
+ writel_relaxed(RESUME_TERMINATE, cb_base + ARM_SMMU_CB_RESUME);
+ }
+
+ val = readq_relaxed(tbu->base + DEBUG_PAR_REG);
+ if (val & DEBUG_PAR_FAULT_VAL) {
+ dev_err(tbu->dev, "ECATS translation failed! PAR = %llx\n",
+ val);
+ ret = -EINVAL;
+ }
+
+ phys = (val >> DEBUG_PAR_PA_SHIFT) & DEBUG_PAR_PA_MASK;
+ if (ret < 0)
+ phys = 0;
+
+ /* Reset hardware */
+ writeq_relaxed(0, tbu->base + DEBUG_TXN_TRIGG_REG);
+ writeq_relaxed(0, tbu->base + DEBUG_VA_ADDR_REG);
+
+ /*
+ * After a failed translation, the next successful translation will
+ * incorrectly be reported as a failure.
+ */
+ if (!phys && needs_redo++ < 2)
+ goto redo;
+
+ writel_relaxed(sctlr_orig, cb_base + ARM_SMMU_CB_SCTLR);
+ qsmmuv500_ecats_unlock(smmu_domain, tbu, &flags);
+
+out_resume:
+ qsmmuv500_tbu_resume(tbu);
+
+out_power_off:
+ arm_smmu_power_off(tbu->pwr);
+
+ return phys;
+}
+
+static phys_addr_t qsmmuv500_iova_to_phys_hard(
+ struct iommu_domain *domain, dma_addr_t iova)
+{
+ u16 sid;
+ struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);
+ struct iommu_fwspec *fwspec;
+
+ /* Select a sid */
+ fwspec = smmu_domain->dev->iommu_fwspec;
+ sid = (u16)fwspec->ids[0];
+
+ return qsmmuv500_iova_to_phys(domain, iova, sid);
+}
+
static int qsmmuv500_tbu_register(struct device *dev, void *data)
{
struct arm_smmu_device *smmu = data;
@@ -4168,16 +4347,26 @@
static int qsmmuv500_arch_init(struct arm_smmu_device *smmu)
{
+ struct resource *res;
struct device *dev = smmu->dev;
- struct list_head *list;
+ struct qsmmuv500_archdata *data;
+ struct platform_device *pdev;
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);
+
+ pdev = container_of(dev, struct platform_device, dev);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tcu-base");
+ data->tcu_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->tcu_base))
+ return PTR_ERR(data->tcu_base);
+
+ data->version = readl_relaxed(data->tcu_base + TCU_HW_VERSION_HLOS1);
+ smmu->archdata = data;
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
if (ret)
@@ -4194,6 +4383,7 @@
struct arm_smmu_arch_ops qsmmuv500_arch_ops = {
.init = qsmmuv500_arch_init,
.device_reset = qsmmuv500_device_reset,
+ .iova_to_phys_hard = qsmmuv500_iova_to_phys_hard,
};
static const struct of_device_id qsmmuv500_tbu_of_match[] = {
@@ -4206,6 +4396,8 @@
struct resource *res;
struct device *dev = &pdev->dev;
struct qsmmuv500_tbu_device *tbu;
+ const __be32 *cell;
+ int len;
tbu = devm_kzalloc(dev, sizeof(*tbu), GFP_KERNEL);
if (!tbu)
@@ -4225,6 +4417,13 @@
if (IS_ERR(tbu->status_reg))
return PTR_ERR(tbu->status_reg);
+ cell = of_get_property(dev->of_node, "qcom,stream-id-range", &len);
+ if (!cell || len < 8)
+ return -EINVAL;
+
+ tbu->sid_start = of_read_number(cell, 1);
+ tbu->num_sids = of_read_number(cell + 1, 1);
+
tbu->pwr = arm_smmu_init_power_resources(pdev);
if (IS_ERR(tbu->pwr))
return PTR_ERR(tbu->pwr);
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/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c
index 01e553c..b045e3b 100644
--- a/drivers/leds/leds-qpnp-flash-v2.c
+++ b/drivers/leds/leds-qpnp-flash-v2.c
@@ -1077,6 +1077,8 @@
pr_err("trigger lmh mitigation failed, rc=%d\n", rc);
return rc;
}
+ /* Wait for LMH mitigation to take effect */
+ udelay(500);
}
if (led->trigger_chgr) {
diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c
index c31d2e1..3060cfa 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -33,6 +33,7 @@
/* ctrl registers */
#define QPNP_WLED_FAULT_STATUS(b) (b + 0x08)
+#define QPNP_WLED_INT_RT_STS(b) (b + 0x10)
#define QPNP_WLED_EN_REG(b) (b + 0x46)
#define QPNP_WLED_FDBK_OP_REG(b) (b + 0x48)
#define QPNP_WLED_VREF_REG(b) (b + 0x49)
@@ -44,6 +45,7 @@
#define QPNP_WLED_SOFTSTART_RAMP_DLY(b) (b + 0x53)
#define QPNP_WLED_VLOOP_COMP_RES_REG(b) (b + 0x55)
#define QPNP_WLED_VLOOP_COMP_GM_REG(b) (b + 0x56)
+#define QPNP_WLED_EN_PSM_REG(b) (b + 0x5A)
#define QPNP_WLED_PSM_CTRL_REG(b) (b + 0x5B)
#define QPNP_WLED_LCD_AUTO_PFM_REG(b) (b + 0x5C)
#define QPNP_WLED_SC_PRO_REG(b) (b + 0x5E)
@@ -82,12 +84,13 @@
#define QPNP_WLED_VREF_PSM_MIN_MV 400
#define QPNP_WLED_VREF_PSM_MAX_MV 750
#define QPNP_WLED_VREF_PSM_DFLT_AMOLED_MV 450
-#define QPNP_WLED_PSM_CTRL_OVERWRITE 0x80
+#define QPNP_WLED_PSM_OVERWRITE_BIT BIT(7)
#define QPNP_WLED_LCD_AUTO_PFM_DFLT_THRESH 1
#define QPNP_WLED_LCD_AUTO_PFM_THRESH_MAX 0xF
#define QPNP_WLED_LCD_AUTO_PFM_EN_SHIFT 7
#define QPNP_WLED_LCD_AUTO_PFM_EN_BIT BIT(7)
#define QPNP_WLED_LCD_AUTO_PFM_THRESH_MASK GENMASK(3, 0)
+#define QPNP_WLED_EN_PSM_BIT BIT(7)
#define QPNP_WLED_ILIM_MASK GENMASK(2, 0)
#define QPNP_WLED_ILIM_OVERWRITE BIT(7)
@@ -117,6 +120,9 @@
QPNP_WLED_TEST4_EN_CLAMP_BIT | \
QPNP_WLED_TEST4_EN_SOFT_START_BIT)
#define QPNP_WLED_TEST4_EN_IIND_UP 0x1
+#define QPNP_WLED_ILIM_FAULT_BIT BIT(0)
+#define QPNP_WLED_OVP_FAULT_BIT BIT(1)
+#define QPNP_WLED_SC_FAULT_BIT BIT(2)
/* sink registers */
#define QPNP_WLED_CURR_SINK_REG(b) (b + 0x46)
@@ -335,6 +341,7 @@
* @ lcd_auto_pfm_thresh - the threshold for lcd auto pfm mode
* @ loop_auto_gm_en - select if auto gm is enabled
* @ lcd_auto_pfm_en - select if auto pfm is enabled in lcd mode
+ * @ lcd_psm_ctrl - select if psm needs to be controlled in lcd mode
* @ avdd_mode_spmi - enable avdd programming via spmi
* @ en_9b_dim_res - enable or disable 9bit dimming
* @ en_phase_stag - enable or disable phase staggering
@@ -380,6 +387,7 @@
u8 lcd_auto_pfm_thresh;
bool loop_auto_gm_en;
bool lcd_auto_pfm_en;
+ bool lcd_psm_ctrl;
bool avdd_mode_spmi;
bool en_9b_dim_res;
bool en_phase_stag;
@@ -549,6 +557,30 @@
return 0;
}
+static int qpnp_wled_psm_config(struct qpnp_wled *wled, bool enable)
+{
+ int rc;
+
+ if (!wled->lcd_psm_ctrl)
+ return 0;
+
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_EN_PSM_REG(wled->ctrl_base),
+ QPNP_WLED_EN_PSM_BIT,
+ enable ? QPNP_WLED_EN_PSM_BIT : 0);
+ if (rc < 0)
+ return rc;
+
+ rc = qpnp_wled_masked_write_reg(wled,
+ QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base),
+ QPNP_WLED_PSM_OVERWRITE_BIT,
+ enable ? QPNP_WLED_PSM_OVERWRITE_BIT : 0);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
static int qpnp_wled_module_en(struct qpnp_wled *wled,
u16 base_addr, bool state)
{
@@ -561,21 +593,31 @@
if (rc < 0)
return rc;
- if (wled->ovp_irq > 0) {
- if (state && wled->ovp_irq_disabled) {
- /*
- * Wait for at least 10ms before enabling OVP fault
- * interrupt after enabling the module so that soft
- * start is completed. Keep OVP interrupt disabled
- * when the module is disabled.
- */
- usleep_range(10000, 11000);
+ /*
+ * Wait for at least 10ms before enabling OVP fault interrupt after
+ * enabling the module so that soft start is completed. Also, this
+ * delay can be used to control PSM during enable when required. Keep
+ * OVP interrupt disabled when the module is disabled.
+ */
+ if (state) {
+ usleep_range(10000, 11000);
+ rc = qpnp_wled_psm_config(wled, false);
+ if (rc < 0)
+ return rc;
+
+ if (wled->ovp_irq > 0 && wled->ovp_irq_disabled) {
enable_irq(wled->ovp_irq);
wled->ovp_irq_disabled = false;
- } else if (!state && !wled->ovp_irq_disabled) {
+ }
+ } else {
+ if (wled->ovp_irq > 0 && !wled->ovp_irq_disabled) {
disable_irq(wled->ovp_irq);
wled->ovp_irq_disabled = true;
}
+
+ rc = qpnp_wled_psm_config(wled, true);
+ if (rc < 0)
+ return rc;
}
return 0;
@@ -990,7 +1032,7 @@
reg &= QPNP_WLED_VREF_PSM_MASK;
reg |= ((wled->vref_psm_mv - QPNP_WLED_VREF_PSM_MIN_MV)/
QPNP_WLED_VREF_PSM_STEP_MV);
- reg |= QPNP_WLED_PSM_CTRL_OVERWRITE;
+ reg |= QPNP_WLED_PSM_OVERWRITE_BIT;
rc = qpnp_wled_write_reg(wled,
QPNP_WLED_PSM_CTRL_REG(wled->ctrl_base), reg);
if (rc)
@@ -1053,16 +1095,25 @@
{
struct qpnp_wled *wled = _wled;
int rc;
- u8 val;
+ u8 fault_sts, int_sts;
rc = qpnp_wled_read_reg(wled,
- QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &val);
+ QPNP_WLED_INT_RT_STS(wled->ctrl_base), &int_sts);
+ if (rc < 0) {
+ pr_err("Error in reading WLED_INT_RT_STS rc=%d\n", rc);
+ return IRQ_HANDLED;
+ }
+
+ rc = qpnp_wled_read_reg(wled,
+ QPNP_WLED_FAULT_STATUS(wled->ctrl_base), &fault_sts);
if (rc < 0) {
pr_err("Error in reading WLED_FAULT_STATUS rc=%d\n", rc);
return IRQ_HANDLED;
}
- pr_err("WLED OVP fault detected, fault_status= %x\n", val);
+ if (fault_sts & (QPNP_WLED_OVP_FAULT_BIT | QPNP_WLED_ILIM_FAULT_BIT))
+ pr_err("WLED OVP fault detected, int_sts=%x fault_sts= %x\n",
+ int_sts, fault_sts);
return IRQ_HANDLED;
}
@@ -1677,6 +1728,8 @@
wled->ovp_irq, rc);
return rc;
}
+ disable_irq(wled->ovp_irq);
+ wled->ovp_irq_disabled = true;
}
if (wled->sc_irq >= 0) {
@@ -2063,6 +2116,8 @@
wled->en_ext_pfet_sc_pro = of_property_read_bool(pdev->dev.of_node,
"qcom,en-ext-pfet-sc-pro");
+ wled->lcd_psm_ctrl = of_property_read_bool(pdev->dev.of_node,
+ "qcom,lcd-psm-ctrl");
return 0;
}
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index 85a6be8..817dfa3 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -897,9 +897,10 @@
}
}
- if (led->mpp_cfg->pwm_mode != MANUAL_MODE)
+ if (led->mpp_cfg->pwm_mode != MANUAL_MODE) {
pwm_enable(led->mpp_cfg->pwm_cfg->pwm_dev);
- else {
+ led->mpp_cfg->pwm_cfg->pwm_enabled = 1;
+ } else {
if (led->cdev.brightness < LED_MPP_CURRENT_MIN)
led->cdev.brightness = LED_MPP_CURRENT_MIN;
else {
@@ -950,6 +951,7 @@
led->mpp_cfg->pwm_mode =
led->mpp_cfg->pwm_cfg->default_mode;
pwm_disable(led->mpp_cfg->pwm_cfg->pwm_dev);
+ led->mpp_cfg->pwm_cfg->pwm_enabled = 0;
}
rc = qpnp_led_masked_write(led,
LED_MPP_MODE_CTRL(led->base),
@@ -1606,7 +1608,7 @@
dev_err(&led->pdev->dev, "pwm enable failed\n");
return rc;
}
-
+ led->kpdbl_cfg->pwm_cfg->pwm_enabled = 1;
set_bit(led->kpdbl_cfg->row_id, kpdbl_leds_in_use);
/* is_kpdbl_master_turn_on will be set to true when GPLED1
@@ -1642,6 +1644,7 @@
"pwm enable failed\n");
return rc;
}
+ led->kpdbl_cfg->pwm_cfg->pwm_enabled = 1;
} else {
if (kpdbl_master) {
pwm_disable(kpdbl_master);
@@ -1660,6 +1663,7 @@
is_kpdbl_master_turn_on = false;
} else {
pwm_disable(led->kpdbl_cfg->pwm_cfg->pwm_dev);
+ led->kpdbl_cfg->pwm_cfg->pwm_enabled = 0;
clear_bit(led->kpdbl_cfg->row_id, kpdbl_leds_in_use);
if (bitmap_weight(kpdbl_leds_in_use,
NUM_KPDBL_LEDS) == 1 && kpdbl_master &&
@@ -1727,20 +1731,17 @@
"Failed to write led enable reg\n");
return rc;
}
-
+ if (!led->rgb_cfg->pwm_cfg->pwm_enabled) {
+ pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
+ led->rgb_cfg->pwm_cfg->pwm_enabled = 1;
+ }
+ } else {
+ led->rgb_cfg->pwm_cfg->mode =
+ led->rgb_cfg->pwm_cfg->default_mode;
if (led->rgb_cfg->pwm_cfg->pwm_enabled) {
pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
led->rgb_cfg->pwm_cfg->pwm_enabled = 0;
}
-
- rc = pwm_enable(led->rgb_cfg->pwm_cfg->pwm_dev);
- if (!rc)
- led->rgb_cfg->pwm_cfg->pwm_enabled = 1;
- } else {
- led->rgb_cfg->pwm_cfg->mode =
- led->rgb_cfg->pwm_cfg->default_mode;
- pwm_disable(led->rgb_cfg->pwm_cfg->pwm_dev);
- led->rgb_cfg->pwm_cfg->pwm_enabled = 0;
rc = qpnp_led_masked_write(led,
RGB_LED_EN_CTL(led->base),
led->rgb_cfg->enable, RGB_LED_DISABLE);
@@ -2183,11 +2184,17 @@
previous_pwm_us = pwm_cfg->pwm_period_us;
pwm_cfg->pwm_period_us = pwm_us;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
if (ret) {
pwm_cfg->pwm_period_us = previous_pwm_us;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
qpnp_led_set(&led->cdev, led->cdev.brightness);
dev_err(&led->pdev->dev,
@@ -2237,12 +2244,18 @@
previous_pause_lo = pwm_cfg->lut_params.lut_pause_lo;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
pwm_cfg->lut_params.lut_pause_lo = pause_lo;
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
if (ret) {
pwm_cfg->lut_params.lut_pause_lo = previous_pause_lo;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
qpnp_led_set(&led->cdev, led->cdev.brightness);
dev_err(&led->pdev->dev,
@@ -2292,12 +2305,18 @@
previous_pause_hi = pwm_cfg->lut_params.lut_pause_hi;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
pwm_cfg->lut_params.lut_pause_hi = pause_hi;
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
if (ret) {
pwm_cfg->lut_params.lut_pause_hi = previous_pause_hi;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
qpnp_led_set(&led->cdev, led->cdev.brightness);
dev_err(&led->pdev->dev,
@@ -2348,12 +2367,18 @@
previous_start_idx = pwm_cfg->duty_cycles->start_idx;
pwm_cfg->duty_cycles->start_idx = start_idx;
pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
if (ret) {
pwm_cfg->duty_cycles->start_idx = previous_start_idx;
pwm_cfg->lut_params.start_idx = pwm_cfg->duty_cycles->start_idx;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
qpnp_led_set(&led->cdev, led->cdev.brightness);
dev_err(&led->pdev->dev,
@@ -2403,12 +2428,18 @@
previous_ramp_step_ms = pwm_cfg->lut_params.ramp_step_ms;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
pwm_cfg->lut_params.ramp_step_ms = ramp_step_ms;
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
if (ret) {
pwm_cfg->lut_params.ramp_step_ms = previous_ramp_step_ms;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
qpnp_led_set(&led->cdev, led->cdev.brightness);
dev_err(&led->pdev->dev,
@@ -2458,12 +2489,18 @@
previous_lut_flags = pwm_cfg->lut_params.flags;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
pwm_cfg->lut_params.flags = lut_flags;
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
if (ret) {
pwm_cfg->lut_params.flags = previous_lut_flags;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
qpnp_led_set(&led->cdev, led->cdev.brightness);
dev_err(&led->pdev->dev,
@@ -2543,7 +2580,11 @@
pwm_cfg->old_duty_pcts = previous_duty_pcts;
pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
+
ret = qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
if (ret)
goto restore;
@@ -2558,7 +2599,10 @@
pwm_cfg->old_duty_pcts = pwm_cfg->duty_cycles->duty_pcts;
pwm_cfg->duty_cycles->duty_pcts = previous_duty_pcts;
pwm_cfg->lut_params.idx_len = pwm_cfg->duty_cycles->num_duty_pcts;
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
qpnp_led_set(&led->cdev, led->cdev.brightness);
return ret;
@@ -2588,7 +2632,10 @@
led->kpdbl_cfg->pwm_mode =
pwm_cfg->default_mode;
}
- pwm_free(pwm_cfg->pwm_dev);
+ if (pwm_cfg->pwm_enabled) {
+ pwm_disable(pwm_cfg->pwm_dev);
+ pwm_cfg->pwm_enabled = 0;
+ }
qpnp_pwm_init(pwm_cfg, led->pdev, led->cdev.name);
if (led->id == QPNP_ID_RGB_RED || led->id == QPNP_ID_RGB_GREEN
|| led->id == QPNP_ID_RGB_BLUE) {
@@ -3541,8 +3588,11 @@
}
rc = qpnp_get_config_pwm(led->kpdbl_cfg->pwm_cfg, led->pdev, node);
- if (rc < 0)
+ if (rc < 0) {
+ if (led->kpdbl_cfg->pwm_cfg->pwm_dev)
+ pwm_put(led->kpdbl_cfg->pwm_cfg->pwm_dev);
return rc;
+ }
rc = of_property_read_u32(node, "qcom,row-id", &val);
if (!rc)
@@ -3605,8 +3655,11 @@
}
rc = qpnp_get_config_pwm(led->rgb_cfg->pwm_cfg, led->pdev, node);
- if (rc < 0)
+ if (rc < 0) {
+ if (led->rgb_cfg->pwm_cfg->pwm_dev)
+ pwm_put(led->rgb_cfg->pwm_cfg->pwm_dev);
return rc;
+ }
return 0;
}
@@ -3729,8 +3782,11 @@
}
rc = qpnp_get_config_pwm(led->mpp_cfg->pwm_cfg, led->pdev, node);
- if (rc < 0)
+ if (rc < 0) {
+ if (led->mpp_cfg->pwm_cfg && led->mpp_cfg->pwm_cfg->pwm_dev)
+ pwm_put(led->mpp_cfg->pwm_cfg->pwm_dev);
goto err_config_mpp;
+ }
return 0;
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..1c73c5a2 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;
@@ -333,6 +334,7 @@
u32 irq_status, sts;
struct tcs_mbox *tcs;
struct tcs_response *resp;
+ struct tcs_cmd *cmd;
u32 irq_clear = 0;
u32 data;
@@ -352,28 +354,20 @@
cancel_delayed_work(&resp->dwork);
- /* Clear the AMC mode for non-ACTIVE TCSes */
tcs = get_tcs_from_index(drv, m);
if (!tcs) {
pr_err("TCS-%d doesn't exist in DRV\n", m);
continue;
}
- if (tcs->type != ACTIVE_TCS) {
- data = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
- data &= ~TCS_AMC_MODE_ENABLE;
- write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, data);
- } else {
- /* Clear the enable bit for the commands */
- write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
- }
/* Check if all commands were completed */
resp->err = 0;
for (i = 0; i < resp->msg->num_payload; i++) {
+ cmd = &resp->msg->payload[i];
sts = read_tcs_reg(base, TCS_DRV_CMD_STATUS, m, i);
- if (!(sts & CMD_STATUS_ISSUED) ||
- (resp->msg->is_complete &&
- !(sts & CMD_STATUS_COMPL)))
+ if ((!(sts & CMD_STATUS_ISSUED)) ||
+ ((resp->msg->is_complete || cmd->complete) &&
+ (!(sts & CMD_STATUS_COMPL))))
resp->err = -EIO;
}
@@ -385,7 +379,18 @@
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);
+
+ /* Clear the AMC mode for non-ACTIVE TCSes */
+ if (tcs->type != ACTIVE_TCS) {
+ data = read_tcs_reg(base, TCS_DRV_CONTROL, m, 0);
+ data &= ~TCS_AMC_MODE_ENABLE;
+ write_tcs_reg(base, TCS_DRV_CONTROL, m, 0, data);
+ } else {
+ /* Clear the enable bit for the commands */
+ write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
+ }
/* Notify the client that this request is completed. */
send_tcs_response(resp);
@@ -401,7 +406,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,15 +474,16 @@
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;
+ u32 msgid, cmd_msgid = 0;
u32 cmd_enable = 0;
u32 cmd_complete;
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;
@@ -489,11 +497,13 @@
cmd = &msg->payload[i];
cmd_enable |= BIT(n + i);
cmd_complete |= cmd->complete << (n + i);
- write_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n + i, cmd_msgid);
+ msgid = cmd_msgid;
+ msgid |= (cmd->complete) ? CMD_MSGID_RESP_REQ : 0;
+ write_tcs_reg(base, TCS_DRV_CMD_MSGID, m, n + i, 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, msgid, cmd->addr,
+ cmd->data, cmd->complete, trigger);
}
/* Write the send-after-prev completion bits for the batch */
@@ -716,7 +726,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)
@@ -727,6 +737,41 @@
return 0;
}
+static void __tcs_buffer_invalidate(void __iomem *base, int m)
+{
+ write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
+}
+
+static int tcs_mbox_invalidate(struct mbox_chan *chan)
+{
+ struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
+ struct tcs_mbox *tcs;
+ int m, i;
+ int inv_types[] = { WAKE_TCS, SLEEP_TCS };
+ int type = 0;
+
+ do {
+ tcs = get_tcs_of_type(drv, inv_types[type]);
+ if (IS_ERR(tcs))
+ return PTR_ERR(tcs);
+
+ spin_lock(&tcs->tcs_lock);
+ for (i = 0; i < tcs->num_tcs; i++) {
+ m = i + tcs->tcs_offset;
+ spin_lock(&tcs->tcs_m_lock[i]);
+ while (!tcs_is_free(drv->reg_base, m))
+ cpu_relax();
+ __tcs_buffer_invalidate(drv->reg_base, m);
+ spin_unlock(&tcs->tcs_m_lock[i]);
+ }
+ /* Mark the TCS as free */
+ bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
+ spin_unlock(&tcs->tcs_lock);
+ } while (++type < ARRAY_SIZE(inv_types));
+
+ return 0;
+}
+
/**
* chan_tcs_write: Validate the incoming message and write to the
* appropriate TCS block.
@@ -771,6 +816,13 @@
goto tx_fail;
}
+ /*
+ * Since we are re-purposing the wake TCS, invalidate previous
+ * contents to avoid confusion.
+ */
+ if (msg->state == RPMH_AWAKE_STATE)
+ tcs_mbox_invalidate(chan);
+
/* Post the message to the TCS and trigger */
ret = tcs_mbox_write(chan, msg, true);
@@ -791,50 +843,16 @@
return 0;
}
-static void __tcs_buffer_invalidate(void __iomem *base, int m)
-{
- write_tcs_reg(base, TCS_DRV_CMD_ENABLE, m, 0, 0);
-}
-
-static int tcs_mbox_invalidate(struct mbox_chan *chan)
-{
- struct tcs_drv *drv = container_of(chan->mbox, struct tcs_drv, mbox);
- struct tcs_mbox *tcs;
- int m, i;
- int inv_types[] = { WAKE_TCS, SLEEP_TCS };
- int type = 0;
-
- do {
- tcs = get_tcs_of_type(drv, inv_types[type]);
- if (IS_ERR(tcs))
- return PTR_ERR(tcs);
-
- spin_lock(&tcs->tcs_lock);
- for (i = 0; i < tcs->num_tcs; i++) {
- m = i + tcs->tcs_offset;
- spin_lock(&tcs->tcs_m_lock[i]);
- while (!tcs_is_free(drv->reg_base, m))
- cpu_relax();
- __tcs_buffer_invalidate(drv->reg_base, m);
- spin_unlock(&tcs->tcs_m_lock[i]);
- }
- /* Mark the TCS as free */
- bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
- spin_unlock(&tcs->tcs_lock);
- } while (++type < ARRAY_SIZE(inv_types));
-
- 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 +873,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;
@@ -949,6 +967,7 @@
u32 config, max_tcs, ncpt;
int tcs_type_count[TCS_TYPE_NR] = { 0 };
struct resource *res;
+ u32 irq_mask;
drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
if (!drv)
@@ -1073,6 +1092,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;
@@ -1088,9 +1111,14 @@
if (ret)
return ret;
- /* Enable interrupts for AMC TCS */
- write_tcs_reg(drv->reg_base, TCS_DRV_IRQ_ENABLE, 0, 0,
- drv->tcs[ACTIVE_TCS].tcs_mask);
+ /*
+ * Enable interrupts for AMC TCS,
+ * if there are no AMC TCS, use wake TCS.
+ */
+ irq_mask = (drv->tcs[ACTIVE_TCS].num_tcs) ?
+ drv->tcs[ACTIVE_TCS].tcs_mask :
+ drv->tcs[WAKE_TCS].tcs_mask;
+ write_tcs_reg(drv->reg_base, TCS_DRV_IRQ_ENABLE, 0, 0, irq_mask);
ret = mbox_controller_register(&drv->mbox);
if (ret)
diff --git a/drivers/media/platform/msm/camera/Makefile b/drivers/media/platform/msm/camera/Makefile
index faba819..c897669 100644
--- a/drivers/media/platform/msm/camera/Makefile
+++ b/drivers/media/platform/msm/camera/Makefile
@@ -1,5 +1,4 @@
-ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr
-
obj-$(CONFIG_SPECTRA_CAMERA) += cam_req_mgr/
obj-$(CONFIG_SPECTRA_CAMERA) += cam_utils/
-
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_core/
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync/
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_sync/Makefile b/drivers/media/platform/msm/camera/cam_sync/Makefile
new file mode 100644
index 0000000..e3012cb
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync.o cam_sync_util.o
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
new file mode 100644
index 0000000..a736148
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -0,0 +1,1024 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "CAM-SYNC %s:%d " fmt, __func__, __LINE__
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/irqflags.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include "cam_sync_util.h"
+
+struct sync_device *sync_dev;
+
+int cam_sync_create(int32_t *sync_obj, const char *name)
+{
+ int rc;
+ long idx;
+
+ do {
+ idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
+ if (idx >= CAM_SYNC_MAX_OBJS)
+ return -ENOMEM;
+ } while (!spin_trylock_bh(&sync_dev->row_spinlocks[idx]));
+
+ rc = cam_sync_init_object(sync_dev->sync_table, idx, name);
+ if (rc) {
+ pr_err("Error: Unable to init row at idx = %ld\n", idx);
+ spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+ return -EINVAL;
+ }
+
+ set_bit(idx, sync_dev->bitmap);
+ *sync_obj = idx;
+ spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+
+ return rc;
+}
+
+int cam_sync_register_callback(sync_callback cb_func,
+ void *userdata, int32_t sync_obj)
+{
+ struct sync_callback_info *sync_cb;
+ struct sync_callback_info *cb_info;
+ struct sync_callback_info *temp_cb;
+ struct sync_table_row *row = NULL;
+
+ if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0 || !cb_func)
+ return -EINVAL;
+
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ row = sync_dev->sync_table + sync_obj;
+
+ if (row->state == CAM_SYNC_STATE_INVALID) {
+ pr_err("Error: accessing an uninitialized sync obj %d\n",
+ sync_obj);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return -EINVAL;
+ }
+
+ sync_cb = kzalloc(sizeof(*sync_cb), GFP_ATOMIC);
+ if (!sync_cb) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return -ENOMEM;
+ }
+
+ /* Trigger callback if sync object is already in SIGNALED state */
+ if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
+ row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
+ sync_cb->callback_func = cb_func;
+ sync_cb->cb_data = userdata;
+ sync_cb->sync_obj = sync_obj;
+ INIT_WORK(&sync_cb->cb_dispatch_work,
+ cam_sync_util_cb_dispatch);
+
+ sync_cb->status = row->state;
+ queue_work(sync_dev->work_queue,
+ &sync_cb->cb_dispatch_work);
+
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return 0;
+ }
+
+ /* Don't register if callback was registered earlier */
+ list_for_each_entry_safe(cb_info, temp_cb, &row->callback_list, list) {
+ if (cb_info->callback_func == cb_func &&
+ cb_info->cb_data == userdata) {
+ kfree(sync_cb);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return -EALREADY;
+ }
+ }
+
+ sync_cb->callback_func = cb_func;
+ sync_cb->cb_data = userdata;
+ sync_cb->sync_obj = sync_obj;
+ INIT_WORK(&sync_cb->cb_dispatch_work, cam_sync_util_cb_dispatch);
+ list_add_tail(&sync_cb->list, &row->callback_list);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+
+ return 0;
+}
+
+int cam_sync_deregister_callback(sync_callback cb_func,
+ void *userdata, int32_t sync_obj)
+{
+ struct sync_table_row *row = NULL;
+ struct sync_callback_info *sync_cb, *temp;
+
+ if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+ return -EINVAL;
+
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ row = sync_dev->sync_table + sync_obj;
+
+ if (row->state == CAM_SYNC_STATE_INVALID) {
+ pr_err("Error: accessing an uninitialized sync obj = %d\n",
+ sync_obj);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return -EINVAL;
+ }
+
+ list_for_each_entry_safe(sync_cb, temp, &row->callback_list, list) {
+ if (sync_cb->callback_func == cb_func &&
+ sync_cb->cb_data == userdata) {
+ list_del_init(&sync_cb->list);
+ kfree(sync_cb);
+ }
+ }
+
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return 0;
+}
+
+int cam_sync_signal(int32_t sync_obj, uint32_t status)
+{
+ int rc;
+ struct sync_table_row *row = NULL;
+ struct sync_table_row *parent_row = NULL;
+ struct sync_callback_info *sync_cb;
+ struct sync_user_payload *payload_info;
+ struct sync_parent_info *parent_info;
+ struct list_head sync_list;
+ struct cam_signalable_info *list_info = NULL;
+ struct cam_signalable_info *temp_list_info = NULL;
+
+ /* Objects to be signaled will be added into this list */
+ INIT_LIST_HEAD(&sync_list);
+
+ if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+ return -EINVAL;
+
+ row = sync_dev->sync_table + sync_obj;
+ if (row->state == CAM_SYNC_STATE_INVALID) {
+ pr_err("Error: accessing an uninitialized sync obj = %d\n",
+ sync_obj);
+ return -EINVAL;
+ }
+
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ if (row->type == CAM_SYNC_TYPE_GROUP) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ pr_err("Error: Signaling a GROUP sync object = %d\n",
+ sync_obj);
+ return -EINVAL;
+ }
+
+ if (row->state != CAM_SYNC_STATE_ACTIVE) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ pr_err("Error: Sync object already signaled sync_obj = %d",
+ sync_obj);
+ return -EALREADY;
+ }
+
+ if (status != CAM_SYNC_STATE_SIGNALED_SUCCESS &&
+ status != CAM_SYNC_STATE_SIGNALED_ERROR) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ pr_err("Error: signaling with undefined status = %d\n",
+ status);
+ return -EINVAL;
+ }
+
+ row->state = status;
+ rc = cam_sync_util_add_to_signalable_list(sync_obj, status, &sync_list);
+ if (rc < 0) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return rc;
+ }
+
+ /*
+ * Now iterate over all parents of this object and if they too need to
+ * be signaled add them to the list
+ */
+ list_for_each_entry(parent_info,
+ &row->parents_list,
+ list) {
+ parent_row = sync_dev->sync_table + parent_info->sync_id;
+ spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
+ parent_row->remaining--;
+
+ parent_row->state = cam_sync_util_get_state(
+ parent_row->state,
+ status);
+
+ if (!parent_row->remaining) {
+ rc = cam_sync_util_add_to_signalable_list
+ (parent_info->sync_id,
+ parent_row->state,
+ &sync_list);
+ if (rc < 0) {
+ spin_unlock_bh(
+ &sync_dev->row_spinlocks[
+ parent_info->sync_id]);
+ return rc;
+ }
+ }
+ spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
+ }
+
+ /*
+ * Now dispatch the various sync objects collected so far, in our
+ * list
+ */
+ list_for_each_entry_safe(list_info,
+ temp_list_info,
+ &sync_list,
+ list) {
+ struct sync_table_row *signalable_row = NULL;
+ struct sync_callback_info *temp_sync_cb;
+ struct sync_user_payload *temp_payload_info;
+
+ signalable_row = sync_dev->sync_table + list_info->sync_obj;
+ /* Dispatch kernel callbacks if any were registered earlier */
+ list_for_each_entry_safe(sync_cb,
+ temp_sync_cb, &signalable_row->callback_list, list) {
+ sync_cb->status = list_info->status;
+ queue_work(sync_dev->work_queue,
+ &sync_cb->cb_dispatch_work);
+ list_del_init(&sync_cb->list);
+ }
+
+ /* Dispatch user payloads if any were registered earlier */
+ list_for_each_entry_safe(payload_info, temp_payload_info,
+ &signalable_row->user_payload_list, list) {
+ spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
+ if (!sync_dev->cam_sync_eventq) {
+ spin_unlock_bh(
+ &sync_dev->cam_sync_eventq_lock);
+ break;
+ }
+ spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
+ cam_sync_util_send_v4l2_event(
+ CAM_SYNC_V4L_EVENT_ID_CB_TRIG,
+ list_info->sync_obj,
+ list_info->status,
+ payload_info->payload_data,
+ CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64));
+
+ list_del_init(&payload_info->list);
+ /*
+ * We can free the list node here because
+ * sending V4L event will make a deep copy
+ * anyway
+ */
+ kfree(payload_info);
+ }
+
+ /*
+ * This needs to be done because we want to unblock anyone
+ * who might be blocked and waiting on this sync object
+ */
+ complete_all(&signalable_row->signaled);
+
+ list_del_init(&list_info->list);
+ kfree(list_info);
+ }
+
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+
+ return rc;
+}
+
+int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj)
+{
+ int rc;
+ long idx = 0;
+
+ rc = cam_sync_util_validate_merge(sync_obj,
+ num_objs);
+ if (rc < 0) {
+ pr_err("Validation failed, Merge not allowed");
+ return -EINVAL;
+ }
+
+ rc = cam_sync_util_find_and_set_empty_row(sync_dev, &idx);
+ if (rc < 0) {
+ pr_err("Error: Unable to find empty row, table full");
+ return -EINVAL;
+ }
+
+ if (idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) {
+ pr_err("Error: Invalid empty row index returned = %ld", idx);
+ return -EINVAL;
+ }
+
+ rc = cam_sync_init_group_object(sync_dev->sync_table,
+ idx, sync_obj,
+ num_objs);
+
+ if (rc < 0) {
+ pr_err("Error: Unable to init row at idx = %ld\n", idx);
+ return -EINVAL;
+ }
+
+ *merged_obj = idx;
+
+ return 0;
+}
+
+int cam_sync_destroy(int32_t sync_obj)
+{
+ struct sync_table_row *row = NULL;
+
+ if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+ return -EINVAL;
+
+ row = sync_dev->sync_table + sync_obj;
+ if (row->state == CAM_SYNC_STATE_INVALID) {
+ pr_err("Error: accessing an uninitialized sync obj: idx = %d\n",
+ sync_obj);
+ return -EINVAL;
+ }
+
+ cam_sync_deinit_object(sync_dev->sync_table, sync_obj);
+ return 0;
+}
+
+int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms)
+{
+ unsigned long timeleft;
+ int rc = -EINVAL;
+ struct sync_table_row *row = NULL;
+
+ if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+ return -EINVAL;
+
+ row = sync_dev->sync_table + sync_obj;
+
+ if (row->state == CAM_SYNC_STATE_INVALID) {
+ pr_err("Error: accessing an uninitialized sync obj = %d\n",
+ sync_obj);
+ return -EINVAL;
+ }
+
+ timeleft = wait_for_completion_timeout(&row->signaled,
+ msecs_to_jiffies(timeout_ms));
+
+ if (!timeleft) {
+ pr_err("Error: cam_sync_wait() timed out for sync obj = %d\n",
+ sync_obj);
+ rc = -ETIMEDOUT;
+ } else {
+ switch (row->state) {
+ case CAM_SYNC_STATE_INVALID:
+ case CAM_SYNC_STATE_ACTIVE:
+ case CAM_SYNC_STATE_SIGNALED_ERROR:
+ pr_err("Error: Wait on invalid state = %d, obj = %d\n",
+ row->state, sync_obj);
+ rc = -EINVAL;
+ break;
+ case CAM_SYNC_STATE_SIGNALED_SUCCESS:
+ rc = 0;
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl)
+{
+ struct cam_sync_info sync_create;
+ int result;
+
+ if (k_ioctl->size != sizeof(struct cam_sync_info))
+ return -EINVAL;
+
+ if (!k_ioctl->ioctl_ptr)
+ return -EINVAL;
+
+ if (copy_from_user(&sync_create,
+ (void *)k_ioctl->ioctl_ptr,
+ k_ioctl->size))
+ return -EFAULT;
+
+ result = cam_sync_create(&sync_create.sync_obj,
+ sync_create.name);
+
+ if (!result)
+ if (copy_to_user((void *)k_ioctl->ioctl_ptr,
+ &sync_create,
+ k_ioctl->size))
+ return -EFAULT;
+
+ return result;
+}
+
+static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl)
+{
+ struct cam_sync_signal sync_signal;
+
+ if (k_ioctl->size != sizeof(struct cam_sync_signal))
+ return -EINVAL;
+
+ if (!k_ioctl->ioctl_ptr)
+ return -EINVAL;
+
+ if (copy_from_user(&sync_signal,
+ (void *)k_ioctl->ioctl_ptr,
+ k_ioctl->size))
+ return -EFAULT;
+
+ return cam_sync_signal(sync_signal.sync_obj,
+ sync_signal.sync_state);
+}
+
+static int cam_sync_handle_merge(struct cam_private_ioctl_arg *k_ioctl)
+{
+ struct cam_sync_merge sync_merge;
+ uint32_t *sync_objs;
+ uint32_t num_objs;
+ uint32_t size;
+ int result;
+
+ if (k_ioctl->size != sizeof(struct cam_sync_merge))
+ return -EINVAL;
+
+ if (!k_ioctl->ioctl_ptr)
+ return -EINVAL;
+
+ if (copy_from_user(&sync_merge,
+ (void *)k_ioctl->ioctl_ptr,
+ k_ioctl->size))
+ return -EFAULT;
+
+ if (sync_merge.num_objs >= CAM_SYNC_MAX_OBJS)
+ return -EINVAL;
+
+ size = sizeof(uint32_t) * sync_merge.num_objs;
+ sync_objs = kzalloc(size, GFP_ATOMIC);
+
+ if (!sync_objs)
+ return -ENOMEM;
+
+ if (copy_from_user(sync_objs,
+ (void *)sync_merge.sync_objs,
+ sizeof(uint32_t) * sync_merge.num_objs)) {
+ kfree(sync_objs);
+ return -EFAULT;
+ }
+
+ num_objs = sync_merge.num_objs;
+
+ result = cam_sync_merge(sync_objs,
+ num_objs,
+ &sync_merge.merged);
+
+ if (!result)
+ if (copy_to_user((void *)k_ioctl->ioctl_ptr,
+ &sync_merge,
+ k_ioctl->size)) {
+ kfree(sync_objs);
+ return -EFAULT;
+ }
+
+ kfree(sync_objs);
+
+ return result;
+}
+
+static int cam_sync_handle_wait(struct cam_private_ioctl_arg *k_ioctl)
+{
+ struct cam_sync_wait sync_wait;
+
+ if (k_ioctl->size != sizeof(struct cam_sync_wait))
+ return -EINVAL;
+
+ if (!k_ioctl->ioctl_ptr)
+ return -EINVAL;
+
+ if (copy_from_user(&sync_wait,
+ (void *)k_ioctl->ioctl_ptr,
+ k_ioctl->size))
+ return -EFAULT;
+
+ k_ioctl->result = cam_sync_wait(sync_wait.sync_obj,
+ sync_wait.timeout_ms);
+
+ return 0;
+}
+
+static int cam_sync_handle_destroy(struct cam_private_ioctl_arg *k_ioctl)
+{
+ struct cam_sync_info sync_create;
+
+ if (k_ioctl->size != sizeof(struct cam_sync_info))
+ return -EINVAL;
+
+ if (!k_ioctl->ioctl_ptr)
+ return -EINVAL;
+
+ if (copy_from_user(&sync_create,
+ (void *)k_ioctl->ioctl_ptr,
+ k_ioctl->size))
+ return -EFAULT;
+
+ return cam_sync_destroy(sync_create.sync_obj);
+}
+
+static int cam_sync_handle_register_user_payload(
+ struct cam_private_ioctl_arg *k_ioctl)
+{
+ struct cam_sync_userpayload_info userpayload_info;
+ struct sync_user_payload *user_payload_kernel;
+ struct sync_user_payload *user_payload_iter;
+ struct sync_user_payload *temp_upayload_kernel;
+ uint32_t sync_obj;
+ struct sync_table_row *row = NULL;
+
+ if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info))
+ return -EINVAL;
+
+ if (!k_ioctl->ioctl_ptr)
+ return -EINVAL;
+
+ if (copy_from_user(&userpayload_info,
+ (void *)k_ioctl->ioctl_ptr,
+ k_ioctl->size))
+ return -EFAULT;
+
+ sync_obj = userpayload_info.sync_obj;
+ if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+ return -EINVAL;
+
+ user_payload_kernel = kzalloc(sizeof(*user_payload_kernel), GFP_KERNEL);
+ if (!user_payload_kernel)
+ return -ENOMEM;
+
+ memcpy(user_payload_kernel->payload_data,
+ userpayload_info.payload,
+ CAM_SYNC_PAYLOAD_WORDS * sizeof(__u64));
+
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ row = sync_dev->sync_table + sync_obj;
+
+ if (row->state == CAM_SYNC_STATE_INVALID) {
+ pr_err("Error: accessing an uninitialized sync obj = %d\n",
+ sync_obj);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ kfree(user_payload_kernel);
+ return -EINVAL;
+ }
+
+ if (row->state == CAM_SYNC_STATE_SIGNALED_SUCCESS ||
+ row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
+
+ cam_sync_util_send_v4l2_event(CAM_SYNC_V4L_EVENT_ID_CB_TRIG,
+ sync_obj,
+ row->state,
+ user_payload_kernel->payload_data,
+ CAM_SYNC_USER_PAYLOAD_SIZE * sizeof(__u64));
+
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ kfree(user_payload_kernel);
+ return 0;
+ }
+
+ list_for_each_entry_safe(user_payload_iter,
+ temp_upayload_kernel,
+ &row->user_payload_list,
+ list) {
+ if (user_payload_iter->payload_data[0] ==
+ user_payload_kernel->payload_data[0] &&
+ user_payload_iter->payload_data[1] ==
+ user_payload_kernel->payload_data[1]) {
+
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ kfree(user_payload_kernel);
+ return -EALREADY;
+ }
+ }
+
+ list_add_tail(&user_payload_kernel->list, &row->user_payload_list);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return 0;
+}
+
+static int cam_sync_handle_deregister_user_payload(
+ struct cam_private_ioctl_arg *k_ioctl)
+{
+ struct cam_sync_userpayload_info userpayload_info;
+ struct sync_user_payload *user_payload_kernel, *temp;
+ uint32_t sync_obj;
+ struct sync_table_row *row = NULL;
+
+ if (k_ioctl->size != sizeof(struct cam_sync_userpayload_info)) {
+ CDBG("Incorrect ioctl size\n");
+ return -EINVAL;
+ }
+
+ if (!k_ioctl->ioctl_ptr) {
+ CDBG("Invalid embedded ioctl ptr\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&userpayload_info,
+ (void *)k_ioctl->ioctl_ptr,
+ k_ioctl->size))
+ return -EFAULT;
+
+ sync_obj = userpayload_info.sync_obj;
+ if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0)
+ return -EINVAL;
+
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ row = sync_dev->sync_table + sync_obj;
+
+ if (row->state == CAM_SYNC_STATE_INVALID) {
+ pr_err("Error: accessing an uninitialized sync obj = %d\n",
+ sync_obj);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return -EINVAL;
+ }
+
+ list_for_each_entry_safe(user_payload_kernel, temp,
+ &row->user_payload_list, list) {
+ if (user_payload_kernel->payload_data[0] ==
+ userpayload_info.payload[0] &&
+ user_payload_kernel->payload_data[1] ==
+ userpayload_info.payload[1]) {
+ list_del_init(&user_payload_kernel->list);
+ kfree(user_payload_kernel);
+ }
+ }
+
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
+ return 0;
+}
+
+static long cam_sync_dev_ioctl(struct file *filep, void *fh,
+ bool valid_prio, unsigned int cmd, void *arg)
+{
+ int32_t rc;
+ struct sync_device *sync_dev = video_drvdata(filep);
+ struct cam_private_ioctl_arg k_ioctl;
+
+ if (!sync_dev) {
+ pr_err("%s sync_dev NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!arg)
+ return -EINVAL;
+
+ if (cmd != CAM_PRIVATE_IOCTL_CMD)
+ return -ENOIOCTLCMD;
+
+ k_ioctl = *(struct cam_private_ioctl_arg *)arg;
+
+ switch (k_ioctl.id) {
+ case CAM_SYNC_CREATE:
+ rc = cam_sync_handle_create(&k_ioctl);
+ break;
+ case CAM_SYNC_DESTROY:
+ rc = cam_sync_handle_destroy(&k_ioctl);
+ break;
+ case CAM_SYNC_REGISTER_PAYLOAD:
+ rc = cam_sync_handle_register_user_payload(
+ &k_ioctl);
+ break;
+ case CAM_SYNC_DEREGISTER_PAYLOAD:
+ rc = cam_sync_handle_deregister_user_payload(
+ &k_ioctl);
+ break;
+ case CAM_SYNC_SIGNAL:
+ rc = cam_sync_handle_signal(&k_ioctl);
+ break;
+ case CAM_SYNC_MERGE:
+ rc = cam_sync_handle_merge(&k_ioctl);
+ break;
+ case CAM_SYNC_WAIT:
+ rc = cam_sync_handle_wait(&k_ioctl);
+ ((struct cam_private_ioctl_arg *)arg)->result =
+ k_ioctl.result;
+ break;
+ default:
+ rc = -ENOIOCTLCMD;
+ }
+
+ return rc;
+}
+
+static unsigned int cam_sync_poll(struct file *f,
+ struct poll_table_struct *pll_table)
+{
+ int rc = 0;
+ struct v4l2_fh *eventq = f->private_data;
+
+ if (!eventq)
+ return -EINVAL;
+
+ poll_wait(f, &eventq->wait, pll_table);
+
+ if (v4l2_event_pending(eventq))
+ rc = POLLPRI;
+
+ return rc;
+}
+
+static int cam_sync_open(struct file *filep)
+{
+ int rc;
+ struct sync_device *sync_dev = video_drvdata(filep);
+
+ if (!sync_dev) {
+ pr_err("%s Sync device NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&sync_dev->table_lock);
+ if (sync_dev->open_cnt >= 1) {
+ mutex_unlock(&sync_dev->table_lock);
+ return -EALREADY;
+ }
+
+ rc = v4l2_fh_open(filep);
+ if (!rc) {
+ sync_dev->open_cnt++;
+ spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
+ sync_dev->cam_sync_eventq = filep->private_data;
+ spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
+ } else {
+ pr_err("v4l2_fh_open failed : %d\n", rc);
+ }
+ mutex_unlock(&sync_dev->table_lock);
+
+ return rc;
+}
+
+static int cam_sync_close(struct file *filep)
+{
+ int rc = 0;
+ int i;
+ struct sync_device *sync_dev = video_drvdata(filep);
+
+ if (!sync_dev) {
+ pr_err("%s Sync device NULL\n", __func__);
+ rc = -ENODEV;
+ return rc;
+ }
+ mutex_lock(&sync_dev->table_lock);
+ sync_dev->open_cnt--;
+ if (!sync_dev->open_cnt) {
+ for (i = 1; i < CAM_SYNC_MAX_OBJS; i++) {
+ struct sync_table_row *row =
+ sync_dev->sync_table + i;
+ if (row->state == CAM_SYNC_STATE_INVALID)
+ continue;
+
+ /* Signal all remaining objects as ERR,but we don't care
+ * about the return status here apart from logging it
+ */
+ rc = cam_sync_signal(i, CAM_SYNC_STATE_SIGNALED_ERROR);
+ if (rc < 0)
+ pr_err("Cleanup signal failed: idx = %d\n", i);
+
+ rc = cam_sync_destroy(i);
+ if (rc < 0)
+ pr_err("Cleanup destroy failed: idx = %d\n", i);
+ }
+ }
+ mutex_unlock(&sync_dev->table_lock);
+ spin_lock_bh(&sync_dev->cam_sync_eventq_lock);
+ sync_dev->cam_sync_eventq = NULL;
+ spin_unlock_bh(&sync_dev->cam_sync_eventq_lock);
+ v4l2_fh_release(filep);
+
+ return rc;
+}
+
+int cam_sync_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_subscribe(fh, sub, CAM_SYNC_MAX_V4L2_EVENTS, NULL);
+}
+
+int cam_sync_unsubscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ return v4l2_event_unsubscribe(fh, sub);
+}
+
+static const struct v4l2_ioctl_ops g_cam_sync_ioctl_ops = {
+ .vidioc_subscribe_event = cam_sync_subscribe_event,
+ .vidioc_unsubscribe_event = cam_sync_unsubscribe_event,
+ .vidioc_default = cam_sync_dev_ioctl,
+};
+
+static struct v4l2_file_operations cam_sync_v4l2_fops = {
+ .owner = THIS_MODULE,
+ .open = cam_sync_open,
+ .release = cam_sync_close,
+ .poll = cam_sync_poll,
+ .unlocked_ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl32 = video_ioctl2,
+#endif
+};
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+static int cam_sync_media_controller_init(struct sync_device *sync_dev,
+ struct platform_device *pdev)
+{
+ int rc;
+
+ sync_dev->v4l2_dev.mdev = kzalloc(sizeof(struct media_device),
+ GFP_KERNEL);
+ if (!sync_dev->v4l2_dev.mdev)
+ return -ENOMEM;
+
+ media_device_init(sync_dev->v4l2_dev.mdev);
+ strlcpy(sync_dev->v4l2_dev.mdev->model, CAM_SYNC_DEVICE_NAME,
+ sizeof(sync_dev->v4l2_dev.mdev->model));
+ sync_dev->v4l2_dev.mdev->dev = &(pdev->dev);
+
+ rc = media_device_register(sync_dev->v4l2_dev.mdev);
+ if (rc < 0)
+ goto register_fail;
+
+ rc = media_entity_pads_init(&sync_dev->vdev->entity, 0, NULL);
+ if (rc < 0)
+ goto entity_fail;
+
+ return 0;
+
+entity_fail:
+ media_device_unregister(sync_dev->v4l2_dev.mdev);
+register_fail:
+ media_device_cleanup(sync_dev->v4l2_dev.mdev);
+ return rc;
+}
+
+static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev)
+{
+ media_entity_cleanup(&sync_dev->vdev->entity);
+ media_device_unregister(sync_dev->v4l2_dev.mdev);
+ media_device_cleanup(sync_dev->v4l2_dev.mdev);
+ kfree(sync_dev->v4l2_dev.mdev);
+}
+
+static void cam_sync_init_entity(struct sync_device *sync_dev)
+{
+ sync_dev->vdev->entity.function = CAM_SYNC_DEVICE_TYPE;
+ sync_dev->vdev->entity.name =
+ video_device_node_name(sync_dev->vdev);
+}
+#else
+static int cam_sync_media_controller_init(struct sync_device *sync_dev,
+ struct platform_device *pdev)
+{
+ return 0;
+}
+
+static void cam_sync_media_controller_cleanup(struct sync_device *sync_dev)
+{
+}
+
+static void cam_sync_init_entity(struct sync_device *sync_dev)
+{
+}
+#endif
+
+static int cam_sync_probe(struct platform_device *pdev)
+{
+ int rc;
+ int idx;
+
+ sync_dev = kzalloc(sizeof(*sync_dev), GFP_KERNEL);
+ if (!sync_dev)
+ return -ENOMEM;
+
+ mutex_init(&sync_dev->table_lock);
+ spin_lock_init(&sync_dev->cam_sync_eventq_lock);
+
+ for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++)
+ spin_lock_init(&sync_dev->row_spinlocks[idx]);
+
+ sync_dev->vdev = video_device_alloc();
+ if (!sync_dev->vdev) {
+ rc = -ENOMEM;
+ goto vdev_fail;
+ }
+
+ rc = cam_sync_media_controller_init(sync_dev, pdev);
+ if (rc < 0)
+ goto mcinit_fail;
+
+ sync_dev->vdev->v4l2_dev = &sync_dev->v4l2_dev;
+
+ rc = v4l2_device_register(&(pdev->dev), sync_dev->vdev->v4l2_dev);
+ if (rc < 0)
+ goto register_fail;
+
+ strlcpy(sync_dev->vdev->name, CAM_SYNC_NAME,
+ sizeof(sync_dev->vdev->name));
+ sync_dev->vdev->release = video_device_release;
+ sync_dev->vdev->fops = &cam_sync_v4l2_fops;
+ sync_dev->vdev->ioctl_ops = &g_cam_sync_ioctl_ops;
+ sync_dev->vdev->minor = -1;
+ sync_dev->vdev->vfl_type = VFL_TYPE_GRABBER;
+ rc = video_register_device(sync_dev->vdev,
+ VFL_TYPE_GRABBER, -1);
+ if (rc < 0)
+ goto v4l2_fail;
+
+ cam_sync_init_entity(sync_dev);
+ video_set_drvdata(sync_dev->vdev, sync_dev);
+ memset(&sync_dev->sync_table, 0, sizeof(sync_dev->sync_table));
+ memset(&sync_dev->bitmap, 0, sizeof(sync_dev->bitmap));
+ bitmap_zero(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
+
+ /*
+ * We treat zero as invalid handle, so we will keep the 0th bit set
+ * always
+ */
+ set_bit(0, sync_dev->bitmap);
+
+ sync_dev->work_queue = alloc_workqueue(CAM_SYNC_WORKQUEUE_NAME,
+ WQ_HIGHPRI | WQ_UNBOUND, 0);
+
+ if (!sync_dev->work_queue) {
+ pr_err("Error: high priority work queue creation failed!\n");
+ rc = -ENOMEM;
+ goto v4l2_fail;
+ }
+
+ return rc;
+
+v4l2_fail:
+ v4l2_device_unregister(sync_dev->vdev->v4l2_dev);
+register_fail:
+ cam_sync_media_controller_cleanup(sync_dev);
+mcinit_fail:
+ video_device_release(sync_dev->vdev);
+vdev_fail:
+ mutex_destroy(&sync_dev->table_lock);
+ kfree(sync_dev);
+ return rc;
+}
+
+static int cam_sync_remove(struct platform_device *pdev)
+{
+ v4l2_device_unregister(sync_dev->vdev->v4l2_dev);
+ cam_sync_media_controller_cleanup(sync_dev);
+ video_device_release(sync_dev->vdev);
+ kfree(sync_dev);
+ sync_dev = NULL;
+
+ return 0;
+}
+
+static struct platform_device cam_sync_device = {
+ .name = "cam_sync",
+ .id = -1,
+};
+
+static struct platform_driver cam_sync_driver = {
+ .probe = cam_sync_probe,
+ .remove = cam_sync_remove,
+ .driver = {
+ .name = "cam_sync",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init cam_sync_init(void)
+{
+ int rc;
+
+ rc = platform_device_register(&cam_sync_device);
+ if (rc)
+ return -ENODEV;
+
+ return platform_driver_register(&cam_sync_driver);
+}
+
+static void __exit cam_sync_exit(void)
+{
+ int idx;
+
+ for (idx = 0; idx < CAM_SYNC_MAX_OBJS; idx++)
+ spin_lock_init(&sync_dev->row_spinlocks[idx]);
+ platform_driver_unregister(&cam_sync_driver);
+ platform_device_unregister(&cam_sync_device);
+ kfree(sync_dev);
+}
+
+module_init(cam_sync_init);
+module_exit(cam_sync_exit);
+MODULE_DESCRIPTION("Camera sync driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h
new file mode 100644
index 0000000..9646887
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_api.h
@@ -0,0 +1,128 @@
+/* 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_SYNC_API_H__
+#define __CAM_SYNC_API_H__
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/videodev2.h>
+#include <uapi/media/cam_sync.h>
+
+#define SYNC_DEBUG_NAME_LEN 63
+typedef void (*sync_callback)(int32_t sync_obj, int status, void *data);
+
+/* Kernel APIs */
+
+/**
+ * @brief: Creates a sync object
+ *
+ * The newly created sync obj is assigned to sync_obj.
+ * sync object.
+ *
+ * @param sync_obj : Pointer to int referencing the sync object.
+ * @param name : Optional parameter associating a name with the sync object for
+ * debug purposes. Only first SYNC_DEBUG_NAME_LEN bytes are accepted,
+ * rest will be ignored.
+ *
+ * @return Status of operation. Zero in case of success.
+ * -EINVAL will be returned if sync_obj is an invalid pointer.
+ * -ENOMEM will be returned if the kernel can't allocate space for
+ * sync object.
+ */
+int cam_sync_create(int32_t *sync_obj, const char *name);
+
+/**
+ * @brief: Registers a callback with a sync object
+ *
+ * @param cb_func: Pointer to callback to be registered
+ * @param userdata: Opaque pointer which will be passed back with callback.
+ * @param sync_obj: int referencing the sync object.
+ *
+ * @return Status of operation. Zero in case of success.
+ * -EINVAL will be returned if userdata is invalid.
+ * -ENOMEM will be returned if cb_func is invalid.
+ *
+ */
+int cam_sync_register_callback(sync_callback cb_func,
+ void *userdata, int32_t sync_obj);
+
+/**
+ * @brief: De-registers a callback with a sync object
+ *
+ * @param cb_func: Pointer to callback to be de-registered
+ * @param userdata: Opaque pointer which will be passed back with callback.
+ * @param sync_obj: int referencing the sync object.
+ *
+ * @return Status of operation. Zero in case of success.
+ * -EINVAL will be returned if userdata is invalid.
+ * -ENOMEM will be returned if cb_func is invalid.
+ */
+int cam_sync_deregister_callback(sync_callback cb_func,
+ void *userdata, int32_t sync_obj);
+
+/**
+ * @brief: Signals a sync object with the status argument.
+ *
+ * This function will signal the sync object referenced by the sync_obj
+ * parameter and when doing so, will trigger callbacks in both user space and
+ * kernel. Callbacks will triggered asynchronously and their order of execution
+ * is not guaranteed. The status parameter will indicate whether the entity
+ * performing the signaling wants to convey an error case or a success case.
+ *
+ * @param sync_obj: int referencing the sync object.
+ * @param status: Status of the signaling. Can be either SYNC_SIGNAL_ERROR or
+ * SYNC_SIGNAL_SUCCESS.
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_signal(int32_t sync_obj, uint32_t status);
+
+/**
+ * @brief: Merges multiple sync objects
+ *
+ * This function will merge multiple sync objects into a sync group.
+ *
+ * @param sync_obj: pointer to a block of ints to be merged
+ * @param num_objs: Number of ints in the block
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj);
+
+/**
+ * @brief: Destroys a sync object
+ *
+ * @param sync_obj: int referencing the sync object to be destroyed
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_destroy(int32_t sync_obj);
+
+/**
+ * @brief: Waits for a sync object synchronously
+ *
+ * Does a wait on the sync object identified by sync_obj for a maximum
+ * of timeout_ms milliseconds. Must not be called from interrupt context as
+ * this API can sleep. Should be called from process context only.
+ *
+ * @param sync_obj: int referencing the sync object to be waited upon
+ * @timeout_ms sync_obj: Timeout in ms.
+ *
+ * @return 0 upon success, -EINVAL if sync object is in bad state or arguments
+ * are invalid, -ETIMEDOUT if wait times out.
+ */
+int cam_sync_wait(int32_t sync_obj, uint64_t timeout_ms);
+
+
+#endif /* __CAM_SYNC_API_H__ */
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h
new file mode 100644
index 0000000..ba9bef4
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h
@@ -0,0 +1,186 @@
+/* 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_SYNC_PRIVATE_H__
+#define __CAM_SYNC_PRIVATE_H__
+
+#include <linux/bitmap.h>
+#include <linux/videodev2.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.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>
+
+#ifdef CONFIG_CAM_SYNC_DBG
+#define CDBG(fmt, args...) pr_err(fmt, ##args)
+#else
+#define CDBG(fmt, args...) pr_debug(fmt, ##args)
+#endif
+
+#define CAM_SYNC_OBJ_NAME_LEN 64
+#define CAM_SYNC_MAX_OBJS 1024
+#define CAM_SYNC_MAX_V4L2_EVENTS 50
+#define CAM_SYNC_DEBUG_FILENAME "cam_debug"
+#define CAM_SYNC_DEBUG_BASEDIR "cam"
+#define CAM_SYNC_DEBUG_BUF_SIZE 32
+#define CAM_SYNC_PAYLOAD_WORDS 2
+#define CAM_SYNC_NAME "cam_sync"
+#define CAM_SYNC_WORKQUEUE_NAME "HIPRIO_SYNC_WORK_QUEUE"
+
+#define CAM_SYNC_TYPE_INDV 0
+#define CAM_SYNC_TYPE_GROUP 1
+
+/**
+ * enum sync_type - Enum to indicate the type of sync object,
+ * i.e. individual or group.
+ *
+ * @SYNC_TYPE_INDV : Object is an individual sync object
+ * @SYNC_TYPE_GROUP : Object is a group sync object
+ */
+enum sync_type {
+ SYNC_TYPE_INDV,
+ SYNC_TYPE_GROUP
+};
+
+/**
+ * struct sync_parent_info - Single node of information about a parent
+ * of a sync object, usually part of the parents linked list
+ *
+ * @sync_id : Sync object id of parent
+ * @list : List member used to append this node to a linked list
+ */
+struct sync_parent_info {
+ int32_t sync_id;
+ struct list_head list;
+};
+
+/**
+ * struct sync_parent_info - Single node of information about a child
+ * of a sync object, usually part of the children linked list
+ *
+ * @sync_id : Sync object id of child
+ * @list : List member used to append this node to a linked list
+ */
+struct sync_child_info {
+ int32_t sync_id;
+ struct list_head list;
+};
+
+
+/**
+ * struct sync_callback_info - Single node of information about a kernel
+ * callback registered on a sync object
+ *
+ * @callback_func : Callback function, registered by client driver
+ * @cb_data : Callback data, registered by client driver
+ * @status........ : Status with which callback will be invoked in client
+ * @sync_obj : Sync id of the object for which callback is registered
+ * @cb_dispatch_work : Work representing the call dispatch
+ * @list : List member used to append this node to a linked list
+ */
+struct sync_callback_info {
+ sync_callback callback_func;
+ void *cb_data;
+ int status;
+ int32_t sync_obj;
+ struct work_struct cb_dispatch_work;
+ struct list_head list;
+};
+
+/**
+ * struct sync_user_payload - Single node of information about a user space
+ * payload registered from user space
+ *
+ * @payload_data : Payload data, opaque to kernel
+ * @list : List member used to append this node to a linked list
+ */
+struct sync_user_payload {
+ uint64_t payload_data[CAM_SYNC_PAYLOAD_WORDS];
+ struct list_head list;
+};
+
+/**
+ * struct sync_table_row - Single row of information about a sync object, used
+ * for internal book keeping in the sync driver
+ *
+ * @name : Optional string representation of the sync object
+ * @type : Type of the sync object (individual or group)
+ * @sync_id : Integer id representing this sync object
+ * @parents_list : Linked list of parents of this sync object
+ * @children_list : Linked list of children of this sync object
+ * @state : State (INVALID, ACTIVE, SIGNALED_SUCCESS or
+ * SIGNALED_ERROR)
+ * @remaining : Count of remaining children that not been signaled
+ * @signaled : Completion variable on which block calls will wait
+ * @callback_list : Linked list of kernel callbacks registered
+ * @user_payload_list : LInked list of user space payloads registered
+ */
+struct sync_table_row {
+ char name[CAM_SYNC_OBJ_NAME_LEN];
+ enum sync_type type;
+ int32_t sync_id;
+ /* List of parents, which are merged objects */
+ struct list_head parents_list;
+ /* List of children, which constitute the merged object */
+ struct list_head children_list;
+ uint32_t state;
+ uint32_t remaining;
+ struct completion signaled;
+ struct list_head callback_list;
+ struct list_head user_payload_list;
+};
+
+/**
+ * struct cam_signalable_info - Information for a single sync object that is
+ * ready to be signaled
+ *
+ * @sync_obj : Sync object id of signalable object
+ * @status : Status with which to signal
+ * @list : List member used to append this node to a linked list
+ */
+struct cam_signalable_info {
+ int32_t sync_obj;
+ uint32_t status;
+ struct list_head list;
+};
+
+/**
+ * struct sync_device - Internal struct to book keep sync driver details
+ *
+ * @vdev : Video device
+ * @v4l2_dev : V4L2 device
+ * @sync_table : Table of all sync objects
+ * @row_spinlocks : Spinlock array, one for each row in the table
+ * @table_lock : Mutex used to lock the table
+ * @open_cnt : Count of file open calls made on the sync driver
+ * @work_queue : Work queue used for dispatching kernel callbacks
+ * @cam_sync_eventq : Event queue used to dispatch user payloads to user space
+ * @bitmap : Bitmap representation of all sync objects
+ */
+struct sync_device {
+ struct video_device *vdev;
+ struct v4l2_device v4l2_dev;
+ struct sync_table_row sync_table[CAM_SYNC_MAX_OBJS];
+ spinlock_t row_spinlocks[CAM_SYNC_MAX_OBJS];
+ struct mutex table_lock;
+ int open_cnt;
+ struct workqueue_struct *work_queue;
+ struct v4l2_fh *cam_sync_eventq;
+ spinlock_t cam_sync_eventq_lock;
+ DECLARE_BITMAP(bitmap, CAM_SYNC_MAX_OBJS);
+};
+
+
+#endif /* __CAM_SYNC_PRIVATE_H__ */
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
new file mode 100644
index 0000000..4f5bf87
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
@@ -0,0 +1,296 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "CAM-SYNC-UTIL %s:%d " fmt, __func__, __LINE__
+
+#include "cam_sync_util.h"
+
+int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev,
+ long *idx)
+{
+ int rc = 0;
+
+ mutex_lock(&sync_dev->table_lock);
+
+ *idx = find_first_zero_bit(sync_dev->bitmap, CAM_SYNC_MAX_OBJS);
+
+ if (*idx < CAM_SYNC_MAX_OBJS)
+ set_bit(*idx, sync_dev->bitmap);
+ else
+ rc = -1;
+
+ mutex_unlock(&sync_dev->table_lock);
+
+ return rc;
+}
+
+int cam_sync_init_object(struct sync_table_row *table,
+ uint32_t idx,
+ const char *name)
+{
+ struct sync_table_row *row = table + idx;
+
+ if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS)
+ return -EINVAL;
+
+ if (name)
+ strlcpy(row->name, name, SYNC_DEBUG_NAME_LEN);
+ INIT_LIST_HEAD(&row->parents_list);
+ INIT_LIST_HEAD(&row->children_list);
+ row->type = CAM_SYNC_TYPE_INDV;
+ row->sync_id = idx;
+ row->state = CAM_SYNC_STATE_ACTIVE;
+ row->remaining = 0;
+ init_completion(&row->signaled);
+ INIT_LIST_HEAD(&row->callback_list);
+ INIT_LIST_HEAD(&row->user_payload_list);
+
+ return 0;
+}
+
+int cam_sync_init_group_object(struct sync_table_row *table,
+ uint32_t idx,
+ uint32_t *sync_objs,
+ uint32_t num_objs)
+{
+ int i;
+ struct sync_child_info *child_info;
+ struct sync_parent_info *parent_info;
+ struct sync_table_row *row = table + idx;
+ struct sync_table_row *child_row = NULL;
+
+ spin_lock_bh(&sync_dev->row_spinlocks[idx]);
+ INIT_LIST_HEAD(&row->parents_list);
+
+ INIT_LIST_HEAD(&row->children_list);
+
+ /*
+ * While traversing parents and children, we allocate in a loop and in
+ * case allocation fails, we call the clean up function which frees up
+ * all memory allocation thus far
+ */
+ for (i = 0; i < num_objs; i++) {
+ child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC);
+
+ if (!child_info) {
+ cam_sync_util_cleanup_children_list(
+ &row->children_list);
+ spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+ return -ENOMEM;
+ }
+
+ child_info->sync_id = sync_objs[i];
+ list_add_tail(&child_info->list, &row->children_list);
+ }
+
+ for (i = 0; i < num_objs; i++) {
+ /* This gets us the row corresponding to the sync object */
+ child_row = table + sync_objs[i];
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC);
+ if (!parent_info) {
+ cam_sync_util_cleanup_parents_list(
+ &child_row->parents_list);
+ cam_sync_util_cleanup_children_list(
+ &row->children_list);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+ return -ENOMEM;
+ }
+ parent_info->sync_id = idx;
+ list_add_tail(&parent_info->list, &child_row->parents_list);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ }
+
+ row->type = CAM_SYNC_TYPE_GROUP;
+ row->sync_id = idx;
+ row->state = CAM_SYNC_STATE_ACTIVE;
+ row->remaining = num_objs;
+ init_completion(&row->signaled);
+ INIT_LIST_HEAD(&row->callback_list);
+ INIT_LIST_HEAD(&row->user_payload_list);
+
+ spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+ return 0;
+}
+
+int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx)
+{
+ struct sync_table_row *row = table + idx;
+ struct sync_child_info *child_info, *temp_child;
+ struct sync_callback_info *sync_cb, *temp_cb;
+ struct sync_parent_info *parent_info, *temp_parent;
+ struct sync_user_payload *upayload_info, *temp_upayload;
+
+ if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS)
+ return -EINVAL;
+
+ spin_lock_bh(&sync_dev->row_spinlocks[idx]);
+ clear_bit(idx, sync_dev->bitmap);
+ list_for_each_entry_safe(child_info, temp_child,
+ &row->children_list, list) {
+ list_del_init(&child_info->list);
+ kfree(child_info);
+ }
+
+ list_for_each_entry_safe(parent_info, temp_parent,
+ &row->parents_list, list) {
+ list_del_init(&parent_info->list);
+ kfree(parent_info);
+ }
+
+ list_for_each_entry_safe(upayload_info, temp_upayload,
+ &row->user_payload_list, list) {
+ list_del_init(&upayload_info->list);
+ kfree(upayload_info);
+ }
+
+ list_for_each_entry_safe(sync_cb, temp_cb,
+ &row->callback_list, list) {
+ list_del_init(&sync_cb->list);
+ kfree(sync_cb);
+ }
+
+ row->state = CAM_SYNC_STATE_INVALID;
+ memset(row, 0, sizeof(*row));
+ spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
+
+ return 0;
+}
+
+void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work)
+{
+ struct sync_callback_info *cb_info = container_of(cb_dispatch_work,
+ struct sync_callback_info,
+ cb_dispatch_work);
+
+ cb_info->callback_func(cb_info->sync_obj,
+ cb_info->status,
+ cb_info->cb_data);
+
+ kfree(cb_info);
+}
+
+void cam_sync_util_send_v4l2_event(uint32_t id,
+ uint32_t sync_obj,
+ int status,
+ void *payload,
+ int len)
+{
+ struct v4l2_event event;
+ __u64 *payload_data = NULL;
+ struct cam_sync_ev_header *ev_header = NULL;
+
+ event.id = id;
+ event.type = CAM_SYNC_V4L_EVENT;
+
+ ev_header = CAM_SYNC_GET_HEADER_PTR(event);
+ ev_header->sync_obj = sync_obj;
+ ev_header->status = status;
+
+ payload_data = CAM_SYNC_GET_PAYLOAD_PTR(event, __u64);
+ memcpy(payload_data, payload, len);
+
+ v4l2_event_queue(sync_dev->vdev, &event);
+}
+
+int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs)
+{
+ int i;
+ struct sync_table_row *row = NULL;
+
+ for (i = 0; i < num_objs; i++) {
+ row = sync_dev->sync_table + sync_obj[i];
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_obj[i]]);
+ if (row->type == CAM_SYNC_TYPE_GROUP ||
+ row->state == CAM_SYNC_STATE_INVALID) {
+ pr_err("Group obj %d can't be merged or obj UNINIT\n",
+ sync_obj[i]);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]);
+ return -EINVAL;
+ }
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]);
+ }
+ return 0;
+}
+
+int cam_sync_util_add_to_signalable_list(int32_t sync_obj,
+ uint32_t status,
+ struct list_head *sync_list)
+{
+ struct cam_signalable_info *signalable_info = NULL;
+
+ signalable_info = kzalloc(sizeof(*signalable_info), GFP_ATOMIC);
+ if (!signalable_info)
+ return -ENOMEM;
+
+ signalable_info->sync_obj = sync_obj;
+ signalable_info->status = status;
+
+ list_add_tail(&signalable_info->list, sync_list);
+
+ return 0;
+}
+
+int cam_sync_util_get_state(int current_state,
+ int new_state)
+{
+ int result = CAM_SYNC_STATE_SIGNALED_ERROR;
+
+ if (new_state != CAM_SYNC_STATE_SIGNALED_SUCCESS &&
+ new_state != CAM_SYNC_STATE_SIGNALED_ERROR)
+ return CAM_SYNC_STATE_SIGNALED_ERROR;
+
+ switch (current_state) {
+ case CAM_SYNC_STATE_INVALID:
+ result = CAM_SYNC_STATE_SIGNALED_ERROR;
+ break;
+
+ case CAM_SYNC_STATE_ACTIVE:
+ case CAM_SYNC_STATE_SIGNALED_SUCCESS:
+ if (new_state == CAM_SYNC_STATE_SIGNALED_ERROR)
+ result = CAM_SYNC_STATE_SIGNALED_ERROR;
+ else if (new_state == CAM_SYNC_STATE_SIGNALED_SUCCESS)
+ result = CAM_SYNC_STATE_SIGNALED_SUCCESS;
+ break;
+
+ case CAM_SYNC_STATE_SIGNALED_ERROR:
+ result = CAM_SYNC_STATE_SIGNALED_ERROR;
+ break;
+ }
+
+ return result;
+}
+
+void cam_sync_util_cleanup_children_list(struct list_head *list_to_clean)
+{
+ struct sync_child_info *child_info = NULL;
+ struct sync_child_info *temp_child_info = NULL;
+
+ list_for_each_entry_safe(child_info,
+ temp_child_info, list_to_clean, list) {
+ list_del_init(&child_info->list);
+ kfree(child_info);
+ }
+}
+
+void cam_sync_util_cleanup_parents_list(struct list_head *list_to_clean)
+{
+ struct sync_parent_info *parent_info = NULL;
+ struct sync_parent_info *temp_parent_info = NULL;
+
+ list_for_each_entry_safe(parent_info,
+ temp_parent_info, list_to_clean, list) {
+ list_del_init(&parent_info->list);
+ kfree(parent_info);
+ }
+}
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h
new file mode 100644
index 0000000..9dedd14
--- /dev/null
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h
@@ -0,0 +1,156 @@
+/* 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_SYNC_UTIL_H__
+#define __CAM_SYNC_UTIL_H__
+
+
+#include <cam_sync_api.h>
+#include "cam_sync_private.h"
+
+extern struct sync_device *sync_dev;
+
+/**
+ * @brief: Finds an empty row in the sync table and sets its corresponding bit
+ * in the bit array
+ *
+ * @param sync_dev : Pointer to the sync device instance
+ * @param idx : Pointer to an long containing the index found in the bit
+ * array
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev,
+ long *idx);
+
+/**
+ * @brief: Function to initialize an empty row in the sync table. This should be
+ * called only for individual sync objects.
+ *
+ * @param table : Pointer to the sync objects table
+ * @param idx : Index of row to initialize
+ * @param name : Optional string representation of the sync object. Should be
+ * 63 characters or less
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_init_object(struct sync_table_row *table,
+ uint32_t idx,
+ const char *name);
+
+/**
+ * @brief: Function to uninitialize a row in the sync table
+ *
+ * @param table : Pointer to the sync objects table
+ * @param idx : Index of row to initialize
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx);
+
+/**
+ * @brief: Function to initialize a row in the sync table when the object is a
+ * group object, also known as a merged sync object
+ *
+ * @param table : Pointer to the sync objects table
+ * @param idx : Index of row to initialize
+ * @param sync_objs : Array of sync objects which will merged
+ * or grouped together
+ * @param num_objs : Number of sync objects in the array
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_init_group_object(struct sync_table_row *table,
+ uint32_t idx,
+ uint32_t *sync_objs,
+ uint32_t num_objs);
+
+int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx);
+
+/**
+ * @brief: Function to dispatch a kernel callback for a sync callback
+ *
+ * @param cb_dispatch_work : Pointer to the work_struct that needs to be
+ * dispatched
+ *
+ * @return None
+ */
+void cam_sync_util_cb_dispatch(struct work_struct *cb_dispatch_work);
+
+/**
+ * @brief: Function to send V4L event to user space
+ * @param id : V4L event id to send
+ * @param sync_obj : Sync obj for which event needs to be sent
+ * @param status : Status of the event
+ * @payload : Payload that needs to be sent to user space
+ * @len : Length of the payload
+ *
+ * @return None
+ */
+void cam_sync_util_send_v4l2_event(uint32_t id,
+ uint32_t sync_obj,
+ int status,
+ void *payload,
+ int len);
+
+/**
+ * @brief: Function to validate sync merge arguments
+ *
+ * @param sync_obj : Array of sync objects to merge
+ * @param num_objs : Number of sync objects in the array
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs);
+
+/**
+ * @brief: Function which adds sync object information to the signalable list
+ *
+ * @param sync_obj : Sync object to add
+ * @param status : Status of above sync object
+ * @param list : Linked list where the information should be added to
+ *
+ * @return Status of operation. Negative in case of error. Zero otherwise.
+ */
+int cam_sync_util_add_to_signalable_list(int32_t sync_obj,
+ uint32_t status,
+ struct list_head *sync_list);
+
+/**
+ * @brief: Function which gets the next state of the sync object based on the
+ * current state and the new state
+ *
+ * @param current_state : Current state of the sync object
+ * @param new_state : New state of the sync object
+ *
+ * @return Next state of the sync object
+ */
+int cam_sync_util_get_state(int current_state,
+ int new_state);
+
+/**
+ * @brief: Function to clean up the children of a sync object
+ * @param list_to_clean : List to clean up
+ *
+ * @return None
+ */
+void cam_sync_util_cleanup_children_list(struct list_head *list_to_clean);
+
+/**
+ * @brief: Function to clean up the parents of a sync object
+ * @param list_to_clean : List to clean up
+ *
+ * @return None
+ */
+void cam_sync_util_cleanup_parents_list(struct list_head *list_to_clean);
+
+#endif /* __CAM_SYNC_UTIL_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..9a28700 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;
}
@@ -2004,7 +2007,7 @@
devm_kfree(&mgr->pdev->dev, req);
}
-static void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr,
+void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr,
struct sde_rot_file_private *private)
{
struct sde_rot_entry_container *req, *req_next;
@@ -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_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
index 0818917..980e4af 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h
@@ -686,6 +686,14 @@
int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable);
/*
+ * sde_rotator_cancel_all_requests - cancel all outstanding requests
+ * @mgr: Pointer to rotator manager
+ * @private: Pointer to rotator manager per file context
+ */
+void sde_rotator_cancel_all_requests(struct sde_rot_mgr *mgr,
+ struct sde_rot_file_private *private);
+
+/*
* sde_rot_mgr_lock - serialization lock prior to rotator manager calls
* @mgr: Pointer to rotator manager
*/
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
index 86e04d6..e56c70a 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c
@@ -996,11 +996,14 @@
{
struct sde_rotator_debug_base *dbg = file->private_data;
- if (dbg && dbg->buf) {
+ if (dbg) {
+ mutex_lock(&dbg->buflock);
kfree(dbg->buf);
dbg->buf_len = 0;
dbg->buf = NULL;
+ mutex_unlock(&dbg->buflock);
}
+
return 0;
}
@@ -1032,8 +1035,10 @@
if (cnt > (dbg->max_offset - off))
cnt = dbg->max_offset - off;
+ mutex_lock(&dbg->buflock);
dbg->off = off;
dbg->cnt = cnt;
+ mutex_unlock(&dbg->buflock);
SDEROT_DBG("offset=%x cnt=%x\n", off, cnt);
@@ -1053,7 +1058,10 @@
if (*ppos)
return 0; /* the end */
+ mutex_lock(&dbg->buflock);
len = snprintf(buf, sizeof(buf), "0x%08zx %zx\n", dbg->off, dbg->cnt);
+ mutex_unlock(&dbg->buflock);
+
if (len < 0 || len >= sizeof(buf))
return 0;
@@ -1092,6 +1100,8 @@
if (off >= dbg->max_offset)
return -EFAULT;
+ mutex_lock(&dbg->buflock);
+
/* Enable Clock for register access */
sde_rotator_clk_ctrl(dbg->mgr, true);
@@ -1100,6 +1110,8 @@
/* Disable Clock after register access */
sde_rotator_clk_ctrl(dbg->mgr, false);
+ mutex_unlock(&dbg->buflock);
+
SDEROT_DBG("addr=%zx data=%x\n", off, data);
return count;
@@ -1110,12 +1122,14 @@
{
struct sde_rotator_debug_base *dbg = file->private_data;
size_t len;
+ int rc = 0;
if (!dbg) {
SDEROT_ERR("invalid handle\n");
return -ENODEV;
}
+ mutex_lock(&dbg->buflock);
if (!dbg->buf) {
char dump_buf[64];
char *ptr;
@@ -1127,7 +1141,8 @@
if (!dbg->buf) {
SDEROT_ERR("not enough memory to hold reg dump\n");
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto debug_read_error;
}
ptr = dbg->base + dbg->off;
@@ -1157,18 +1172,26 @@
dbg->buf_len = tot;
}
- if (*ppos >= dbg->buf_len)
- return 0; /* done reading */
+ if (*ppos >= dbg->buf_len) {
+ rc = 0; /* done reading */
+ goto debug_read_error;
+ }
len = min(count, dbg->buf_len - (size_t) *ppos);
if (copy_to_user(user_buf, dbg->buf + *ppos, len)) {
SDEROT_ERR("failed to copy to user\n");
- return -EFAULT;
+ rc = -EFAULT;
+ goto debug_read_error;
}
*ppos += len; /* increase offset */
+ mutex_unlock(&dbg->buflock);
return len;
+
+debug_read_error:
+ mutex_unlock(&dbg->buflock);
+ return rc;
}
static const struct file_operations sde_rotator_off_fops = {
@@ -1202,6 +1225,9 @@
if (!dbg)
return -ENOMEM;
+ mutex_init(&dbg->buflock);
+ mutex_lock(&dbg->buflock);
+
if (name)
strlcpy(dbg->name, name, sizeof(dbg->name));
dbg->base = io_data->base;
@@ -1223,6 +1249,7 @@
dbg->base += rot_dev->mdata->regdump ?
rot_dev->mdata->regdump[0].offset : 0;
}
+ mutex_unlock(&dbg->buflock);
strlcpy(dbgname + prefix_len, "off", sizeof(dbgname) - prefix_len);
ent_off = debugfs_create_file(dbgname, 0644, debugfs_root, dbg,
@@ -1240,7 +1267,9 @@
goto reg_fail;
}
+ mutex_lock(&dbg->buflock);
dbg->mgr = rot_dev->mgr;
+ mutex_unlock(&dbg->buflock);
return 0;
reg_fail:
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
index c2c6f97..c6d0151 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.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
@@ -53,6 +53,7 @@
char *buf;
size_t buf_len;
struct sde_rot_mgr *mgr;
+ struct mutex buflock;
};
#if defined(CONFIG_DEBUG_FS)
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
index 47f4cb0..c061446 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c
@@ -450,11 +450,15 @@
list_empty(&ctx->pending_list),
msecs_to_jiffies(rot_dev->streamoff_timeout));
mutex_lock(q->lock);
- if (!ret)
+ if (!ret) {
SDEDEV_ERR(rot_dev->dev,
"timeout to stream off s:%d t:%d p:%d\n",
ctx->session_id, q->type,
!list_empty(&ctx->pending_list));
+ sde_rot_mgr_lock(rot_dev->mgr);
+ sde_rotator_cancel_all_requests(rot_dev->mgr, ctx->private);
+ sde_rot_mgr_unlock(rot_dev->mgr);
+ }
sde_rotator_return_all_buffers(q, VB2_BUF_STATE_ERROR);
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..9071361 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
@@ -1860,6 +1860,7 @@
u32 danger_lut = 0; /* applicable for realtime client only */
u32 safe_lut = 0; /* applicable for realtime client only */
u32 flags = 0;
+ u32 rststs = 0;
struct sde_rotation_item *item;
int ret;
@@ -1931,10 +1932,46 @@
SDEROT_EVTLOG(ctx->start_ctrl, ctx->sys_cache_mode, ctx->op_mode);
+ /*
+ * if Rotator HW is reset, but missing PM event notification, we
+ * need to init the SW timestamp automatically.
+ */
+ rststs = SDE_ROTREG_READ(rot->mdss_base, REGDMA_RESET_STATUS_REG);
+ if (!rot->reset_hw_ts && rststs) {
+ u32 l_ts, h_ts, swts;
+
+ swts = SDE_ROTREG_READ(rot->mdss_base, REGDMA_TIMESTAMP_REG);
+ h_ts = atomic_read(&rot->timestamp[ROT_QUEUE_HIGH_PRIORITY]);
+ l_ts = atomic_read(&rot->timestamp[ROT_QUEUE_LOW_PRIORITY]);
+ SDEROT_EVTLOG(0xbad0, rststs, swts, h_ts, l_ts);
+
+ if (ctx->q_id == ROT_QUEUE_HIGH_PRIORITY)
+ h_ts = (h_ts - 1) & SDE_REGDMA_SWTS_MASK;
+ else
+ l_ts = (l_ts - 1) & SDE_REGDMA_SWTS_MASK;
+
+ /* construct the combined timstamp */
+ swts = (h_ts & SDE_REGDMA_SWTS_MASK) |
+ ((l_ts & SDE_REGDMA_SWTS_MASK) <<
+ SDE_REGDMA_SWTS_SHIFT);
+
+ SDEROT_DBG("swts:0x%x, h_ts:0x%x, l_ts;0x%x\n",
+ swts, h_ts, l_ts);
+ SDEROT_EVTLOG(0x900d, swts, h_ts, l_ts);
+ rot->last_hw_ts = swts;
+
+ SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG,
+ rot->last_hw_ts);
+ SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_RESET_STATUS_REG, 0);
+ /* ensure write is issued to the rotator HW */
+ wmb();
+ }
+
if (rot->reset_hw_ts) {
SDEROT_EVTLOG(rot->last_hw_ts);
SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_TIMESTAMP_REG,
rot->last_hw_ts);
+ SDE_ROTREG_WRITE(rot->mdss_base, REGDMA_RESET_STATUS_REG, 0);
/* ensure write is issued to the rotator HW */
wmb();
rot->reset_hw_ts = false;
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
index dc97bdf..aa762dd 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_r3_hwio.h
@@ -291,5 +291,6 @@
#define REGDMA_INT_LOW_MASK 0x00000700
#define REGDMA_INT_ERR_MASK 0x000F0000
#define REGDMA_TIMESTAMP_REG ROT_SSPP_TPG_PATTERN_GEN_INIT_VAL
+#define REGDMA_RESET_STATUS_REG ROT_SSPP_TPG_RGB_MAPPING
#endif /*_SDE_ROTATOR_R3_HWIO_H */
diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
index 4f6386b..e209192 100644
--- a/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
+++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_smmu.c
@@ -471,11 +471,18 @@
sde_smmu = (struct sde_smmu_client *)token;
- /* trigger rotator panic and dump */
- SDEROT_ERR("trigger rotator panic and dump, iova=0x%08lx\n", iova);
+ /* trigger rotator dump */
+ SDEROT_ERR("trigger rotator dump, iova=0x%08lx, flags=0x%x\n",
+ iova, flags);
+ SDEROT_ERR("SMMU device:%s", sde_smmu->dev->kobj.name);
- sde_rot_dump_panic();
+ /* generate dump, but no panic */
+ sde_rot_evtlog_tout_handler(false, __func__, "rot", "vbif_dbg_bus");
+ /*
+ * return -ENOSYS to allow smmu driver to dump out useful
+ * debug info.
+ */
return rc;
}
diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c
index 16c2aae..87a4ac8 100644
--- a/drivers/media/platform/msm/vidc/hfi_packetization.c
+++ b/drivers/media/platform/msm/vidc/hfi_packetization.c
@@ -33,7 +33,6 @@
[ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] =
HFI_H264_PROFILE_CONSTRAINED_HIGH,
[ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1,
- [ilog2(HAL_MVC_PROFILE_STEREO_HIGH)] = HFI_H264_PROFILE_STEREO_HIGH,
};
static int entropy_mode[] = {
@@ -68,13 +67,10 @@
[ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565,
[ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888,
[ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888,
- [ilog2(HAL_COLOR_FORMAT_RGBA8888)] = HFI_COLOR_FORMAT_RGBA8888,
/* UBWC Color formats*/
[ilog2(HAL_COLOR_FORMAT_NV12_UBWC)] = HFI_COLOR_FORMAT_NV12_UBWC,
[ilog2(HAL_COLOR_FORMAT_NV12_TP10_UBWC)] =
HFI_COLOR_FORMAT_YUV420_TP10_UBWC,
- [ilog2(HAL_COLOR_FORMAT_RGBA8888_UBWC)] =
- HFI_COLOR_FORMAT_RGBA8888_UBWC,
};
static int nal_type[] = {
@@ -126,26 +122,6 @@
}
}
-u32 get_hfi_layout(enum hal_buffer_layout_type hal_buf_layout)
-{
- u32 hfi_layout;
-
- switch (hal_buf_layout) {
- case HAL_BUFFER_LAYOUT_TOP_BOTTOM:
- hfi_layout = HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM;
- break;
- case HAL_BUFFER_LAYOUT_SEQ:
- hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
- break;
- default:
- dprintk(VIDC_ERR, "Invalid buffer layout: %#x\n",
- hal_buf_layout);
- hfi_layout = HFI_MVC_BUFFER_LAYOUT_SEQ;
- break;
- }
- return hfi_layout;
-}
-
enum hal_domain vidc_get_hal_domain(u32 hfi_domain)
{
enum hal_domain hal_domain = 0;
@@ -192,9 +168,6 @@
case HFI_VIDEO_CODEC_VP9:
hal_codec = HAL_VIDEO_CODEC_VP9;
break;
- case HFI_VIDEO_CODEC_HEVC_HYBRID:
- hal_codec = HAL_VIDEO_CODEC_HEVC_HYBRID;
- break;
default:
dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
__func__, hfi_codec);
@@ -233,7 +206,6 @@
u32 hfi_codec = 0;
switch (hal_codec) {
- case HAL_VIDEO_CODEC_MVC:
case HAL_VIDEO_CODEC_H264:
hfi_codec = HFI_VIDEO_CODEC_H264;
break;
@@ -252,9 +224,6 @@
case HAL_VIDEO_CODEC_VP9:
hfi_codec = HFI_VIDEO_CODEC_VP9;
break;
- case HAL_VIDEO_CODEC_HEVC_HYBRID:
- hfi_codec = HFI_VIDEO_CODEC_HEVC_HYBRID;
- break;
default:
dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
__func__, hal_codec);
@@ -555,12 +524,6 @@
case HAL_EXTRADATA_INTERLACE_VIDEO:
ret = HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA;
break;
- case HAL_EXTRADATA_VC1_FRAMEDISP:
- ret = HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA;
- break;
- case HAL_EXTRADATA_VC1_SEQDISP:
- ret = HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA;
- break;
case HAL_EXTRADATA_TIMESTAMP:
ret = HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA;
break;
@@ -673,9 +636,6 @@
case HAL_LTR_MODE_MANUAL:
ltrmode = HFI_LTR_MODE_MANUAL;
break;
- case HAL_LTR_MODE_PERIODIC:
- ltrmode = HFI_LTR_MODE_PERIODIC;
- break;
default:
dprintk(VIDC_ERR, "Invalid ltr mode: %#x\n",
ltr_mode_type);
@@ -939,31 +899,10 @@
struct hfi_cmd_session_get_property_packet *pkt,
struct hal_session *session, enum hal_property ptype)
{
- int rc = 0;
-
- if (!pkt || !session) {
- dprintk(VIDC_ERR, "%s Invalid parameters\n", __func__);
- return -EINVAL;
- }
- pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
- pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
- pkt->session_id = hash32_ptr(session);
- pkt->num_properties = 1;
- switch (ptype) {
- case HAL_CONFIG_VDEC_ENTROPY:
- pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VDEC_ENTROPY;
- break;
- case HAL_PARAM_PROFILE_LEVEL_CURRENT:
- pkt->rg_property_data[0] =
- HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
- break;
- default:
- dprintk(VIDC_ERR, "%s cmd:%#x not supported\n", __func__,
+ /* Currently no get property is supported */
+ dprintk(VIDC_ERR, "%s cmd:%#x not supported\n", __func__,
ptype);
- rc = -EINVAL;
- break;
- }
- return rc;
+ return -EINVAL;
}
int create_pkt_cmd_session_set_property(
@@ -1028,8 +967,6 @@
break;
case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO:
break;
- case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG:
- break;
case HAL_PARAM_FRAME_SIZE:
{
struct hfi_frame_size *hfi;
@@ -1142,14 +1079,6 @@
pkt->size += sizeof(u32) * 2;
break;
}
- case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER:
- {
- create_pkt_enable(pkt->rg_property_data,
- HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
- ((struct hal_enable *)pdata)->enable);
- pkt->size += sizeof(u32) * 2;
- break;
- }
case HAL_PARAM_VDEC_MULTI_STREAM:
{
struct hfi_multi_stream *hfi;
@@ -1199,10 +1128,6 @@
HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
pkt->size += sizeof(u32);
break;
- case HAL_PARAM_VENC_MPEG4_SHORT_HEADER:
- break;
- case HAL_PARAM_VENC_MPEG4_AC_PREDICTION:
- break;
case HAL_CONFIG_VENC_TARGET_BITRATE:
{
struct hfi_bitrate *hfi;
@@ -1590,14 +1515,6 @@
pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
break;
}
- case HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC:
- {
- create_pkt_enable(pkt->rg_property_data,
- HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
- ((struct hal_enable *)pdata)->enable);
- pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
- break;
- }
case HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY:
{
create_pkt_enable(pkt->rg_property_data,
@@ -1606,21 +1523,6 @@
pkt->size += sizeof(u32) + sizeof(struct hfi_enable);
break;
}
- case HAL_PARAM_MVC_BUFFER_LAYOUT:
- {
- struct hfi_mvc_buffer_layout_descp_type *hfi;
- struct hal_mvc_buffer_layout *layout_info = pdata;
-
- pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT;
- hfi = (struct hfi_mvc_buffer_layout_descp_type *)
- &pkt->rg_property_data[1];
- hfi->layout_type = get_hfi_layout(layout_info->layout_type);
- hfi->bright_view_first = layout_info->bright_view_first;
- hfi->ngap = layout_info->ngap;
- pkt->size += sizeof(u32) +
- sizeof(struct hfi_mvc_buffer_layout_descp_type);
- break;
- }
case HAL_PARAM_VENC_LTRMODE:
{
struct hfi_ltr_mode *hfi;
@@ -1731,14 +1633,6 @@
pkt->size += sizeof(u32) * 2;
break;
}
- case HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS:
- {
- pkt->rg_property_data[0] =
- HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER;
- pkt->rg_property_data[1] = *(u32 *)pdata;
- pkt->size += sizeof(u32) * 2;
- break;
- }
case HAL_PARAM_VENC_HIER_P_HYBRID_MODE:
{
pkt->rg_property_data[0] =
@@ -1937,7 +1831,6 @@
case HAL_PARAM_VDEC_MB_QUANTIZATION:
case HAL_PARAM_VDEC_NUM_CONCEALED_MB:
case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING:
- case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING:
case HAL_CONFIG_BUFFER_COUNT_ACTUAL:
case HAL_CONFIG_VDEC_MULTI_STREAM:
case HAL_PARAM_VENC_MULTI_SLICE_INFO:
diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index abc6cc8..7c99e90 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -26,13 +26,6 @@
#define MAX_OPERATING_FRAME_RATE (300 << 16)
#define OPERATING_FRAME_RATE_STEP (1 << 16)
-static const char *const mpeg_video_vidc_divx_format[] = {
- "DIVX Format 3",
- "DIVX Format 4",
- "DIVX Format 5",
- "DIVX Format 6",
- NULL
-};
static const char *const mpeg_video_stream_format[] = {
"NAL Format Start Codes",
"NAL Format One NAL Per Buffer",
@@ -57,29 +50,6 @@
"Turbo"
};
-static const char *const h263_level[] = {
- "1.0",
- "2.0",
- "3.0",
- "4.0",
- "4.5",
- "5.0",
- "6.0",
- "7.0",
-};
-
-static const char *const h263_profile[] = {
- "Baseline",
- "H320 Coding",
- "Backward Compatible",
- "ISWV2",
- "ISWV3",
- "High Compression",
- "Internet",
- "Interlace",
- "High Latency",
-};
-
static const char *const vp8_profile_level[] = {
"Unused",
"0.0",
@@ -108,11 +78,6 @@
"CABAC Entropy Mode",
};
-static const char *const mpeg_vidc_video_h264_mvc_layout[] = {
- "Frame packing arrangement sequential",
- "Frame packing arrangement top-bottom",
-};
-
static const char *const mpeg_vidc_video_dpb_color_format[] = {
"DPB Color Format None",
"DPB Color Format UBWC",
@@ -462,37 +427,6 @@
return frame_size;
}
-static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
- struct v4l2_ctrl *ctrl)
-{
- int rc = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
- ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) {
- dprintk(VIDC_ERR,
- "Profile %#x not supported for MVC\n",
- ctrl->val);
- rc = -ENOTSUPP;
- break;
- }
- break;
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264_MVC &&
- ctrl->val >= V4L2_MPEG_VIDEO_H264_LEVEL_5_2) {
- dprintk(VIDC_ERR, "Level %#x not supported for MVC\n",
- ctrl->val);
- rc = -ENOTSUPP;
- break;
- }
- break;
- default:
- break;
- }
- return rc;
-}
-
struct msm_vidc_format vdec_formats[] = {
{
.name = "YCbCr Semiplanar 4:2:0",
@@ -516,14 +450,6 @@
.type = CAPTURE_PORT,
},
{
- .name = "Mpeg4",
- .description = "Mpeg4 compressed format",
- .fourcc = V4L2_PIX_FMT_MPEG4,
- .get_frame_size = get_frame_size_compressed,
- .type = OUTPUT_PORT,
- .defer_outputs = false,
- },
- {
.name = "Mpeg2",
.description = "Mpeg2 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG2,
@@ -532,30 +458,6 @@
.defer_outputs = false,
},
{
- .name = "H263",
- .description = "H263 compressed format",
- .fourcc = V4L2_PIX_FMT_H263,
- .get_frame_size = get_frame_size_compressed,
- .type = OUTPUT_PORT,
- .defer_outputs = false,
- },
- {
- .name = "VC1",
- .description = "VC-1 compressed format",
- .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
- .get_frame_size = get_frame_size_compressed,
- .type = OUTPUT_PORT,
- .defer_outputs = false,
- },
- {
- .name = "VC1 SP",
- .description = "VC-1 compressed format G",
- .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
- .get_frame_size = get_frame_size_compressed,
- .type = OUTPUT_PORT,
- .defer_outputs = false,
- },
- {
.name = "H264",
.description = "H264 compressed format",
.fourcc = V4L2_PIX_FMT_H264,
@@ -564,14 +466,6 @@
.defer_outputs = false,
},
{
- .name = "H264_MVC",
- .description = "H264_MVC compressed format",
- .fourcc = V4L2_PIX_FMT_H264_MVC,
- .get_frame_size = get_frame_size_compressed,
- .type = OUTPUT_PORT,
- .defer_outputs = false,
- },
- {
.name = "HEVC",
.description = "HEVC compressed format",
.fourcc = V4L2_PIX_FMT_HEVC,
@@ -826,10 +720,6 @@
}
hdev = inst->core->device;
- rc = is_ctrl_valid_for_codec(inst, ctrl);
- if (rc)
- return rc;
-
/* Small helper macro for quickly getting a control and err checking */
#define TRY_GET_CTRL(__ctrl_id) ({ \
struct v4l2_ctrl *__temp; \
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 64937aa..13cc1b2 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -37,11 +37,6 @@
#define MAX_HYBRID_HIER_P_LAYERS 6
#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
-#define CODING V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY
-#define BITSTREAM_RESTRICT_ENABLED \
- V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED
-#define BITSTREAM_RESTRICT_DISABLED \
- V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED
#define MIN_TIME_RESOLUTION 1
#define MAX_TIME_RESOLUTION 0xFFFFFF
#define DEFAULT_TIME_RESOLUTION 0x7530
@@ -774,72 +769,6 @@
.qmenu = NULL,
},
{
- .id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE,
- .name = "I-Frame X coordinate search range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 4,
- .maximum = 128,
- .default_value = 4,
- .step = 1,
- .menu_skip_mask = 0,
- .qmenu = NULL,
- },
- {
- .id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE,
- .name = "I-Frame Y coordinate search range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 4,
- .maximum = 128,
- .default_value = 4,
- .step = 1,
- .menu_skip_mask = 0,
- .qmenu = NULL,
- },
- {
- .id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE,
- .name = "P-Frame X coordinate search range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 4,
- .maximum = 128,
- .default_value = 4,
- .step = 1,
- .menu_skip_mask = 0,
- .qmenu = NULL,
- },
- {
- .id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE,
- .name = "P-Frame Y coordinate search range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 4,
- .maximum = 128,
- .default_value = 4,
- .step = 1,
- .menu_skip_mask = 0,
- .qmenu = NULL,
- },
- {
- .id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE,
- .name = "B-Frame X coordinate search range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 4,
- .maximum = 128,
- .default_value = 4,
- .step = 1,
- .menu_skip_mask = 0,
- .qmenu = NULL,
- },
- {
- .id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE,
- .name = "B-Frame Y coordinate search range",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .minimum = 4,
- .maximum = 128,
- .default_value = 4,
- .step = 1,
- .menu_skip_mask = 0,
- .qmenu = NULL,
- },
- {
.id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS,
.name = "Set Hier B num layers",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -1258,7 +1187,7 @@
struct hal_ltr_use use_ltr;
struct hal_ltr_mark mark_ltr;
struct hal_hybrid_hierp hyb_hierp;
- u32 hier_p_layers = 0, hier_b_layers = 0;
+ u32 hier_p_layers = 0;
int max_hierp_layers;
int baselayerid = 0;
struct hal_video_signal_info signal_info = {0};
@@ -1475,28 +1404,6 @@
temp_ctrl->val);
pdata = &h264_entropy_control;
break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
- temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL);
-
- property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
- profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id,
- ctrl->val);
- profile_level.level = msm_comm_v4l2_to_hal(
- V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
- temp_ctrl->val);
- pdata = &profile_level;
- break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
- temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE);
-
- property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT;
- profile_level.level = msm_comm_v4l2_to_hal(ctrl->id,
- ctrl->val);
- profile_level.profile = msm_comm_v4l2_to_hal(
- V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
- temp_ctrl->val);
- pdata = &profile_level;
- break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
@@ -1715,6 +1622,8 @@
enable.enable = 0;
break;
case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME:
+ enable.enable = 1;
+ break;
default:
rc = -ENOTSUPP;
break;
@@ -1835,16 +1744,6 @@
enable.enable = ctrl->val;
pdata = &enable;
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS:
- if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) {
- dprintk(VIDC_ERR, "Hier B supported for HEVC only\n");
- rc = -ENOTSUPP;
- break;
- }
- property_id = HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS;
- hier_b_layers = ctrl->val;
- pdata = &hier_b_layers;
- break;
case V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE:
property_id = HAL_PARAM_VENC_HIER_P_HYBRID_MODE;
hyb_hierp.layers = ctrl->val;
@@ -2081,7 +1980,6 @@
struct v4l2_ext_control *control;
struct hfi_device *hdev;
struct hal_ltr_mode ltr_mode;
- struct hal_vc1e_perf_cfg_type search_range = { {0} };
u32 property_id = 0, layer_id = MSM_VIDC_ALL_LAYER_ID;
void *pdata = NULL;
struct msm_vidc_capability *cap = NULL;
@@ -2136,36 +2034,6 @@
property_id = HAL_PARAM_VENC_LTRMODE;
pdata = <r_mode;
break;
- case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE:
- search_range.i_frame.x_subsampled = control[i].value;
- property_id = HAL_PARAM_VENC_SEARCH_RANGE;
- pdata = &search_range;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE:
- search_range.i_frame.y_subsampled = control[i].value;
- property_id = HAL_PARAM_VENC_SEARCH_RANGE;
- pdata = &search_range;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE:
- search_range.p_frame.x_subsampled = control[i].value;
- property_id = HAL_PARAM_VENC_SEARCH_RANGE;
- pdata = &search_range;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE:
- search_range.p_frame.y_subsampled = control[i].value;
- property_id = HAL_PARAM_VENC_SEARCH_RANGE;
- pdata = &search_range;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE:
- search_range.b_frame.x_subsampled = control[i].value;
- property_id = HAL_PARAM_VENC_SEARCH_RANGE;
- pdata = &search_range;
- break;
- case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE:
- search_range.b_frame.y_subsampled = control[i].value;
- property_id = HAL_PARAM_VENC_SEARCH_RANGE;
- pdata = &search_range;
- break;
case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH:
sar.aspect_width = control[i].value;
property_id = HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c
index 270fc31..114a702 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc.c
@@ -1820,14 +1820,12 @@
switch (ctrl->id) {
- case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
ctrl->val = inst->profile;
break;
- case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
ctrl->val = inst->level;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 74e68e4..5e49f42 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -52,8 +52,6 @@
"Extradata none",
"Extradata MB Quantization",
"Extradata Interlace Video",
- "Extradata VC1 Framedisp",
- "Extradata VC1 Seqdisp",
"Extradata timestamp",
"Extradata S3D Frame Packing",
"Extradata Frame Rate",
@@ -715,22 +713,13 @@
case V4L2_PIX_FMT_H264_MVC:
codec = HAL_VIDEO_CODEC_MVC;
break;
- case V4L2_PIX_FMT_H263:
- codec = HAL_VIDEO_CODEC_H263;
- break;
+
case V4L2_PIX_FMT_MPEG1:
codec = HAL_VIDEO_CODEC_MPEG1;
break;
case V4L2_PIX_FMT_MPEG2:
codec = HAL_VIDEO_CODEC_MPEG2;
break;
- case V4L2_PIX_FMT_MPEG4:
- codec = HAL_VIDEO_CODEC_MPEG4;
- break;
- case V4L2_PIX_FMT_VC1_ANNEX_G:
- case V4L2_PIX_FMT_VC1_ANNEX_L:
- codec = HAL_VIDEO_CODEC_VC1;
- break;
case V4L2_PIX_FMT_VP8:
codec = HAL_VIDEO_CODEC_VP8;
break;
@@ -766,9 +755,6 @@
case V4L2_PIX_FMT_NV12_TP10_UBWC:
format = HAL_COLOR_FORMAT_NV12_TP10_UBWC;
break;
- case V4L2_PIX_FMT_RGB32:
- format = HAL_COLOR_FORMAT_RGBA8888;
- break;
default:
format = HAL_UNUSED_COLOR;
break;
@@ -2434,55 +2420,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 +2464,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..eb36b33 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -539,7 +539,8 @@
*pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0;
- if (msm_vidc_debug & VIDC_PKT) {
+ if ((msm_vidc_debug & VIDC_PKT) &&
+ !(queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q)) {
dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo);
__dump_packet(packet, VIDC_PKT);
}
@@ -3176,14 +3177,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.h b/drivers/media/platform/msm/vidc/vidc_hfi.h
index 7caff53..2a833dc 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi.h
@@ -73,8 +73,6 @@
#define HFI_EXTRADATA_NONE 0x00000000
#define HFI_EXTRADATA_MB_QUANTIZATION 0x00000001
#define HFI_EXTRADATA_INTERLACE_VIDEO 0x00000002
-#define HFI_EXTRADATA_VC1_FRAMEDISP 0x00000003
-#define HFI_EXTRADATA_VC1_SEQDISP 0x00000004
#define HFI_EXTRADATA_TIMESTAMP 0x00000005
#define HFI_EXTRADATA_S3D_FRAME_PACKING 0x00000006
#define HFI_EXTRADATA_FRAME_RATE 0x00000007
@@ -132,8 +130,6 @@
(HFI_PROPERTY_PARAM_OX_START + 0x001)
#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO \
(HFI_PROPERTY_PARAM_OX_START + 0x002)
-#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG \
- (HFI_PROPERTY_PARAM_OX_START + 0x005)
#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x006)
#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \
@@ -175,10 +171,6 @@
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C)
#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D)
-#define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011)
-#define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA \
- (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x012)
#define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013)
#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA \
@@ -206,8 +198,6 @@
#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x4000)
-#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER \
- (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001)
#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING \
(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002)
#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP \
@@ -279,14 +269,6 @@
u32 picture_type;
};
-struct hfi_extra_data_header_config {
- u32 type;
- u32 buffer_type;
- u32 version;
- u32 port_index;
- u32 client_extra_data_id;
-};
-
struct hfi_mb_error_map {
u32 error_map_size;
u8 rg_error_map[1];
@@ -720,35 +702,6 @@
u8 rg_mb_qp[1];
};
-struct hfi_extradata_vc1_pswnd {
- u32 ps_wnd_h_offset;
- u32 ps_wnd_v_offset;
- u32 ps_wnd_width;
- u32 ps_wnd_height;
-};
-
-struct hfi_extradata_vc1_framedisp_payload {
- u32 res_pic;
- u32 ref;
- u32 range_map_present;
- u32 range_map_y;
- u32 range_map_uv;
- u32 num_pan_scan_wnds;
- struct hfi_extradata_vc1_pswnd rg_ps_wnd[1];
-};
-
-struct hfi_extradata_vc1_seqdisp_payload {
- u32 prog_seg_frm;
- u32 uv_sampling_fmt;
- u32 color_fmt_flag;
- u32 color_primaries;
- u32 transfer_char;
- u32 mat_coeff;
- u32 aspect_ratio;
- u32 aspect_horiz;
- u32 aspect_vert;
-};
-
struct hfi_extradata_timestamp_payload {
u32 time_stamp_low;
u32 time_stamp_high;
@@ -836,10 +789,6 @@
u32 aspect_width;
u32 aspect_height;
};
-struct hfi_extradata_panscan_wndw_payload {
- u32 num_window;
- struct hfi_extradata_vc1_pswnd wnd[1];
-};
struct hfi_extradata_frame_type_payload {
u32 frame_rate;
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index d60a0d1..8aa0bbb 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -98,8 +98,6 @@
HAL_EXTRADATA_NONE,
HAL_EXTRADATA_MB_QUANTIZATION,
HAL_EXTRADATA_INTERLACE_VIDEO,
- HAL_EXTRADATA_VC1_FRAMEDISP,
- HAL_EXTRADATA_VC1_SEQDISP,
HAL_EXTRADATA_TIMESTAMP,
HAL_EXTRADATA_S3D_FRAME_PACKING,
HAL_EXTRADATA_FRAME_RATE,
@@ -134,7 +132,6 @@
HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT,
HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO,
HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO,
- HAL_PARAM_EXTRA_DATA_HEADER_CONFIG,
HAL_PARAM_INDEX_EXTRADATA,
HAL_PARAM_FRAME_SIZE,
HAL_CONFIG_REALTIME,
@@ -144,22 +141,16 @@
HAL_PARAM_VDEC_OUTPUT_ORDER,
HAL_PARAM_VDEC_PICTURE_TYPE_DECODE,
HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO,
- HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER,
HAL_PARAM_VDEC_MULTI_STREAM,
HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT,
- HAL_PARAM_DIVX_FORMAT,
HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING,
HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER,
HAL_CONFIG_VDEC_MB_ERROR_MAP,
HAL_CONFIG_VENC_REQUEST_IFRAME,
- HAL_PARAM_VENC_MPEG4_SHORT_HEADER,
- HAL_PARAM_VENC_MPEG4_AC_PREDICTION,
HAL_CONFIG_VENC_TARGET_BITRATE,
HAL_PARAM_PROFILE_LEVEL_CURRENT,
HAL_PARAM_VENC_H264_ENTROPY_CONTROL,
HAL_PARAM_VENC_RATE_CONTROL,
- HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION,
- HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION,
HAL_PARAM_VENC_H264_DEBLOCK_CONTROL,
HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF,
HAL_PARAM_VENC_SESSION_QP_RANGE,
@@ -190,7 +181,6 @@
HAL_PARAM_VDEC_NUM_CONCEALED_MB,
HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING,
HAL_PARAM_VENC_SLICE_DELIVERY_MODE,
- HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING,
HAL_CONFIG_BUFFER_COUNT_ACTUAL,
HAL_CONFIG_VDEC_MULTI_STREAM,
HAL_PARAM_VENC_MULTI_SLICE_INFO,
@@ -204,12 +194,10 @@
HAL_PARAM_VENC_MAX_NUM_B_FRAMES,
HAL_PARAM_BUFFER_ALLOC_MODE,
HAL_PARAM_VDEC_FRAME_ASSEMBLY,
- HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC,
HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY,
HAL_PARAM_VDEC_CONCEAL_COLOR,
HAL_PARAM_VDEC_SCS_THRESHOLD,
HAL_PARAM_GET_BUFFER_REQUIREMENTS,
- HAL_PARAM_MVC_BUFFER_LAYOUT,
HAL_PARAM_VENC_LTRMODE,
HAL_CONFIG_VENC_MARKLTRFRAME,
HAL_CONFIG_VENC_USELTRFRAME,
@@ -221,7 +209,6 @@
HAL_PARAM_VPE_COLOR_SPACE_CONVERSION,
HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE,
HAL_CONFIG_VENC_PERF_MODE,
- HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS,
HAL_PARAM_VDEC_NON_SECURE_OUTPUT2,
HAL_PARAM_VENC_HIER_P_HYBRID_MODE,
HAL_PARAM_VENC_MBI_STATISTICS_MODE,
@@ -232,7 +219,6 @@
HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO,
HAL_CONFIG_VDEC_ENTROPY,
HAL_PARAM_VENC_BITRATE_TYPE,
- HAL_PARAM_VENC_H264_PIC_ORDER_CNT,
HAL_PARAM_VENC_LOW_LATENCY,
HAL_CONFIG_VENC_BLUR_RESOLUTION,
HAL_PARAM_VENC_H264_TRANSFORM_8x8,
@@ -289,31 +275,6 @@
HAL_UNUSED_CODEC = 0x10000000,
};
-enum hal_h263_profile {
- HAL_H263_PROFILE_BASELINE = 0x00000001,
- HAL_H263_PROFILE_H320CODING = 0x00000002,
- HAL_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004,
- HAL_H263_PROFILE_ISWV2 = 0x00000008,
- HAL_H263_PROFILE_ISWV3 = 0x00000010,
- HAL_H263_PROFILE_HIGHCOMPRESSION = 0x00000020,
- HAL_H263_PROFILE_INTERNET = 0x00000040,
- HAL_H263_PROFILE_INTERLACE = 0x00000080,
- HAL_H263_PROFILE_HIGHLATENCY = 0x00000100,
- HAL_UNUSED_H263_PROFILE = 0x10000000,
-};
-
-enum hal_h263_level {
- HAL_H263_LEVEL_10 = 0x00000001,
- HAL_H263_LEVEL_20 = 0x00000002,
- HAL_H263_LEVEL_30 = 0x00000004,
- HAL_H263_LEVEL_40 = 0x00000008,
- HAL_H263_LEVEL_45 = 0x00000010,
- HAL_H263_LEVEL_50 = 0x00000020,
- HAL_H263_LEVEL_60 = 0x00000040,
- HAL_H263_LEVEL_70 = 0x00000080,
- HAL_UNUSED_H263_LEVEL = 0x10000000,
-};
-
enum hal_mpeg2_profile {
HAL_MPEG2_PROFILE_SIMPLE = 0x00000001,
HAL_MPEG2_PROFILE_MAIN = 0x00000002,
@@ -332,44 +293,6 @@
HAL_UNUSED_MEPG2_LEVEL = 0x10000000,
};
-enum hal_mpeg4_profile {
- HAL_MPEG4_PROFILE_SIMPLE = 0x00000001,
- HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00000002,
- HAL_MPEG4_PROFILE_CORE = 0x00000004,
- HAL_MPEG4_PROFILE_MAIN = 0x00000008,
- HAL_MPEG4_PROFILE_NBIT = 0x00000010,
- HAL_MPEG4_PROFILE_SCALABLETEXTURE = 0x00000020,
- HAL_MPEG4_PROFILE_SIMPLEFACE = 0x00000040,
- HAL_MPEG4_PROFILE_SIMPLEFBA = 0x00000080,
- HAL_MPEG4_PROFILE_BASICANIMATED = 0x00000100,
- HAL_MPEG4_PROFILE_HYBRID = 0x00000200,
- HAL_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400,
- HAL_MPEG4_PROFILE_CORESCALABLE = 0x00000800,
- HAL_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000,
- HAL_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000,
- HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000,
- HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00008000,
- HAL_UNUSED_MPEG4_PROFILE = 0x10000000,
-};
-
-enum hal_mpeg4_level {
- HAL_MPEG4_LEVEL_0 = 0x00000001,
- HAL_MPEG4_LEVEL_0b = 0x00000002,
- HAL_MPEG4_LEVEL_1 = 0x00000004,
- HAL_MPEG4_LEVEL_2 = 0x00000008,
- HAL_MPEG4_LEVEL_3 = 0x00000010,
- HAL_MPEG4_LEVEL_4 = 0x00000020,
- HAL_MPEG4_LEVEL_4a = 0x00000040,
- HAL_MPEG4_LEVEL_5 = 0x00000080,
- HAL_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000,
- HAL_MPEG4_LEVEL_6 = 0x7F000001,
- HAL_MPEG4_LEVEL_7 = 0x7F000002,
- HAL_MPEG4_LEVEL_8 = 0x7F000003,
- HAL_MPEG4_LEVEL_9 = 0x7F000004,
- HAL_MPEG4_LEVEL_3b = 0x7F000005,
- HAL_UNUSED_MPEG4_LEVEL = 0x10000000,
-};
-
enum hal_h264_profile {
HAL_H264_PROFILE_BASELINE = 0x00000001,
HAL_H264_PROFILE_MAIN = 0x00000002,
@@ -457,66 +380,6 @@
HAL_VPX_PROFILE_UNUSED = 0x10000000,
};
-enum hal_vc1_profile {
- HAL_VC1_PROFILE_SIMPLE = 0x00000001,
- HAL_VC1_PROFILE_MAIN = 0x00000002,
- HAL_VC1_PROFILE_ADVANCED = 0x00000004,
- HAL_UNUSED_VC1_PROFILE = 0x10000000,
-};
-
-enum hal_vc1_level {
- HAL_VC1_LEVEL_LOW = 0x00000001,
- HAL_VC1_LEVEL_MEDIUM = 0x00000002,
- HAL_VC1_LEVEL_HIGH = 0x00000004,
- HAL_VC1_LEVEL_0 = 0x00000008,
- HAL_VC1_LEVEL_1 = 0x00000010,
- HAL_VC1_LEVEL_2 = 0x00000020,
- HAL_VC1_LEVEL_3 = 0x00000040,
- HAL_VC1_LEVEL_4 = 0x00000080,
- HAL_UNUSED_VC1_LEVEL = 0x10000000,
-};
-
-enum hal_divx_format {
- HAL_DIVX_FORMAT_4,
- HAL_DIVX_FORMAT_5,
- HAL_DIVX_FORMAT_6,
- HAL_UNUSED_DIVX_FORMAT = 0x10000000,
-};
-
-enum hal_divx_profile {
- HAL_DIVX_PROFILE_QMOBILE = 0x00000001,
- HAL_DIVX_PROFILE_MOBILE = 0x00000002,
- HAL_DIVX_PROFILE_MT = 0x00000004,
- HAL_DIVX_PROFILE_HT = 0x00000008,
- HAL_DIVX_PROFILE_HD = 0x00000010,
- HAL_UNUSED_DIVX_PROFILE = 0x10000000,
-};
-
-enum hal_mvc_profile {
- HAL_MVC_PROFILE_STEREO_HIGH = 0x00001000,
- HAL_UNUSED_MVC_PROFILE = 0x10000000,
-};
-
-enum hal_mvc_level {
- HAL_MVC_LEVEL_1 = 0x00000001,
- HAL_MVC_LEVEL_1b = 0x00000002,
- HAL_MVC_LEVEL_11 = 0x00000004,
- HAL_MVC_LEVEL_12 = 0x00000008,
- HAL_MVC_LEVEL_13 = 0x00000010,
- HAL_MVC_LEVEL_2 = 0x00000020,
- HAL_MVC_LEVEL_21 = 0x00000040,
- HAL_MVC_LEVEL_22 = 0x00000080,
- HAL_MVC_LEVEL_3 = 0x00000100,
- HAL_MVC_LEVEL_31 = 0x00000200,
- HAL_MVC_LEVEL_32 = 0x00000400,
- HAL_MVC_LEVEL_4 = 0x00000800,
- HAL_MVC_LEVEL_41 = 0x00001000,
- HAL_MVC_LEVEL_42 = 0x00002000,
- HAL_MVC_LEVEL_5 = 0x00004000,
- HAL_MVC_LEVEL_51 = 0x00008000,
- HAL_UNUSED_MVC_LEVEL = 0x10000000,
-};
-
struct hal_frame_rate {
enum hal_buffer buffer_type;
u32 frame_rate;
@@ -585,14 +448,6 @@
struct hal_uncompressed_plane_constraints rg_plane_format[1];
};
-struct hal_extra_data_header_config {
- u32 type;
- enum hal_buffer buffer_type;
- u32 version;
- u32 port_index;
- u32 client_extradata_id;
-};
-
struct hal_frame_size {
enum hal_buffer buffer_type;
u32 width;
@@ -718,14 +573,6 @@
HAL_UNUSED_RC = 0x10000000,
};
-struct hal_mpeg4_time_resolution {
- u32 time_increment_resolution;
-};
-
-struct hal_mpeg4_header_extension {
- u32 header_extension;
-};
-
enum hal_h264_db_mode {
HAL_H264_DB_MODE_DISABLE,
HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY,
@@ -946,12 +793,6 @@
HAL_UNUSED_BUFFER_LAYOUT = 0x10000000,
};
-struct hal_mvc_buffer_layout {
- enum hal_buffer_layout_type layout_type;
- u32 bright_view_first;
- u32 ngap;
-};
-
struct hal_aspect_ratio {
u32 aspect_width;
u32 aspect_height;
@@ -985,13 +826,6 @@
u32 enable;
};
-struct hal_vc1e_perf_cfg_type {
- struct {
- u32 x_subsampled;
- u32 y_subsampled;
- } i_frame, p_frame, b_frame;
-};
-
struct hal_vpe_color_space_conversion {
u32 csc_matrix[HAL_MAX_MATRIX_COEFFS];
u32 csc_bias[HAL_MAX_BIAS_COEFFS];
@@ -1105,7 +939,6 @@
enum ltr_mode {
HAL_LTR_MODE_DISABLE,
HAL_LTR_MODE_MANUAL,
- HAL_LTR_MODE_PERIODIC,
};
struct hal_ltr_mode {
@@ -1149,7 +982,6 @@
struct hal_uncompressed_plane_constraints plane_constraints;
struct hal_uncompressed_plane_actual_constraints_info
plane_constraints_info;
- struct hal_extra_data_header_config extra_data_header_config;
struct hal_frame_size frame_size;
struct hal_enable enable;
struct hal_buffer_count_actual buffer_count_actual;
@@ -1162,8 +994,6 @@
struct hal_bitrate bitrate;
struct hal_profile_level profile_level;
struct hal_profile_level_supported profile_level_supported;
- struct hal_mpeg4_time_resolution mpeg4_time_resolution;
- struct hal_mpeg4_header_extension mpeg4_header_extension;
struct hal_h264_db_control h264_db_control;
struct hal_temporal_spatial_tradeoff temporal_spatial_tradeoff;
struct hal_quantization quantization;
@@ -1227,8 +1057,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/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index dc64ad2..0d73410 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -81,7 +81,6 @@
#define HFI_VIDEO_CODEC_VP8 0x00001000
#define HFI_VIDEO_CODEC_HEVC 0x00002000
#define HFI_VIDEO_CODEC_VP9 0x00004000
-#define HFI_VIDEO_CODEC_HEVC_HYBRID 0x80000000
#define HFI_PROFILE_UNKNOWN 0x00000000
#define HFI_H264_PROFILE_BASELINE 0x00000001
@@ -214,8 +213,6 @@
(HFI_PROPERTY_PARAM_COMMON_START + 0x00C)
#define HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED \
(HFI_PROPERTY_PARAM_COMMON_START + 0x00E)
-#define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT \
- (HFI_PROPERTY_PARAM_COMMON_START + 0x00F)
#define HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED \
(HFI_PROPERTY_PARAM_COMMON_START + 0x010)
@@ -281,8 +278,6 @@
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01E)
#define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020)
-#define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC \
- (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x021)
#define HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE \
(HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x022)
#define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY \
@@ -549,7 +544,6 @@
#define HFI_LTR_MODE_DISABLE 0x0
#define HFI_LTR_MODE_MANUAL 0x1
-#define HFI_LTR_MODE_PERIODIC 0x2
struct hfi_ltr_mode {
u32 ltr_mode;
@@ -744,7 +738,6 @@
u32 close_gop;
u32 h264_constrain_intra_pred;
u32 h264_transform_8x8_flag;
- u32 mpeg4_qpel_enable;
u32 multi_refp_en;
u32 qmatrix_en;
u8 vpp_info_packet_mode;
@@ -786,15 +779,6 @@
u32 type;
};
-#define HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM (0)
-#define HFI_MVC_BUFFER_LAYOUT_SIDEBYSIDE (1)
-#define HFI_MVC_BUFFER_LAYOUT_SEQ (2)
-struct hfi_mvc_buffer_layout_descp_type {
- u32 layout_type;
- u32 bright_view_first;
- u32 ngap;
-};
-
#define HFI_CMD_SYS_COMMON_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + HFI_CMD_START_OFFSET \
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 5818986..1d1928a 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1363,6 +1363,10 @@
case V4L2_PIX_FMT_JPGL: descr = "JPEG Lite"; break;
case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break;
case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break;
+ case V4L2_PIX_FMT_HEVC:
+ descr = "HEVC"; break;
+ case V4L2_PIX_FMT_VP9:
+ descr = "VP9"; break;
default:
WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat);
if (fmt->description[0])
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 1a50f37..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);
@@ -704,20 +705,27 @@
static int wcd9xxx_irq_probe(struct platform_device *pdev)
{
- int irq;
+ int irq, dir_apps_irq = -EINVAL;
struct wcd9xxx_irq_drv_data *data;
struct device_node *node = pdev->dev.of_node;
int ret = -EINVAL;
irq = of_get_named_gpio(node, "qcom,gpio-connect", 0);
- if (!gpio_is_valid(irq)) {
+ if (!gpio_is_valid(irq))
+ dir_apps_irq = platform_get_irq_byname(pdev, "wcd_irq");
+
+ if (!gpio_is_valid(irq) && dir_apps_irq < 0) {
dev_err(&pdev->dev, "TLMM connect gpio not found\n");
return -EPROBE_DEFER;
}
- irq = gpio_to_irq(irq);
- if (irq < 0) {
- dev_err(&pdev->dev, "Unable to configure irq\n");
- return irq;
+ if (dir_apps_irq > 0) {
+ irq = dir_apps_irq;
+ } else {
+ irq = gpio_to_irq(irq);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "Unable to configure irq\n");
+ return irq;
+ }
}
dev_dbg(&pdev->dev, "%s: virq = %d\n", __func__, irq);
data = wcd9xxx_irq_add_domain(node, node->parent);
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/Kconfig b/drivers/misc/Kconfig
index 9c9d130..d593315 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -780,6 +780,15 @@
help
Memory time statistics exported to /sys/kernel/memory_state_time
+config QPNP_MISC
+ tristate "QPNP Misc Peripheral"
+ depends on MFD_SPMI_PMIC
+ help
+ Say 'y' here to include support for the QTI QPNP MISC
+ peripheral. The MISC peripheral holds the USB ID interrupt
+ and the driver provides an API to check if this interrupt
+ is available on the current PMIC chip.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 19f9e1d..dd12e9a 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -53,6 +53,7 @@
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
obj-$(CONFIG_CXL_BASE) += cxl/
obj-$(CONFIG_PANEL) += panel.o
+obj-$(CONFIG_QPNP_MISC) += qpnp-misc.o
obj-y += qcom/
obj-$(CONFIG_MEMORY_STATE_TIME) += memory_state_time.o
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/misc/qpnp-misc.c b/drivers/misc/qpnp-misc.c
new file mode 100644
index 0000000..3c11de0
--- /dev/null
+++ b/drivers/misc/qpnp-misc.c
@@ -0,0 +1,352 @@
+/* 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.
+ *
+ * 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.
+ */
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/qpnp/qpnp-misc.h>
+
+#define QPNP_MISC_DEV_NAME "qcom,qpnp-misc"
+
+#define REG_DIG_MAJOR_REV 0x01
+#define REG_SUBTYPE 0x05
+#define REG_PWM_SEL 0x49
+#define REG_GP_DRIVER_EN 0x4C
+
+#define PWM_SEL_MAX 0x03
+#define GP_DRIVER_EN_BIT BIT(0)
+
+static DEFINE_MUTEX(qpnp_misc_dev_list_mutex);
+static LIST_HEAD(qpnp_misc_dev_list);
+
+struct qpnp_misc_version {
+ u8 subtype;
+ u8 dig_major_rev;
+};
+
+/**
+ * struct qpnp_misc_dev - holds controller device specific information
+ * @list: Doubly-linked list parameter linking to other
+ * qpnp_misc devices.
+ * @mutex: Mutex lock that is used to ensure mutual
+ * exclusion between probing and accessing misc
+ * driver information
+ * @dev: Device pointer to the misc device
+ * @regmap: Regmap pointer to the misc device
+ * @version: struct that holds the subtype and dig_major_rev
+ * of the chip.
+ */
+struct qpnp_misc_dev {
+ struct list_head list;
+ struct mutex mutex;
+ struct device *dev;
+ struct regmap *regmap;
+ struct qpnp_misc_version version;
+
+ u32 base;
+ u8 pwm_sel;
+ bool enable_gp_driver;
+};
+
+static const struct of_device_id qpnp_misc_match_table[] = {
+ { .compatible = QPNP_MISC_DEV_NAME },
+ {}
+};
+
+enum qpnp_misc_version_name {
+ INVALID,
+ PM8941,
+ PM8226,
+ PMA8084,
+ PMDCALIFORNIUM,
+};
+
+static struct qpnp_misc_version irq_support_version[] = {
+ {0x00, 0x00}, /* INVALID */
+ {0x01, 0x02}, /* PM8941 */
+ {0x07, 0x00}, /* PM8226 */
+ {0x09, 0x00}, /* PMA8084 */
+ {0x16, 0x00}, /* PMDCALIFORNIUM */
+};
+
+static int qpnp_write_byte(struct qpnp_misc_dev *mdev, u16 addr, u8 val)
+{
+ int rc;
+
+ rc = regmap_write(mdev->regmap, mdev->base + addr, val);
+ if (rc)
+ pr_err("regmap write failed rc=%d\n", rc);
+
+ return rc;
+}
+
+static int qpnp_read_byte(struct qpnp_misc_dev *mdev, u16 addr, u8 *val)
+{
+ unsigned int temp;
+ int rc;
+
+ rc = regmap_read(mdev->regmap, mdev->base + addr, &temp);
+ if (rc) {
+ pr_err("regmap read failed rc=%d\n", rc);
+ return rc;
+ }
+
+ *val = (u8)temp;
+ return rc;
+}
+
+static int get_qpnp_misc_version_name(struct qpnp_misc_dev *dev)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(irq_support_version); i++)
+ if (dev->version.subtype == irq_support_version[i].subtype &&
+ dev->version.dig_major_rev >=
+ irq_support_version[i].dig_major_rev)
+ return i;
+
+ return INVALID;
+}
+
+static bool __misc_irqs_available(struct qpnp_misc_dev *dev)
+{
+ int version_name = get_qpnp_misc_version_name(dev);
+
+ if (version_name == INVALID)
+ return 0;
+ return 1;
+}
+
+int qpnp_misc_read_reg(struct device_node *node, u16 addr, u8 *val)
+{
+ struct qpnp_misc_dev *mdev = NULL;
+ struct qpnp_misc_dev *mdev_found = NULL;
+ int rc;
+ u8 temp;
+
+ if (IS_ERR_OR_NULL(node)) {
+ pr_err("Invalid device node pointer\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&qpnp_misc_dev_list_mutex);
+ list_for_each_entry(mdev, &qpnp_misc_dev_list, list) {
+ if (mdev->dev->of_node == node) {
+ mdev_found = mdev;
+ break;
+ }
+ }
+ mutex_unlock(&qpnp_misc_dev_list_mutex);
+
+ if (!mdev_found) {
+ /*
+ * No MISC device was found. This API should only
+ * be called by drivers which have specified the
+ * misc phandle in their device tree node.
+ */
+ pr_err("no probed misc device found\n");
+ return -EPROBE_DEFER;
+ }
+
+ rc = qpnp_read_byte(mdev, addr, &temp);
+ if (rc < 0) {
+ dev_err(mdev->dev, "Failed to read addr %x, rc=%d\n", addr, rc);
+ return rc;
+ }
+
+ *val = temp;
+ return 0;
+}
+
+int qpnp_misc_irqs_available(struct device *consumer_dev)
+{
+ struct device_node *misc_node = NULL;
+ struct qpnp_misc_dev *mdev = NULL;
+ struct qpnp_misc_dev *mdev_found = NULL;
+
+ if (IS_ERR_OR_NULL(consumer_dev)) {
+ pr_err("Invalid consumer device pointer\n");
+ return -EINVAL;
+ }
+
+ misc_node = of_parse_phandle(consumer_dev->of_node, "qcom,misc-ref", 0);
+ if (!misc_node) {
+ pr_debug("Could not find qcom,misc-ref property in %s\n",
+ consumer_dev->of_node->full_name);
+ return 0;
+ }
+
+ mutex_lock(&qpnp_misc_dev_list_mutex);
+ list_for_each_entry(mdev, &qpnp_misc_dev_list, list) {
+ if (mdev->dev->of_node == misc_node) {
+ mdev_found = mdev;
+ break;
+ }
+ }
+ mutex_unlock(&qpnp_misc_dev_list_mutex);
+
+ if (!mdev_found) {
+ /*
+ * No MISC device was found. This API should only
+ * be called by drivers which have specified the
+ * misc phandle in their device tree node.
+ */
+ pr_err("no probed misc device found\n");
+ return -EPROBE_DEFER;
+ }
+
+ return __misc_irqs_available(mdev_found);
+}
+
+static int qpnp_misc_dt_init(struct qpnp_misc_dev *mdev)
+{
+ struct device_node *node = mdev->dev->of_node;
+ u32 val;
+ int rc;
+
+ rc = of_property_read_u32(node, "reg", &mdev->base);
+ if (rc < 0 || !mdev->base) {
+ dev_err(mdev->dev, "Base address not defined or invalid\n");
+ return -EINVAL;
+ }
+
+ if (!of_property_read_u32(node, "qcom,pwm-sel", &val)) {
+ if (val > PWM_SEL_MAX) {
+ dev_err(mdev->dev, "Invalid value for pwm-sel\n");
+ return -EINVAL;
+ }
+ mdev->pwm_sel = (u8)val;
+ }
+ mdev->enable_gp_driver = of_property_read_bool(node,
+ "qcom,enable-gp-driver");
+
+ WARN((mdev->pwm_sel > 0 && !mdev->enable_gp_driver),
+ "Setting PWM source without enabling gp driver\n");
+ WARN((mdev->pwm_sel == 0 && mdev->enable_gp_driver),
+ "Enabling gp driver without setting PWM source\n");
+
+ return 0;
+}
+
+static int qpnp_misc_config(struct qpnp_misc_dev *mdev)
+{
+ int rc, version_name;
+
+ version_name = get_qpnp_misc_version_name(mdev);
+
+ switch (version_name) {
+ case PMDCALIFORNIUM:
+ if (mdev->pwm_sel > 0 && mdev->enable_gp_driver) {
+ rc = qpnp_write_byte(mdev, REG_PWM_SEL, mdev->pwm_sel);
+ if (rc < 0) {
+ dev_err(mdev->dev,
+ "Failed to write PWM_SEL reg\n");
+ return rc;
+ }
+
+ rc = qpnp_write_byte(mdev, REG_GP_DRIVER_EN,
+ GP_DRIVER_EN_BIT);
+ if (rc < 0) {
+ dev_err(mdev->dev,
+ "Failed to write GP_DRIVER_EN reg\n");
+ return rc;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int qpnp_misc_probe(struct platform_device *pdev)
+{
+ struct qpnp_misc_dev *mdev = ERR_PTR(-EINVAL);
+ int rc;
+
+ mdev = devm_kzalloc(&pdev->dev, sizeof(*mdev), GFP_KERNEL);
+ if (!mdev)
+ return -ENOMEM;
+
+ mdev->dev = &pdev->dev;
+ mdev->regmap = dev_get_regmap(mdev->dev->parent, NULL);
+ if (!mdev->regmap) {
+ dev_err(mdev->dev, "Parent regmap is unavailable\n");
+ return -ENXIO;
+ }
+
+ rc = qpnp_misc_dt_init(mdev);
+ if (rc < 0) {
+ dev_err(mdev->dev,
+ "Error reading device tree properties, rc=%d\n", rc);
+ return rc;
+ }
+
+
+ rc = qpnp_read_byte(mdev, REG_SUBTYPE, &mdev->version.subtype);
+ if (rc < 0) {
+ dev_err(mdev->dev, "Failed to read subtype, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_read_byte(mdev, REG_DIG_MAJOR_REV,
+ &mdev->version.dig_major_rev);
+ if (rc < 0) {
+ dev_err(mdev->dev, "Failed to read dig_major_rev, rc=%d\n", rc);
+ return rc;
+ }
+
+ mutex_lock(&qpnp_misc_dev_list_mutex);
+ list_add_tail(&mdev->list, &qpnp_misc_dev_list);
+ mutex_unlock(&qpnp_misc_dev_list_mutex);
+
+ rc = qpnp_misc_config(mdev);
+ if (rc < 0) {
+ dev_err(mdev->dev,
+ "Error configuring module registers, rc=%d\n", rc);
+ return rc;
+ }
+
+ dev_info(mdev->dev, "probe successful\n");
+ return 0;
+}
+
+static struct platform_driver qpnp_misc_driver = {
+ .probe = qpnp_misc_probe,
+ .driver = {
+ .name = QPNP_MISC_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_misc_match_table,
+ },
+};
+
+static int __init qpnp_misc_init(void)
+{
+ return platform_driver_register(&qpnp_misc_driver);
+}
+
+static void __exit qpnp_misc_exit(void)
+{
+ return platform_driver_unregister(&qpnp_misc_driver);
+}
+
+subsys_initcall(qpnp_misc_init);
+module_exit(qpnp_misc_exit);
+
+MODULE_DESCRIPTION(QPNP_MISC_DEV_NAME);
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_MISC_DEV_NAME);
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 817fcf8..ace47ae 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2324,10 +2324,7 @@
err = mmc_blk_reset(md, card->host, type);
if (!err)
break;
- if (err == -ENODEV ||
- mmc_packed_cmd(mq_rq->cmd_type))
- goto cmd_abort;
- /* Fall through */
+ goto cmd_abort;
}
case MMC_BLK_ECC_ERR:
if (brq->data.blocks > 1) {
@@ -2843,6 +2840,13 @@
MMC_QUIRK_LONG_READ_TIME),
/*
+ * Some Samsung MMC cards need longer data read timeout than
+ * indicated in CSD.
+ */
+ MMC_FIXUP("Q7XSAB", CID_MANFID_SAMSUNG, 0x100, add_quirk_mmc,
+ MMC_QUIRK_LONG_READ_TIME),
+
+ /*
* On these Samsung MoviNAND parts, performing secure erase or
* secure trim can result in unrecoverable corruption due to a
* firmware bug.
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..e19d912 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)
/*
@@ -1080,6 +1089,9 @@
if (pm)
pm_runtime_get_sync(mmc_dev(host));
+ if (host->ops->enable && !stop && host->claim_cnt == 1)
+ host->ops->enable(host);
+
return stop;
}
EXPORT_SYMBOL(__mmc_claim_host);
@@ -1097,6 +1109,9 @@
WARN_ON(!host->claimed);
+ if (host->ops->disable && host->claim_cnt == 1)
+ host->ops->disable(host);
+
spin_lock_irqsave(&host->lock, flags);
if (--host->claim_cnt) {
/* Release for nested claim */
@@ -1149,6 +1164,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 +1174,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 +1195,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 +1271,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 +1289,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 +1300,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 +1758,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 +1796,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 +1858,9 @@
mmc_power_cycle(host, ocr);
}
+err_command:
+ mmc_host_clk_release(host);
+
return err;
}
@@ -1773,8 +1869,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 +1880,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 +1891,7 @@
{
struct mmc_host *host = card->host;
int host_drv_type = SD_DRIVER_TYPE_B;
+ int drive_strength;
*drv_type = 0;
@@ -1813,10 +1914,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 +1940,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 +1975,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 +1984,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 +2001,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 +2216,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 +2739,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/Kconfig b/drivers/mmc/host/Kconfig
index 5274f50..defb66e 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -396,18 +396,26 @@
If unsure, say N.
config MMC_SDHCI_MSM
- tristate "Qualcomm SDHCI Controller Support"
- depends on ARCH_QCOM || (ARM && COMPILE_TEST)
+ tristate "Qualcomm Technologies, Inc. SDHCI Controller Support"
+ depends on ARCH_QCOM || ARCH_MSM || (ARM && COMPILE_TEST)
depends on MMC_SDHCI_PLTFM
help
This selects the Secure Digital Host Controller Interface (SDHCI)
- support present in Qualcomm SOCs. The controller supports
- SD/MMC/SDIO devices.
+ support present in Qualcomm Technologies, Inc. SOCs. The controller
+ supports SD/MMC/SDIO devices.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
+config MMC_MSM
+ tristate "Qualcomm SDCC Controller Support"
+ depends on MMC && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
+ help
+ This provides support for the SD/MMC cell found in the
+ MSM and QSD SOCs from Qualcomm. The controller also has
+ support for SDIO devices.
+
config MMC_MXC
tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"
depends on ARCH_MXC || PPC_MPC512x
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index e2bdaaf..ef56624 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -71,8 +71,8 @@
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
-obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
+obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
obj-$(CONFIG_MMC_SDHCI_MICROCHIP_PIC32) += sdhci-pic32.o
obj-$(CONFIG_MMC_SDHCI_BRCMSTB) += sdhci-brcmstb.o
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 90ed2e1..1861af0 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -1,7 +1,8 @@
/*
- * drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver
+ * drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform
+ * driver source file
*
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, 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
@@ -15,106 +16,218 @@
*/
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/gfp.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+#include <linux/io.h>
#include <linux/delay.h>
-#include <linux/mmc/mmc.h>
+#include <linux/scatterlist.h>
#include <linux/slab.h>
+#include <linux/mmc/mmc.h>
#include "sdhci-pltfm.h"
-#define CORE_MCI_VERSION 0x50
-#define CORE_VERSION_MAJOR_SHIFT 28
-#define CORE_VERSION_MAJOR_MASK (0xf << CORE_VERSION_MAJOR_SHIFT)
-#define CORE_VERSION_MINOR_MASK 0xff
-
+#define SDHCI_VER_100 0x2B
#define CORE_HC_MODE 0x78
#define HC_MODE_EN 0x1
-#define CORE_POWER 0x0
-#define CORE_SW_RST BIT(7)
-#define CORE_PWRCTL_STATUS 0xdc
-#define CORE_PWRCTL_MASK 0xe0
-#define CORE_PWRCTL_CLEAR 0xe4
-#define CORE_PWRCTL_CTL 0xe8
-#define CORE_PWRCTL_BUS_OFF BIT(0)
-#define CORE_PWRCTL_BUS_ON BIT(1)
-#define CORE_PWRCTL_IO_LOW BIT(2)
-#define CORE_PWRCTL_IO_HIGH BIT(3)
-#define CORE_PWRCTL_BUS_SUCCESS BIT(0)
-#define CORE_PWRCTL_IO_SUCCESS BIT(2)
-#define REQ_BUS_OFF BIT(0)
-#define REQ_BUS_ON BIT(1)
-#define REQ_IO_LOW BIT(2)
-#define REQ_IO_HIGH BIT(3)
-#define INT_MASK 0xf
+#define CORE_POWER 0x0
+#define CORE_SW_RST (1 << 7)
+
+#define CORE_PWRCTL_STATUS 0xDC
+#define CORE_PWRCTL_MASK 0xE0
+#define CORE_PWRCTL_CLEAR 0xE4
+#define CORE_PWRCTL_CTL 0xE8
+
+#define CORE_PWRCTL_BUS_OFF 0x01
+#define CORE_PWRCTL_BUS_ON (1 << 1)
+#define CORE_PWRCTL_IO_LOW (1 << 2)
+#define CORE_PWRCTL_IO_HIGH (1 << 3)
+
+#define CORE_PWRCTL_BUS_SUCCESS 0x01
+#define CORE_PWRCTL_BUS_FAIL (1 << 1)
+#define CORE_PWRCTL_IO_SUCCESS (1 << 2)
+#define CORE_PWRCTL_IO_FAIL (1 << 3)
+
+#define INT_MASK 0xF
#define MAX_PHASES 16
-#define CORE_DLL_LOCK BIT(7)
-#define CORE_DLL_EN BIT(16)
-#define CORE_CDR_EN BIT(17)
-#define CORE_CK_OUT_EN BIT(18)
-#define CORE_CDR_EXT_EN BIT(19)
-#define CORE_DLL_PDN BIT(29)
-#define CORE_DLL_RST BIT(30)
+
+#define CORE_DLL_LOCK (1 << 7)
+#define CORE_DLL_EN (1 << 16)
+#define CORE_CDR_EN (1 << 17)
+#define CORE_CK_OUT_EN (1 << 18)
+#define CORE_CDR_EXT_EN (1 << 19)
+#define CORE_DLL_PDN (1 << 29)
+#define CORE_DLL_RST (1 << 30)
#define CORE_DLL_CONFIG 0x100
+#define CORE_DLL_TEST_CTL 0x104
#define CORE_DLL_STATUS 0x108
-#define CORE_VENDOR_SPEC 0x10c
-#define CORE_CLK_PWRSAVE BIT(1)
+#define CORE_VENDOR_SPEC 0x10C
+#define CORE_CLK_PWRSAVE (1 << 1)
+#define CORE_IO_PAD_PWR_SWITCH (1 << 16)
-#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
+/* 8KB descriptors */
+#define SDHCI_MSM_MAX_SEGMENTS (1 << 13)
+#define SDHCI_MSM_MMC_CLK_GATE_DELAY 200 /* msecs */
-#define CDR_SELEXT_SHIFT 20
-#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)
-#define CMUX_SHIFT_PHASE_SHIFT 24
-#define CMUX_SHIFT_PHASE_MASK (7 << CMUX_SHIFT_PHASE_SHIFT)
-
-struct sdhci_msm_host {
- struct platform_device *pdev;
- void __iomem *core_mem; /* MSM SDCC mapped address */
- int pwr_irq; /* power irq */
- struct clk *clk; /* main SD/MMC bus clock */
- struct clk *pclk; /* SDHC peripheral bus clock */
- struct clk *bus_clk; /* SDHC bus voter clock */
- struct mmc_host *mmc;
+static const u32 tuning_block_64[] = {
+ 0x00FF0FFF, 0xCCC3CCFF, 0xFFCC3CC3, 0xEFFEFFFE,
+ 0xDDFFDFFF, 0xFBFFFBFF, 0xFF7FFFBF, 0xEFBDF777,
+ 0xF0FFF0FF, 0x3CCCFC0F, 0xCFCC33CC, 0xEEFFEFFF,
+ 0xFDFFFDFF, 0xFFBFFFDF, 0xFFF7FFBB, 0xDE7B7FF7
};
-/* Platform specific tuning */
-static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
+static const u32 tuning_block_128[] = {
+ 0xFF00FFFF, 0x0000FFFF, 0xCCCCFFFF, 0xCCCC33CC,
+ 0xCC3333CC, 0xFFFFCCCC, 0xFFFFEEFF, 0xFFEEEEFF,
+ 0xFFDDFFFF, 0xDDDDFFFF, 0xBBFFFFFF, 0xBBFFFFFF,
+ 0xFFFFFFBB, 0xFFFFFF77, 0x77FF7777, 0xFFEEDDBB,
+ 0x00FFFFFF, 0x00FFFFFF, 0xCCFFFF00, 0xCC33CCCC,
+ 0x3333CCCC, 0xFFCCCCCC, 0xFFEEFFFF, 0xEEEEFFFF,
+ 0xDDFFFFFF, 0xDDFFFFFF, 0xFFFFFFDD, 0xFFFFFFBB,
+ 0xFFFFBBBB, 0xFFFF77FF, 0xFF7777FF, 0xEEDDBB77
+};
+
+/* This structure keeps information per regulator */
+struct sdhci_msm_reg_data {
+ /* voltage regulator handle */
+ struct regulator *reg;
+ /* regulator name */
+ const char *name;
+ /* voltage level to be set */
+ u32 low_vol_level;
+ u32 high_vol_level;
+ /* Load values for low power and high power mode */
+ u32 lpm_uA;
+ u32 hpm_uA;
+
+ /* is this regulator enabled? */
+ bool is_enabled;
+ /* is this regulator needs to be always on? */
+ bool is_always_on;
+ /* is low power mode setting required for this regulator? */
+ bool lpm_sup;
+ bool set_voltage_sup;
+};
+
+/*
+ * This structure keeps information for all the
+ * regulators required for a SDCC slot.
+ */
+struct sdhci_msm_slot_reg_data {
+ /* keeps VDD/VCC regulator info */
+ struct sdhci_msm_reg_data *vdd_data;
+ /* keeps VDD IO regulator info */
+ struct sdhci_msm_reg_data *vdd_io_data;
+};
+
+struct sdhci_msm_gpio {
+ u32 no;
+ const char *name;
+ bool is_enabled;
+};
+
+struct sdhci_msm_gpio_data {
+ struct sdhci_msm_gpio *gpio;
+ u8 size;
+};
+
+struct sdhci_msm_pin_data {
+ /*
+ * = 1 if controller pins are using gpios
+ * = 0 if controller has dedicated MSM pads
+ */
+ bool cfg_sts;
+ struct sdhci_msm_gpio_data *gpio_data;
+};
+
+struct sdhci_msm_pltfm_data {
+ /* Supported UHS-I Modes */
+ u32 caps;
+
+ /* More capabilities */
+ u32 caps2;
+
+ unsigned long mmc_bus_width;
+ u32 max_clk;
+ struct sdhci_msm_slot_reg_data *vreg_data;
+ bool nonremovable;
+ struct sdhci_msm_pin_data *pin_data;
+};
+
+struct sdhci_msm_host {
+ void __iomem *core_mem; /* MSM SDCC mapped address */
+ struct clk *clk; /* main SD/MMC bus clock */
+ struct clk *pclk; /* SDHC peripheral bus clock */
+ struct clk *bus_clk; /* SDHC bus voter clock */
+ atomic_t clks_on; /* Set if clocks are enabled */
+ struct sdhci_msm_pltfm_data *pdata;
+ struct mmc_host *mmc;
+ struct sdhci_pltfm_data sdhci_msm_pdata;
+ wait_queue_head_t pwr_irq_wait;
+};
+
+enum vdd_io_level {
+ /* set vdd_io_data->low_vol_level */
+ VDD_IO_LOW,
+ /* set vdd_io_data->high_vol_level */
+ VDD_IO_HIGH,
+ /*
+ * set whatever there in voltage_level (third argument) of
+ * sdhci_msm_set_vdd_io_vol() function.
+ */
+ VDD_IO_SET_LEVEL,
+};
+
+/* MSM platform specific tuning */
+static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host,
+ u8 poll)
{
+ int rc = 0;
u32 wait_cnt = 50;
- u8 ck_out_en;
+ u8 ck_out_en = 0;
struct mmc_host *mmc = host->mmc;
- /* Poll for CK_OUT_EN bit. max. poll time = 50us */
+ /* poll for CK_OUT_EN bit. max. poll time = 50us */
ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
CORE_CK_OUT_EN);
while (ck_out_en != poll) {
if (--wait_cnt == 0) {
- dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n",
- mmc_hostname(mmc), poll);
- return -ETIMEDOUT;
+ pr_err("%s: %s: CK_OUT_EN bit is not %d\n",
+ mmc_hostname(mmc), __func__, poll);
+ rc = -ETIMEDOUT;
+ goto out;
}
udelay(1);
- ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
- CORE_CK_OUT_EN);
+ ck_out_en = !!(readl_relaxed(host->ioaddr +
+ CORE_DLL_CONFIG) & CORE_CK_OUT_EN);
}
-
- return 0;
+out:
+ return rc;
}
static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
{
- int rc;
- static const u8 grey_coded_phase_table[] = {
- 0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
- 0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8
- };
+ int rc = 0;
+ u8 grey_coded_phase_table[] = {0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
+ 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9,
+ 0x8};
unsigned long flags;
u32 config;
struct mmc_host *mmc = host->mmc;
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
spin_lock_irqsave(&host->lock, flags);
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
@@ -131,10 +244,10 @@
* Write the selected DLL clock output phase (0 ... 15)
* to CDR_SELEXT bit field of DLL_CONFIG register.
*/
- config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
- config &= ~CDR_SELEXT_MASK;
- config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT;
- writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ & ~(0xF << 20))
+ | (grey_coded_phase_table[phase] << 20)),
+ host->ioaddr + CORE_DLL_CONFIG);
/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
@@ -152,10 +265,11 @@
goto out;
err_out:
- dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n",
- mmc_hostname(mmc), phase);
+ pr_err("%s: %s: Failed to set DLL phase: %d\n",
+ mmc_hostname(mmc), __func__, phase);
out:
spin_unlock_irqrestore(&host->lock, flags);
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
return rc;
}
@@ -170,19 +284,20 @@
*/
static int msm_find_most_appropriate_phase(struct sdhci_host *host,
- u8 *phase_table, u8 total_phases)
+ u8 *phase_table, u8 total_phases)
{
int ret;
u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
- u8 phases_per_row[MAX_PHASES] = { 0 };
+ u8 phases_per_row[MAX_PHASES] = {0};
int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
bool phase_0_found = false, phase_15_found = false;
struct mmc_host *mmc = host->mmc;
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
if (!total_phases || (total_phases > MAX_PHASES)) {
- dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n",
- mmc_hostname(mmc), total_phases);
+ pr_err("%s: %s: invalid argument: total_phases=%d\n",
+ mmc_hostname(mmc), __func__, total_phases);
return -EINVAL;
}
@@ -240,7 +355,7 @@
i = phases_15;
for (cnt = 0; cnt < phases_0; cnt++) {
ranges[phase_15_raw_index][i] =
- ranges[phase_0_raw_index][cnt];
+ ranges[phase_0_raw_index][cnt];
if (++i >= MAX_PHASES)
break;
}
@@ -256,24 +371,25 @@
}
}
- i = (curr_max * 3) / 4;
+ i = ((curr_max * 3) / 4);
if (i)
i--;
- ret = ranges[selected_row_index][i];
+ ret = (int)ranges[selected_row_index][i];
if (ret >= MAX_PHASES) {
ret = -EINVAL;
- dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n",
- mmc_hostname(mmc), ret);
+ pr_err("%s: %s: invalid phase selected=%d\n",
+ mmc_hostname(mmc), __func__, ret);
}
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
return ret;
}
static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
{
- u32 mclk_freq = 0, config;
+ u32 mclk_freq = 0;
/* Program the MCLK value to MCLK_FREQ bit field */
if (host->clock <= 112000000)
@@ -293,28 +409,31 @@
else if (host->clock <= 200000000)
mclk_freq = 7;
- config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
- config &= ~CMUX_SHIFT_PHASE_MASK;
- config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT;
- writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+ writel_relaxed(((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+ & ~(7 << 24)) | (mclk_freq << 24)),
+ host->ioaddr + CORE_DLL_CONFIG);
}
-/* Initialize the DLL (Programmable Delay Line) */
+/* Initialize the DLL (Programmable Delay Line ) */
static int msm_init_cm_dll(struct sdhci_host *host)
{
struct mmc_host *mmc = host->mmc;
- int wait_cnt = 50;
+ int rc = 0;
unsigned long flags;
+ u32 wait_cnt;
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
spin_lock_irqsave(&host->lock, flags);
/*
* Make sure that clock is always enabled when DLL
* tuning is in progress. Keeping PWRSAVE ON may
- * turn off the clock.
+ * turn off the clock. So let's disable the PWRSAVE
+ * here and re-enable it once tuning is completed.
*/
writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
- & ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC);
+ & ~CORE_CLK_PWRSAVE),
+ host->ioaddr + CORE_VENDOR_SPEC);
/* Write 1 to DLL_RST bit of DLL_CONFIG register */
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
@@ -341,69 +460,107 @@
writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
| CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+ wait_cnt = 50;
/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
- CORE_DLL_LOCK)) {
+ CORE_DLL_LOCK)) {
/* max. wait for 50us sec for LOCK bit to be set */
if (--wait_cnt == 0) {
- dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
- mmc_hostname(mmc));
- spin_unlock_irqrestore(&host->lock, flags);
- return -ETIMEDOUT;
+ pr_err("%s: %s: DLL failed to LOCK\n",
+ mmc_hostname(mmc), __func__);
+ rc = -ETIMEDOUT;
+ goto out;
}
+ /* wait for 1us before polling again */
udelay(1);
}
+out:
+ /* re-enable PWRSAVE */
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+ CORE_CLK_PWRSAVE),
+ host->ioaddr + CORE_VENDOR_SPEC);
spin_unlock_irqrestore(&host->lock, flags);
- return 0;
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
+ return rc;
}
-static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
+int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
{
- int tuning_seq_cnt = 3;
- u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
+ unsigned long flags;
+ u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+ const u32 *tuning_block_pattern = tuning_block_64;
+ int size = sizeof(tuning_block_64); /* Tuning pattern size in bytes */
int rc;
struct mmc_host *mmc = host->mmc;
- struct mmc_ios ios = host->mmc->ios;
- /*
- * Tuning is required for SDR104, HS200 and HS400 cards and
- * if clock frequency is greater than 100MHz in these modes.
- */
- if (host->clock <= 100 * 1000 * 1000 ||
- !((ios.timing == MMC_TIMING_MMC_HS200) ||
- (ios.timing == MMC_TIMING_UHS_SDR104)))
- return 0;
+ pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);
+ /* Tuning is only required for SDR104 modes */
+ spin_lock_irqsave(&host->lock, flags);
-retry:
- /* First of all reset the tuning block */
+ if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+ (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
+ tuning_block_pattern = tuning_block_128;
+ size = sizeof(tuning_block_128);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ /* first of all reset the tuning block */
rc = msm_init_cm_dll(host);
if (rc)
- return rc;
+ goto out;
+
+ data_buf = kmalloc(size, GFP_KERNEL);
+ if (!data_buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
phase = 0;
do {
- /* Set the phase in delay line hw block */
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
+ struct mmc_request mrq = {
+ .cmd = &cmd,
+ .data = &data
+ };
+ struct scatterlist sg;
+
+ /* set the phase in delay line hw block */
rc = msm_config_cm_dll_phase(host, phase);
if (rc)
- return rc;
+ goto kfree;
- rc = mmc_send_tuning(mmc, opcode, NULL);
- if (!rc) {
- /* Tuning is successful at this tuning point */
+ cmd.opcode = opcode;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = size;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.timeout_ns = 1000 * 1000 * 1000; /* 1 sec */
+
+ data.sg = &sg;
+ data.sg_len = 1;
+ sg_init_one(&sg, data_buf, size);
+ memset(data_buf, 0, size);
+ mmc_wait_for_req(mmc, &mrq);
+
+ if (!cmd.error && !data.error &&
+ !memcmp(data_buf, tuning_block_pattern, size)) {
+ /* tuning is successful at this tuning point */
tuned_phases[tuned_phase_cnt++] = phase;
- dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
- mmc_hostname(mmc), phase);
+ pr_debug("%s: %s: found good phase = %d\n",
+ mmc_hostname(mmc), __func__, phase);
}
- } while (++phase < ARRAY_SIZE(tuned_phases));
+ } while (++phase < 16);
if (tuned_phase_cnt) {
rc = msm_find_most_appropriate_phase(host, tuned_phases,
- tuned_phase_cnt);
+ tuned_phase_cnt);
if (rc < 0)
- return rc;
+ goto kfree;
else
- phase = rc;
+ phase = (u8)rc;
/*
* Finally set the selected phase in delay
@@ -411,121 +568,737 @@
*/
rc = msm_config_cm_dll_phase(host, phase);
if (rc)
- return rc;
- dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
- mmc_hostname(mmc), phase);
+ goto kfree;
+ pr_debug("%s: %s: finally setting the tuning phase to %d\n",
+ mmc_hostname(mmc), __func__, phase);
} else {
- if (--tuning_seq_cnt)
- goto retry;
- /* Tuning failed */
- dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
- mmc_hostname(mmc));
- rc = -EIO;
+ /* tuning failed */
+ pr_err("%s: %s: no tuning point found\n",
+ mmc_hostname(mmc), __func__);
+ rc = -EAGAIN;
}
+kfree:
+ kfree(data_buf);
+out:
+ pr_debug("%s: Exit %s\n", mmc_hostname(mmc), __func__);
return rc;
}
-static void sdhci_msm_set_uhs_signaling(struct sdhci_host *host,
- unsigned int uhs)
+static int sdhci_msm_setup_gpio(struct sdhci_msm_pltfm_data *pdata, bool enable)
{
- struct mmc_host *mmc = host->mmc;
- u16 ctrl_2;
+ struct sdhci_msm_gpio_data *curr;
+ int i, ret = 0;
- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- /* Select Bus Speed Mode for host */
- ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
- switch (uhs) {
- case MMC_TIMING_UHS_SDR12:
- ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- break;
- case MMC_TIMING_UHS_SDR25:
- ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
- break;
- case MMC_TIMING_UHS_SDR50:
- ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
- break;
- case MMC_TIMING_MMC_HS200:
- case MMC_TIMING_UHS_SDR104:
- ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
- break;
- case MMC_TIMING_UHS_DDR50:
- case MMC_TIMING_MMC_DDR52:
- ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
- break;
+ curr = pdata->pin_data->gpio_data;
+ for (i = 0; i < curr->size; i++) {
+ if (!gpio_is_valid(curr->gpio[i].no)) {
+ ret = -EINVAL;
+ pr_err("%s: Invalid gpio = %d\n", __func__,
+ curr->gpio[i].no);
+ goto free_gpios;
+ }
+ if (enable) {
+ ret = gpio_request(curr->gpio[i].no,
+ curr->gpio[i].name);
+ if (ret) {
+ pr_err("%s: gpio_request(%d, %s) failed %d\n",
+ __func__, curr->gpio[i].no,
+ curr->gpio[i].name, ret);
+ goto free_gpios;
+ }
+ curr->gpio[i].is_enabled = true;
+ } else {
+ gpio_free(curr->gpio[i].no);
+ curr->gpio[i].is_enabled = false;
+ }
}
+ return ret;
- /*
- * When clock frequency is less than 100MHz, the feedback clock must be
- * provided and DLL must not be used so that tuning can be skipped. To
- * provide feedback clock, the mode selection can be any value less
- * than 3'b011 in bits [2:0] of HOST CONTROL2 register.
- */
- if (host->clock <= 100000000 &&
- (uhs == MMC_TIMING_MMC_HS400 ||
- uhs == MMC_TIMING_MMC_HS200 ||
- uhs == MMC_TIMING_UHS_SDR104))
- ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-
- dev_dbg(mmc_dev(mmc), "%s: clock=%u uhs=%u ctrl_2=0x%x\n",
- mmc_hostname(host->mmc), host->clock, uhs, ctrl_2);
- sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+free_gpios:
+ for (i--; i >= 0; i--) {
+ gpio_free(curr->gpio[i].no);
+ curr->gpio[i].is_enabled = false;
+ }
+ return ret;
}
-static void sdhci_msm_voltage_switch(struct sdhci_host *host)
+static int sdhci_msm_setup_pins(struct sdhci_msm_pltfm_data *pdata, bool enable)
{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
- u32 irq_status, irq_ack = 0;
+ int ret = 0;
- irq_status = readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
- irq_status &= INT_MASK;
+ if (!pdata->pin_data || (pdata->pin_data->cfg_sts == enable))
+ return 0;
- writel_relaxed(irq_status, msm_host->core_mem + CORE_PWRCTL_CLEAR);
+ ret = sdhci_msm_setup_gpio(pdata, enable);
+ if (!ret)
+ pdata->pin_data->cfg_sts = enable;
- if (irq_status & (CORE_PWRCTL_BUS_ON | CORE_PWRCTL_BUS_OFF))
- irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
- if (irq_status & (CORE_PWRCTL_IO_LOW | CORE_PWRCTL_IO_HIGH))
- irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+ return ret;
+}
+
+#define MAX_PROP_SIZE 32
+static int sdhci_msm_dt_parse_vreg_info(struct device *dev,
+ struct sdhci_msm_reg_data **vreg_data, const char *vreg_name)
+{
+ int len, ret = 0;
+ const __be32 *prop;
+ char prop_name[MAX_PROP_SIZE];
+ struct sdhci_msm_reg_data *vreg;
+ struct device_node *np = dev->of_node;
+
+ snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", vreg_name);
+ if (!of_parse_phandle(np, prop_name, 0)) {
+ dev_err(dev, "No vreg data found for %s\n", vreg_name);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+ if (!vreg) {
+ dev_err(dev, "No memory for vreg: %s\n", vreg_name);
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ vreg->name = vreg_name;
+
+ snprintf(prop_name, MAX_PROP_SIZE,
+ "qcom,%s-always-on", vreg_name);
+ if (of_get_property(np, prop_name, NULL))
+ vreg->is_always_on = true;
+
+ snprintf(prop_name, MAX_PROP_SIZE,
+ "qcom,%s-lpm-sup", vreg_name);
+ if (of_get_property(np, prop_name, NULL))
+ vreg->lpm_sup = true;
+
+ snprintf(prop_name, MAX_PROP_SIZE,
+ "qcom,%s-voltage-level", vreg_name);
+ prop = of_get_property(np, prop_name, &len);
+ if (!prop || (len != (2 * sizeof(__be32)))) {
+ dev_warn(dev, "%s %s property\n",
+ prop ? "invalid format" : "no", prop_name);
+ } else {
+ vreg->low_vol_level = be32_to_cpup(&prop[0]);
+ vreg->high_vol_level = be32_to_cpup(&prop[1]);
+ }
+
+ snprintf(prop_name, MAX_PROP_SIZE,
+ "qcom,%s-current-level", vreg_name);
+ prop = of_get_property(np, prop_name, &len);
+ if (!prop || (len != (2 * sizeof(__be32)))) {
+ dev_warn(dev, "%s %s property\n",
+ prop ? "invalid format" : "no", prop_name);
+ } else {
+ vreg->lpm_uA = be32_to_cpup(&prop[0]);
+ vreg->hpm_uA = be32_to_cpup(&prop[1]);
+ }
+
+ *vreg_data = vreg;
+ dev_dbg(dev, "%s: %s %s vol=[%d %d]uV, curr=[%d %d]uA\n",
+ vreg->name, vreg->is_always_on ? "always_on," : "",
+ vreg->lpm_sup ? "lpm_sup," : "", vreg->low_vol_level,
+ vreg->high_vol_level, vreg->lpm_uA, vreg->hpm_uA);
+
+ return ret;
+}
+
+#define GPIO_NAME_MAX_LEN 32
+static int sdhci_msm_dt_parse_gpio_info(struct device *dev,
+ struct sdhci_msm_pltfm_data *pdata)
+{
+ int ret = 0, cnt, i;
+ struct sdhci_msm_pin_data *pin_data;
+ struct device_node *np = dev->of_node;
+
+ pin_data = devm_kzalloc(dev, sizeof(*pin_data), GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(dev, "No memory for pin_data\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cnt = of_gpio_count(np);
+ if (cnt > 0) {
+ pin_data->gpio_data = devm_kzalloc(dev,
+ sizeof(struct sdhci_msm_gpio_data), GFP_KERNEL);
+ if (!pin_data->gpio_data) {
+ dev_err(dev, "No memory for gpio_data\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+ pin_data->gpio_data->size = cnt;
+ pin_data->gpio_data->gpio = devm_kzalloc(dev, cnt *
+ sizeof(struct sdhci_msm_gpio), GFP_KERNEL);
+
+ if (!pin_data->gpio_data->gpio) {
+ dev_err(dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ const char *name = NULL;
+ char result[GPIO_NAME_MAX_LEN];
+ pin_data->gpio_data->gpio[i].no = of_get_gpio(np, i);
+ of_property_read_string_index(np,
+ "qcom,gpio-names", i, &name);
+
+ snprintf(result, GPIO_NAME_MAX_LEN, "%s-%s",
+ dev_name(dev), name ? name : "?");
+ pin_data->gpio_data->gpio[i].name = result;
+ dev_dbg(dev, "%s: gpio[%s] = %d\n", __func__,
+ pin_data->gpio_data->gpio[i].name,
+ pin_data->gpio_data->gpio[i].no);
+ pdata->pin_data = pin_data;
+ }
+ }
+
+out:
+ if (ret)
+ dev_err(dev, "%s failed with err %d\n", __func__, ret);
+ return ret;
+}
+
+/* Parse platform data */
+static struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev)
+{
+ struct sdhci_msm_pltfm_data *pdata = NULL;
+ struct device_node *np = dev->of_node;
+ u32 bus_width = 0;
+ int len, i;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ dev_err(dev, "failed to allocate memory for platform data\n");
+ goto out;
+ }
+
+ of_property_read_u32(np, "qcom,bus-width", &bus_width);
+ if (bus_width == 8)
+ pdata->mmc_bus_width = MMC_CAP_8_BIT_DATA;
+ else if (bus_width == 4)
+ pdata->mmc_bus_width = MMC_CAP_4_BIT_DATA;
+ else {
+ dev_notice(dev, "invalid bus-width, default to 1-bit mode\n");
+ pdata->mmc_bus_width = 0;
+ }
+
+ pdata->vreg_data = devm_kzalloc(dev, sizeof(struct
+ sdhci_msm_slot_reg_data),
+ GFP_KERNEL);
+ if (!pdata->vreg_data) {
+ dev_err(dev, "failed to allocate memory for vreg data\n");
+ goto out;
+ }
+
+ if (sdhci_msm_dt_parse_vreg_info(dev, &pdata->vreg_data->vdd_data,
+ "vdd")) {
+ dev_err(dev, "failed parsing vdd data\n");
+ goto out;
+ }
+ if (sdhci_msm_dt_parse_vreg_info(dev,
+ &pdata->vreg_data->vdd_io_data,
+ "vdd-io")) {
+ dev_err(dev, "failed parsing vdd-io data\n");
+ goto out;
+ }
+
+ if (sdhci_msm_dt_parse_gpio_info(dev, pdata)) {
+ dev_err(dev, "failed parsing gpio data\n");
+ goto out;
+ }
+
+ of_property_read_u32(np, "qcom,max-clk-rate", &pdata->max_clk);
+
+ len = of_property_count_strings(np, "qcom,bus-speed-mode");
+
+ for (i = 0; i < len; i++) {
+ const char *name = NULL;
+
+ of_property_read_string_index(np,
+ "qcom,bus-speed-mode", i, &name);
+ if (!name)
+ continue;
+
+ if (!strncmp(name, "HS200_1p8v", sizeof("HS200_1p8v")))
+ pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
+ else if (!strncmp(name, "HS200_1p2v", sizeof("HS200_1p2v")))
+ pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
+ else if (!strncmp(name, "DDR_1p8v", sizeof("DDR_1p8v")))
+ pdata->caps |= MMC_CAP_1_8V_DDR
+ | MMC_CAP_UHS_DDR50;
+ else if (!strncmp(name, "DDR_1p2v", sizeof("DDR_1p2v")))
+ pdata->caps |= MMC_CAP_1_2V_DDR
+ | MMC_CAP_UHS_DDR50;
+ }
+
+ if (of_get_property(np, "qcom,nonremovable", NULL))
+ pdata->nonremovable = true;
+
+ return pdata;
+out:
+ return NULL;
+}
+
+/* Regulator utility functions */
+static int sdhci_msm_vreg_init_reg(struct device *dev,
+ struct sdhci_msm_reg_data *vreg)
+{
+ int ret = 0;
+
+ /* check if regulator is already initialized? */
+ if (vreg->reg)
+ goto out;
+
+ /* Get the regulator handle */
+ vreg->reg = devm_regulator_get(dev, vreg->name);
+ if (IS_ERR(vreg->reg)) {
+ ret = PTR_ERR(vreg->reg);
+ pr_err("%s: devm_regulator_get(%s) failed. ret=%d\n",
+ __func__, vreg->name, ret);
+ goto out;
+ }
+
+ /* sanity check */
+ if (!vreg->high_vol_level || !vreg->hpm_uA) {
+ pr_err("%s: %s invalid constraints specified\n",
+ __func__, vreg->name);
+ ret = -EINVAL;
+ }
+
+out:
+ return ret;
+}
+
+static void sdhci_msm_vreg_deinit_reg(struct sdhci_msm_reg_data *vreg)
+{
+ if (vreg->reg)
+ devm_regulator_put(vreg->reg);
+}
+
+static int sdhci_msm_vreg_set_optimum_mode(struct sdhci_msm_reg_data
+ *vreg, int uA_load)
+{
+ int ret = 0;
+
+ /*
+ * regulators that do not support regulator_set_voltage also
+ * do not support regulator_set_optimum_mode
+ */
+ if (vreg->set_voltage_sup) {
+ ret = regulator_set_load(vreg->reg, uA_load);
+ if (ret < 0)
+ pr_err("%s: regulator_set_load(reg=%s,uA_load=%d) failed. ret=%d\n",
+ __func__, vreg->name, uA_load, ret);
+ else
+ /*
+ * regulator_set_load() can return non zero
+ * value even for success case.
+ */
+ ret = 0;
+ }
+ return ret;
+}
+
+static int sdhci_msm_vreg_set_voltage(struct sdhci_msm_reg_data *vreg,
+ int min_uV, int max_uV)
+{
+ int ret = 0;
+
+ ret = regulator_set_voltage(vreg->reg, min_uV, max_uV);
+ if (ret) {
+ pr_err("%s: regulator_set_voltage(%s)failed. min_uV=%d,max_uV=%d,ret=%d\n",
+ __func__, vreg->name, min_uV, max_uV, ret);
+ }
+
+ return ret;
+}
+
+static int sdhci_msm_vreg_enable(struct sdhci_msm_reg_data *vreg)
+{
+ int ret = 0;
+
+ /* Put regulator in HPM (high power mode) */
+ ret = sdhci_msm_vreg_set_optimum_mode(vreg, vreg->hpm_uA);
+ if (ret < 0)
+ return ret;
+
+ if (!vreg->is_enabled) {
+ /* Set voltage level */
+ ret = sdhci_msm_vreg_set_voltage(vreg, vreg->high_vol_level,
+ vreg->high_vol_level);
+ if (ret)
+ return ret;
+ }
+ ret = regulator_enable(vreg->reg);
+ if (ret) {
+ pr_err("%s: regulator_enable(%s) failed. ret=%d\n",
+ __func__, vreg->name, ret);
+ return ret;
+ }
+ vreg->is_enabled = true;
+ return ret;
+}
+
+static int sdhci_msm_vreg_disable(struct sdhci_msm_reg_data *vreg)
+{
+ int ret = 0;
+
+ /* Never disable regulator marked as always_on */
+ if (vreg->is_enabled && !vreg->is_always_on) {
+ ret = regulator_disable(vreg->reg);
+ if (ret) {
+ pr_err("%s: regulator_disable(%s) failed. ret=%d\n",
+ __func__, vreg->name, ret);
+ goto out;
+ }
+ vreg->is_enabled = false;
+
+ ret = sdhci_msm_vreg_set_optimum_mode(vreg, 0);
+ if (ret < 0)
+ goto out;
+
+ /* Set min. voltage level to 0 */
+ ret = sdhci_msm_vreg_set_voltage(vreg, 0, vreg->high_vol_level);
+ if (ret)
+ goto out;
+ } else if (vreg->is_enabled && vreg->is_always_on) {
+ if (vreg->lpm_sup) {
+ /* Put always_on regulator in LPM (low power mode) */
+ ret = sdhci_msm_vreg_set_optimum_mode(vreg,
+ vreg->lpm_uA);
+ if (ret < 0)
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+static int sdhci_msm_setup_vreg(struct sdhci_msm_pltfm_data *pdata,
+ bool enable, bool is_init)
+{
+ int ret = 0, i;
+ struct sdhci_msm_slot_reg_data *curr_slot;
+ struct sdhci_msm_reg_data *vreg_table[2];
+
+ curr_slot = pdata->vreg_data;
+ if (!curr_slot) {
+ pr_debug("%s: vreg info unavailable,assuming the slot is powered by always on domain\n",
+ __func__);
+ goto out;
+ }
+
+ vreg_table[0] = curr_slot->vdd_data;
+ vreg_table[1] = curr_slot->vdd_io_data;
+
+ for (i = 0; i < ARRAY_SIZE(vreg_table); i++) {
+ if (vreg_table[i]) {
+ if (enable)
+ ret = sdhci_msm_vreg_enable(vreg_table[i]);
+ else
+ ret = sdhci_msm_vreg_disable(vreg_table[i]);
+ if (ret)
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+/*
+ * Reset vreg by ensuring it is off during probe. A call
+ * to enable vreg is needed to balance disable vreg
+ */
+static int sdhci_msm_vreg_reset(struct sdhci_msm_pltfm_data *pdata)
+{
+ int ret;
+
+ ret = sdhci_msm_setup_vreg(pdata, 1, true);
+ if (ret)
+ return ret;
+ ret = sdhci_msm_setup_vreg(pdata, 0, true);
+ return ret;
+}
+
+/* This init function should be called only once for each SDHC slot */
+static int sdhci_msm_vreg_init(struct device *dev,
+ struct sdhci_msm_pltfm_data *pdata,
+ bool is_init)
+{
+ int ret = 0;
+ struct sdhci_msm_slot_reg_data *curr_slot;
+ struct sdhci_msm_reg_data *curr_vdd_reg, *curr_vdd_io_reg;
+
+ curr_slot = pdata->vreg_data;
+ if (!curr_slot)
+ goto out;
+
+ curr_vdd_reg = curr_slot->vdd_data;
+ curr_vdd_io_reg = curr_slot->vdd_io_data;
+
+ if (!is_init)
+ /* Deregister all regulators from regulator framework */
+ goto vdd_io_reg_deinit;
/*
- * The driver has to acknowledge the interrupt, switch voltages and
- * report back if it succeded or not to this register. The voltage
- * switches are handled by the sdhci core, so just report success.
+ * Get the regulator handle from voltage regulator framework
+ * and then try to set the voltage level for the regulator
*/
- writel_relaxed(irq_ack, msm_host->core_mem + CORE_PWRCTL_CTL);
+ if (curr_vdd_reg) {
+ ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_reg);
+ if (ret)
+ goto out;
+ }
+ if (curr_vdd_io_reg) {
+ ret = sdhci_msm_vreg_init_reg(dev, curr_vdd_io_reg);
+ if (ret)
+ goto vdd_reg_deinit;
+ }
+ ret = sdhci_msm_vreg_reset(pdata);
+ if (ret)
+ dev_err(dev, "vreg reset failed (%d)\n", ret);
+ goto out;
+
+vdd_io_reg_deinit:
+ if (curr_vdd_io_reg)
+ sdhci_msm_vreg_deinit_reg(curr_vdd_io_reg);
+vdd_reg_deinit:
+ if (curr_vdd_reg)
+ sdhci_msm_vreg_deinit_reg(curr_vdd_reg);
+out:
+ return ret;
+}
+
+
+static int sdhci_msm_set_vdd_io_vol(struct sdhci_msm_pltfm_data *pdata,
+ enum vdd_io_level level,
+ unsigned int voltage_level)
+{
+ int ret = 0;
+ int set_level;
+ struct sdhci_msm_reg_data *vdd_io_reg;
+
+ if (!pdata->vreg_data)
+ return ret;
+
+ vdd_io_reg = pdata->vreg_data->vdd_io_data;
+ if (vdd_io_reg && vdd_io_reg->is_enabled) {
+ switch (level) {
+ case VDD_IO_LOW:
+ set_level = vdd_io_reg->low_vol_level;
+ break;
+ case VDD_IO_HIGH:
+ set_level = vdd_io_reg->high_vol_level;
+ break;
+ case VDD_IO_SET_LEVEL:
+ set_level = voltage_level;
+ break;
+ default:
+ pr_err("%s: invalid argument level = %d",
+ __func__, level);
+ ret = -EINVAL;
+ return ret;
+ }
+ ret = sdhci_msm_vreg_set_voltage(vdd_io_reg, set_level,
+ set_level);
+ }
+ return ret;
}
static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data)
{
struct sdhci_host *host = (struct sdhci_host *)data;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ u8 irq_status = 0;
+ u8 irq_ack = 0;
+ int ret = 0;
- sdhci_msm_voltage_switch(host);
+ irq_status = readb_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS);
+ pr_debug("%s: Received IRQ(%d), status=0x%x\n",
+ mmc_hostname(msm_host->mmc), irq, irq_status);
+ /* Clear the interrupt */
+ writeb_relaxed(irq_status, (msm_host->core_mem + CORE_PWRCTL_CLEAR));
+ /*
+ * SDHC has core_mem and hc_mem device memory and these memory
+ * addresses do not fall within 1KB region. Hence, any update to
+ * core_mem address space would require an mb() to ensure this gets
+ * completed before its next update to registers within hc_mem.
+ */
+ mb();
+
+ /* Handle BUS ON/OFF*/
+ if (irq_status & CORE_PWRCTL_BUS_ON) {
+ ret = sdhci_msm_setup_vreg(msm_host->pdata, true, false);
+ if (!ret)
+ ret = sdhci_msm_setup_pins(msm_host->pdata, true);
+ if (ret)
+ irq_ack |= CORE_PWRCTL_BUS_FAIL;
+ else
+ irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+ }
+ if (irq_status & CORE_PWRCTL_BUS_OFF) {
+ ret = sdhci_msm_setup_vreg(msm_host->pdata, false, false);
+ if (!ret)
+ ret = sdhci_msm_setup_pins(msm_host->pdata, false);
+ if (ret)
+ irq_ack |= CORE_PWRCTL_BUS_FAIL;
+ else
+ irq_ack |= CORE_PWRCTL_BUS_SUCCESS;
+ }
+ /* Handle IO LOW/HIGH */
+ if (irq_status & CORE_PWRCTL_IO_LOW) {
+ /* Switch voltage Low */
+ ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_LOW, 0);
+ if (ret)
+ irq_ack |= CORE_PWRCTL_IO_FAIL;
+ else
+ irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+ }
+ if (irq_status & CORE_PWRCTL_IO_HIGH) {
+ /* Switch voltage High */
+ ret = sdhci_msm_set_vdd_io_vol(msm_host->pdata, VDD_IO_HIGH, 0);
+ if (ret)
+ irq_ack |= CORE_PWRCTL_IO_FAIL;
+ else
+ irq_ack |= CORE_PWRCTL_IO_SUCCESS;
+ }
+
+ /* ACK status to the core */
+ writeb_relaxed(irq_ack, (msm_host->core_mem + CORE_PWRCTL_CTL));
+ /*
+ * SDHC has core_mem and hc_mem device memory and these memory
+ * addresses do not fall within 1KB region. Hence, any update to
+ * core_mem address space would require an mb() to ensure this gets
+ * completed before its next update to registers within hc_mem.
+ */
+ mb();
+
+ if (irq_status & CORE_PWRCTL_IO_HIGH)
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) &
+ ~CORE_IO_PAD_PWR_SWITCH),
+ host->ioaddr + CORE_VENDOR_SPEC);
+ if (irq_status & CORE_PWRCTL_IO_LOW)
+ writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC) |
+ CORE_IO_PAD_PWR_SWITCH),
+ host->ioaddr + CORE_VENDOR_SPEC);
+ mb();
+
+ pr_debug("%s: Handled IRQ(%d), ret=%d, ack=0x%x\n",
+ mmc_hostname(msm_host->mmc), irq, ret, irq_ack);
+ wake_up_interruptible(&msm_host->pwr_irq_wait);
return IRQ_HANDLED;
}
-static const struct of_device_id sdhci_msm_dt_match[] = {
- { .compatible = "qcom,sdhci-msm-v4" },
- {},
-};
+static void sdhci_msm_check_power_status(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ int ret = 0;
-MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
+ pr_debug("%s: %s: power status before waiting 0x%x\n",
+ mmc_hostname(host->mmc), __func__,
+ readb_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
-static const struct sdhci_ops sdhci_msm_ops = {
+ ret = wait_event_interruptible(msm_host->pwr_irq_wait,
+ (readb_relaxed(msm_host->core_mem +
+ CORE_PWRCTL_CTL)) != 0x0);
+ if (ret)
+ pr_warning("%s: %s: returned due to error %d\n",
+ mmc_hostname(host->mmc), __func__, ret);
+ pr_debug("%s: %s: ret %d power status after handling power IRQ 0x%x\n",
+ mmc_hostname(host->mmc), __func__, ret,
+ readb_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL));
+}
+
+static void sdhci_msm_toggle_cdr(struct sdhci_host *host, bool enable)
+{
+ if (enable)
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ CORE_DLL_CONFIG) | CORE_CDR_EN),
+ host->ioaddr + CORE_DLL_CONFIG);
+ else
+ writel_relaxed((readl_relaxed(host->ioaddr +
+ CORE_DLL_CONFIG) & ~CORE_CDR_EN),
+ host->ioaddr + CORE_DLL_CONFIG);
+}
+
+static unsigned int sdhci_msm_max_segs(void)
+{
+ return SDHCI_MSM_MAX_SEGMENTS;
+}
+
+void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ int rc;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ unsigned long flags;
+
+ if (clock && !atomic_read(&msm_host->clks_on)) {
+ pr_debug("%s: request to enable clock at rate %u\n",
+ mmc_hostname(host->mmc), clock);
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
+ rc = clk_prepare_enable(msm_host->bus_clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the bus-clock with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto out;
+ }
+ }
+ if (!IS_ERR(msm_host->pclk)) {
+ rc = clk_prepare_enable(msm_host->pclk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the pclk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_bus_clk;
+ }
+ }
+ rc = clk_prepare_enable(msm_host->clk);
+ if (rc) {
+ pr_err("%s: %s: failed to enable the host-clk with error %d\n",
+ mmc_hostname(host->mmc), __func__, rc);
+ goto disable_pclk;
+ }
+ mb();
+ atomic_set(&msm_host->clks_on, 1);
+
+ } else if (!clock && atomic_read(&msm_host->clks_on)) {
+ pr_debug("%s: request to disable clocks\n",
+ mmc_hostname(host->mmc));
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+ mb();
+ clk_disable_unprepare(msm_host->clk);
+ if (!IS_ERR(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+ clk_disable_unprepare(msm_host->bus_clk);
+ atomic_set(&msm_host->clks_on, 0);
+ }
+ spin_lock_irqsave(&host->lock, flags);
+ host->clock = clock;
+ spin_unlock_irqrestore(&host->lock, flags);
+ goto out;
+disable_pclk:
+ if (!IS_ERR_OR_NULL(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
+disable_bus_clk:
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk))
+ clk_disable_unprepare(msm_host->bus_clk);
+out:
+ return;
+}
+
+static struct sdhci_ops sdhci_msm_ops = {
+ .check_power_status = sdhci_msm_check_power_status,
.platform_execute_tuning = sdhci_msm_execute_tuning,
- .reset = sdhci_reset,
- .set_clock = sdhci_set_clock,
- .set_bus_width = sdhci_set_bus_width,
- .set_uhs_signaling = sdhci_msm_set_uhs_signaling,
- .voltage_switch = sdhci_msm_voltage_switch,
-};
-
-static const struct sdhci_pltfm_data sdhci_msm_pdata = {
- .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
- SDHCI_QUIRK_NO_CARD_NO_RESET |
- SDHCI_QUIRK_SINGLE_POWER_WRITE,
- .ops = &sdhci_msm_ops,
+ .toggle_cdr = sdhci_msm_toggle_cdr,
+ .get_max_segments = sdhci_msm_max_segs,
+ .set_clock = sdhci_msm_set_clock,
};
static int sdhci_msm_probe(struct platform_device *pdev)
@@ -533,30 +1306,47 @@
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_msm_host *msm_host;
- struct resource *core_memres;
- int ret;
- u16 host_version, core_minor;
- u32 core_version, caps;
- u8 core_major;
+ struct resource *core_memres = NULL;
+ int ret = 0, pwr_irq = 0, dead = 0;
+ u32 host_version;
- host = sdhci_pltfm_init(pdev, &sdhci_msm_pdata, sizeof(*msm_host));
- if (IS_ERR(host))
- return PTR_ERR(host);
+ pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
+ msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
+ GFP_KERNEL);
+ if (!msm_host) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ init_waitqueue_head(&msm_host->pwr_irq_wait);
+
+ msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
+ host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
+ if (IS_ERR(host)) {
+ ret = PTR_ERR(host);
+ goto out;
+ }
pltfm_host = sdhci_priv(host);
- msm_host = sdhci_pltfm_priv(pltfm_host);
+ pltfm_host->priv = msm_host;
msm_host->mmc = host->mmc;
- msm_host->pdev = pdev;
- ret = mmc_of_parse(host->mmc);
- if (ret)
+ /* Extract platform data */
+ if (pdev->dev.of_node) {
+ msm_host->pdata = sdhci_msm_populate_pdata(&pdev->dev);
+ if (!msm_host->pdata) {
+ dev_err(&pdev->dev, "DT parsing error\n");
+ goto pltfm_free;
+ }
+ } else {
+ dev_err(&pdev->dev, "No device tree node\n");
goto pltfm_free;
+ }
- sdhci_get_of_property(pdev);
+ /* Setup Clocks */
/* Setup SDCC bus voter clock. */
- msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
- if (!IS_ERR(msm_host->bus_clk)) {
+ msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk)) {
/* Vote for max. clk rate for max. performance */
ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
if (ret)
@@ -567,113 +1357,146 @@
}
/* Setup main peripheral bus clock */
- msm_host->pclk = devm_clk_get(&pdev->dev, "iface");
- if (IS_ERR(msm_host->pclk)) {
- ret = PTR_ERR(msm_host->pclk);
- dev_err(&pdev->dev, "Peripheral clk setup failed (%d)\n", ret);
- goto bus_clk_disable;
+ msm_host->pclk = devm_clk_get(&pdev->dev, "iface_clk");
+ if (!IS_ERR(msm_host->pclk)) {
+ ret = clk_prepare_enable(msm_host->pclk);
+ if (ret)
+ goto bus_clk_disable;
}
- ret = clk_prepare_enable(msm_host->pclk);
- if (ret)
- goto bus_clk_disable;
-
/* Setup SDC MMC clock */
- msm_host->clk = devm_clk_get(&pdev->dev, "core");
+ msm_host->clk = devm_clk_get(&pdev->dev, "core_clk");
if (IS_ERR(msm_host->clk)) {
ret = PTR_ERR(msm_host->clk);
- dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
goto pclk_disable;
}
- /* Vote for maximum clock rate for maximum performance */
- ret = clk_set_rate(msm_host->clk, INT_MAX);
- if (ret)
- dev_warn(&pdev->dev, "core clock boost failed\n");
-
ret = clk_prepare_enable(msm_host->clk);
if (ret)
goto pclk_disable;
- core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres);
-
- if (IS_ERR(msm_host->core_mem)) {
- dev_err(&pdev->dev, "Failed to remap registers\n");
- ret = PTR_ERR(msm_host->core_mem);
+ atomic_set(&msm_host->clks_on, 1);
+ /* Setup regulators */
+ ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true);
+ if (ret) {
+ dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret);
goto clk_disable;
}
/* Reset the core and Enable SDHC mode */
- writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
- CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+ core_memres = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "core_mem");
+ msm_host->core_mem = devm_ioremap(&pdev->dev, core_memres->start,
+ resource_size(core_memres));
- /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
- usleep_range(1000, 5000);
- if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) {
- dev_err(&pdev->dev, "Stuck in reset\n");
- ret = -ETIMEDOUT;
- goto clk_disable;
+ if (!msm_host->core_mem) {
+ dev_err(&pdev->dev, "Failed to remap registers\n");
+ ret = -ENOMEM;
+ goto vreg_deinit;
}
+ /* Set SW_RST bit in POWER register (Offset 0x0) */
+ writel_relaxed(CORE_SW_RST, msm_host->core_mem + CORE_POWER);
/* Set HC_MODE_EN bit in HC_MODE register */
writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
- host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
+ /*
+ * Following are the deviations from SDHC spec v3.0 -
+ * 1. Card detection is handled using separate GPIO.
+ * 2. Bus power control is handled by interacting with PMIC.
+ */
+ host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+ host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
+
+ host_version = readl_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
- SDHCI_VENDOR_VER_SHIFT));
-
- core_version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION);
- core_major = (core_version & CORE_VERSION_MAJOR_MASK) >>
- CORE_VERSION_MAJOR_SHIFT;
- core_minor = core_version & CORE_VERSION_MINOR_MASK;
- dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
- core_version, core_major, core_minor);
-
- /*
- * Support for some capabilities is not advertised by newer
- * controller versions and must be explicitly enabled.
- */
- if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) {
- caps = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES);
- caps |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT;
- writel_relaxed(caps, host->ioaddr +
- CORE_VENDOR_SPEC_CAPABILITIES0);
+ SDHCI_VENDOR_VER_SHIFT));
+ if (((host_version & SDHCI_VENDOR_VER_MASK) >>
+ SDHCI_VENDOR_VER_SHIFT) == SDHCI_VER_100) {
+ /*
+ * Add 40us delay in interrupt handler when
+ * operating at initialization frequency(400KHz).
+ */
+ host->quirks2 |= SDHCI_QUIRK2_SLOW_INT_CLR;
+ /*
+ * Set Software Reset for DAT line in Software
+ * Reset Register (Bit 2).
+ */
+ host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT;
}
- /* Setup IRQ for handling power/voltage tasks with PMIC */
- msm_host->pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
- if (msm_host->pwr_irq < 0) {
- dev_err(&pdev->dev, "Get pwr_irq failed (%d)\n",
- msm_host->pwr_irq);
- ret = msm_host->pwr_irq;
- goto clk_disable;
+ /* Setup PWRCTL irq */
+ pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
+ if (pwr_irq < 0) {
+ dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n",
+ pwr_irq);
+ goto vreg_deinit;
}
-
- ret = devm_request_threaded_irq(&pdev->dev, msm_host->pwr_irq, NULL,
+ ret = devm_request_threaded_irq(&pdev->dev, pwr_irq, NULL,
sdhci_msm_pwr_irq, IRQF_ONESHOT,
dev_name(&pdev->dev), host);
if (ret) {
- dev_err(&pdev->dev, "Request IRQ failed (%d)\n", ret);
- goto clk_disable;
+ dev_err(&pdev->dev, "Request threaded irq(%d) failed (%d)\n",
+ pwr_irq, ret);
+ goto vreg_deinit;
}
+ /* Enable pwr irq interrupts */
+ writel_relaxed(INT_MASK, (msm_host->core_mem + CORE_PWRCTL_MASK));
+
+#ifdef CONFIG_MMC_CLKGATE
+ /* Set clock gating delay to be used when CONFIG_MMC_CLKGATE is set */
+ msm_host->mmc->clkgate_delay = SDHCI_MSM_MMC_CLK_GATE_DELAY;
+#endif
+
+ /* Set host capabilities */
+ msm_host->mmc->caps |= msm_host->pdata->mmc_bus_width;
+ msm_host->mmc->caps |= msm_host->pdata->caps;
+ msm_host->mmc->caps |= MMC_CAP_HW_RESET;
+ msm_host->mmc->caps2 |= msm_host->pdata->caps2;
+ msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR;
+ msm_host->mmc->caps2 |= MMC_CAP2_PACKED_WR_CONTROL;
+
+ if (msm_host->pdata->nonremovable)
+ msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
+
ret = sdhci_add_host(host);
- if (ret)
- goto clk_disable;
+ if (ret) {
+ dev_err(&pdev->dev, "Add host failed (%d)\n", ret);
+ goto vreg_deinit;
+ }
- return 0;
+ /* Set core clk rate, optionally override from dts */
+ if (msm_host->pdata->max_clk)
+ host->max_clk = msm_host->pdata->max_clk;
+ ret = clk_set_rate(msm_host->clk, host->max_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "MClk rate set failed (%d)\n", ret);
+ goto remove_host;
+ }
+ /* Successful initialization */
+ goto out;
+
+remove_host:
+ dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+ sdhci_remove_host(host, dead);
+vreg_deinit:
+ sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
clk_disable:
- clk_disable_unprepare(msm_host->clk);
+ if (!IS_ERR(msm_host->clk))
+ clk_disable_unprepare(msm_host->clk);
pclk_disable:
- clk_disable_unprepare(msm_host->pclk);
+ if (!IS_ERR(msm_host->pclk))
+ clk_disable_unprepare(msm_host->pclk);
bus_clk_disable:
- if (!IS_ERR(msm_host->bus_clk))
+ if (!IS_ERR_OR_NULL(msm_host->bus_clk))
clk_disable_unprepare(msm_host->bus_clk);
pltfm_free:
sdhci_pltfm_free(pdev);
+out:
+ pr_debug("%s: Exit %s\n", dev_name(&pdev->dev), __func__);
return ret;
}
@@ -681,29 +1504,37 @@
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+ struct sdhci_msm_pltfm_data *pdata = msm_host->pdata;
int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
- 0xffffffff);
+ 0xffffffff);
+ pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__);
sdhci_remove_host(host, dead);
- clk_disable_unprepare(msm_host->clk);
- clk_disable_unprepare(msm_host->pclk);
- if (!IS_ERR(msm_host->bus_clk))
- clk_disable_unprepare(msm_host->bus_clk);
sdhci_pltfm_free(pdev);
+ sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false);
+
+ if (pdata->pin_data)
+ sdhci_msm_setup_gpio(pdata, false);
return 0;
}
+static const struct of_device_id sdhci_msm_dt_match[] = {
+ {.compatible = "qcom,sdhci-msm"},
+};
+MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
+
static struct platform_driver sdhci_msm_driver = {
- .probe = sdhci_msm_probe,
- .remove = sdhci_msm_remove,
- .driver = {
- .name = "sdhci_msm",
- .of_match_table = sdhci_msm_dt_match,
+ .probe = sdhci_msm_probe,
+ .remove = sdhci_msm_remove,
+ .driver = {
+ .name = "sdhci_msm",
+ .owner = THIS_MODULE,
+ .of_match_table = sdhci_msm_dt_match,
},
};
module_platform_driver(sdhci_msm_driver);
-MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Secure Digital Host Controller Interface driver");
MODULE_LICENSE("GPL v2");
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-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 3280f20..33b4fa6 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -23,6 +23,7 @@
struct sdhci_pltfm_host {
struct clk *clk;
+ void *priv; /* to handle quirks across io-accessor calls */
/* migrate from sdhci_of_host */
unsigned int clock;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ba637ff..e72d188 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -748,6 +748,17 @@
}
}
+static void sdhci_set_blk_size_reg(struct sdhci_host *host, unsigned int blksz,
+ unsigned int sdma_boundary)
+{
+ if (host->flags & SDHCI_USE_ADMA)
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(0, blksz),
+ SDHCI_BLOCK_SIZE);
+ else
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(sdma_boundary, blksz),
+ SDHCI_BLOCK_SIZE);
+}
+
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
{
u8 ctrl;
@@ -880,8 +891,7 @@
sdhci_set_transfer_irqs(host);
/* Set the DMA boundary value and block size */
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
- data->blksz), SDHCI_BLOCK_SIZE);
+ sdhci_set_blk_size_reg(host, data->blksz, SDHCI_DEFAULT_BOUNDARY_ARG);
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
}
@@ -1350,7 +1360,8 @@
host->mmc->actual_clock = 0;
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+ if (host->clock)
+ sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
if (clock == 0)
return;
@@ -1371,7 +1382,9 @@
return;
}
timeout--;
- mdelay(1);
+ spin_unlock_irq(&host->lock);
+ usleep_range(900, 1100);
+ spin_lock_irq(&host->lock);
}
clk |= SDHCI_CLOCK_CARD_EN;
@@ -1579,22 +1592,16 @@
return;
}
- /*
- * Reset the chip on each power off.
- * Should clear out any weird states.
- */
- if (ios->power_mode == MMC_POWER_OFF) {
- sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- sdhci_reinit(host);
- }
-
if (host->version >= SDHCI_SPEC_300 &&
(ios->power_mode == MMC_POWER_UP) &&
!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
sdhci_enable_preset_value(host, false);
+ spin_lock_irqsave(&host->lock, flags);
if (!ios->clock || ios->clock != host->clock) {
+ spin_unlock_irqrestore(&host->lock, flags);
host->ops->set_clock(host, ios->clock);
+ spin_lock_irqsave(&host->lock, flags);
host->clock = ios->clock;
if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK &&
@@ -1609,11 +1616,13 @@
host->mmc->max_busy_timeout /= host->timeout_clk;
}
}
+ spin_unlock_irqrestore(&host->lock, flags);
if (host->ops->set_power)
host->ops->set_power(host, ios->power_mode, ios->vdd);
else
- sdhci_set_power(host, ios->power_mode, ios->vdd);
+ if (ios->power_mode & (MMC_POWER_UP | MMC_POWER_ON))
+ sdhci_set_power(host, ios->power_mode, ios->vdd);
if (host->ops->platform_send_init_74_clocks)
host->ops->platform_send_init_74_clocks(host, ios->power_mode);
@@ -1712,6 +1721,7 @@
} else
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ spin_unlock_irqrestore(&host->lock, flags);
/*
* Some (ENE) controllers go apeshit on some ios operation,
* signalling timeout and CRC errors even on CMD0. Resetting
@@ -1720,8 +1730,19 @@
if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+ /*
+ * Reset the chip on each power off.
+ * Should clear out any weird states.
+ */
+ if (ios->power_mode == MMC_POWER_OFF) {
+ sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
+ sdhci_reinit(host);
+ sdhci_set_power(host, ios->power_mode, ios->vdd);
+ }
+ if (!ios->clock)
+ sdhci_set_clock(host, ios->clock);
+
mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
}
static int sdhci_get_cd(struct mmc_host *mmc)
@@ -2054,14 +2075,11 @@
*/
if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
- SDHCI_BLOCK_SIZE);
+ sdhci_set_blk_size_reg(host, 128, 7);
else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
- SDHCI_BLOCK_SIZE);
+ sdhci_set_blk_size_reg(host, 64, 7);
} else {
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
- SDHCI_BLOCK_SIZE);
+ sdhci_set_blk_size_reg(host, 64, 7);
}
/*
@@ -2360,6 +2378,9 @@
sdhci_do_reset(host, SDHCI_RESET_DATA);
host->pending_reset = false;
+ } else {
+ if (host->quirks2 & SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT)
+ sdhci_reset(host, SDHCI_RESET_DATA);
}
if (!sdhci_has_requests(host))
@@ -2706,11 +2727,19 @@
result = IRQ_WAKE_THREAD;
}
- if (intmask & SDHCI_INT_CMD_MASK)
+ if (intmask & SDHCI_INT_CMD_MASK) {
+ if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+ (host->clock <= 400000))
+ udelay(40);
sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+ }
- if (intmask & SDHCI_INT_DATA_MASK)
+ if (intmask & SDHCI_INT_DATA_MASK) {
+ if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
+ (host->clock <= 400000))
+ udelay(40);
sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
+ }
if (intmask & SDHCI_INT_BUS_POWER)
pr_err("%s: Card is consuming too much power!\n",
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 2570455..b56b3c1 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -425,6 +425,17 @@
#define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14)
/* Broken Clock divider zero in controller */
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15)
+/*
+ * Read Transfer Active/ Write Transfer Active may be not
+ * de-asserted after end of transaction. Issue reset for DAT line.
+ */
+#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT (1<<17)
+/*
+ * Slow interrupt clearance at 400KHz may cause
+ * host controller driver interrupt handler to
+ * be called twice.
+*/
+#define SDHCI_QUIRK2_SLOW_INT_CLR (1<<18)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@@ -558,7 +569,10 @@
void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
void (*hw_reset)(struct sdhci_host *host);
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
+ unsigned int (*get_max_segments)(void);
void (*card_event)(struct sdhci_host *host);
+ void (*toggle_cdr)(struct sdhci_host *host, bool enable);
+ void (*check_power_status)(struct sdhci_host *host);
void (*voltage_switch)(struct sdhci_host *host);
int (*select_drive_strength)(struct sdhci_host *host,
struct mmc_card *card,
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/Makefile b/drivers/net/wireless/Makefile
index f00d429..91594de 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -25,3 +25,5 @@
obj-$(CONFIG_USB_NET_RNDIS_WLAN) += rndis_wlan.o
obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
+
+obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/
diff --git a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
index 636f466..61de231 100644
--- a/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
+++ b/drivers/net/wireless/cnss_prealloc/cnss_prealloc.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012,2014-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012,2014-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -207,6 +207,8 @@
print_stack_trace(&wcnss_allocs[i].trace, 1);
}
}
+#else
+void wcnss_prealloc_check_memory_leak(void) {}
#endif
int wcnss_pre_alloc_reset(void)
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/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index b37b572..ad3e1e7 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -27,6 +27,9 @@
#include <asm/cputype.h>
#include <asm/irq_regs.h>
+#define USE_CPUHP_STATE CPUHP_AP_PERF_ARM_STARTING
+#define USE_CPUHP_STR "AP_PERF_ARM_STARTING"
+
static int
armpmu_map_cache_event(const unsigned (*cache_map)
[PERF_COUNT_HW_CACHE_MAX]
@@ -366,6 +369,8 @@
return err;
}
+ armpmu->pmu_state = ARM_PMU_STATE_RUNNING;
+
return 0;
}
@@ -568,6 +573,7 @@
.read = armpmu_read,
.filter_match = armpmu_filter_match,
.attr_groups = armpmu->attr_groups,
+ .events_across_hotplug = 1,
};
armpmu->attr_groups[ARMPMU_ATTR_GROUP_COMMON] =
&armpmu_common_attr_group;
@@ -620,6 +626,8 @@
struct platform_device *pmu_device = cpu_pmu->plat_device;
struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events;
+ cpu_pmu->pmu_state = ARM_PMU_STATE_GOING_DOWN;
+
irqs = min(pmu_device->num_resources, num_possible_cpus());
irq = platform_get_irq(pmu_device, 0);
@@ -627,6 +635,7 @@
on_each_cpu_mask(&cpu_pmu->supported_cpus,
cpu_pmu_disable_percpu_irq, &irq, 1);
free_percpu_irq(irq, &hw_events->percpu_pmu);
+ cpu_pmu->percpu_irq = -1;
} else {
for (i = 0; i < irqs; ++i) {
int cpu = i;
@@ -641,6 +650,7 @@
free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu));
}
}
+ cpu_pmu->pmu_state = ARM_PMU_STATE_OFF;
}
static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
@@ -670,6 +680,7 @@
on_each_cpu_mask(&cpu_pmu->supported_cpus,
cpu_pmu_enable_percpu_irq, &irq, 1);
+ cpu_pmu->percpu_irq = irq;
} else {
for (i = 0; i < irqs; ++i) {
int cpu = i;
@@ -709,22 +720,12 @@
return 0;
}
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
-{
- struct arm_pmu *pmu = hlist_entry_safe(node, struct arm_pmu, node);
-
- if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
- return 0;
- if (pmu->reset)
- pmu->reset(pmu);
- return 0;
-}
+struct cpu_pm_pmu_args {
+ struct arm_pmu *armpmu;
+ unsigned long cmd;
+ int cpu;
+ int ret;
+};
#ifdef CONFIG_CPU_PM
static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd)
@@ -772,15 +773,19 @@
}
}
-static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
- void *v)
+static void cpu_pm_pmu_common(void *info)
{
- struct arm_pmu *armpmu = container_of(b, struct arm_pmu, cpu_pm_nb);
+ struct cpu_pm_pmu_args *data = info;
+ struct arm_pmu *armpmu = data->armpmu;
+ unsigned long cmd = data->cmd;
+ int cpu = data->cpu;
struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
- if (!cpumask_test_cpu(smp_processor_id(), &armpmu->supported_cpus))
- return NOTIFY_DONE;
+ if (!cpumask_test_cpu(cpu, &armpmu->supported_cpus)) {
+ data->ret = NOTIFY_DONE;
+ return;
+ }
/*
* Always reset the PMU registers on power-up even if
@@ -789,8 +794,12 @@
if (cmd == CPU_PM_EXIT && armpmu->reset)
armpmu->reset(armpmu);
- if (!enabled)
- return NOTIFY_OK;
+ if (!enabled) {
+ data->ret = NOTIFY_OK;
+ return;
+ }
+
+ data->ret = NOTIFY_OK;
switch (cmd) {
case CPU_PM_ENTER:
@@ -798,15 +807,29 @@
cpu_pm_pmu_setup(armpmu, cmd);
break;
case CPU_PM_EXIT:
- cpu_pm_pmu_setup(armpmu, cmd);
case CPU_PM_ENTER_FAILED:
+ cpu_pm_pmu_setup(armpmu, cmd);
armpmu->start(armpmu);
break;
default:
- return NOTIFY_DONE;
+ data->ret = NOTIFY_DONE;
+ break;
}
- return NOTIFY_OK;
+ return;
+}
+
+static int cpu_pm_pmu_notify(struct notifier_block *b, unsigned long cmd,
+ void *v)
+{
+ struct cpu_pm_pmu_args data = {
+ .armpmu = container_of(b, struct arm_pmu, cpu_pm_nb),
+ .cmd = cmd,
+ .cpu = smp_processor_id(),
+ };
+
+ cpu_pm_pmu_common(&data);
+ return data.ret;
}
static int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu)
@@ -819,11 +842,75 @@
{
cpu_pm_unregister_notifier(&cpu_pmu->cpu_pm_nb);
}
+
#else
static inline int cpu_pm_pmu_register(struct arm_pmu *cpu_pmu) { return 0; }
static inline void cpu_pm_pmu_unregister(struct arm_pmu *cpu_pmu) { }
+static void cpu_pm_pmu_common(void *info) { }
#endif
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
+{
+ struct arm_pmu *pmu = hlist_entry_safe(node, struct arm_pmu, node);
+
+ struct cpu_pm_pmu_args data = {
+ .armpmu = pmu,
+ .cpu = (int)cpu,
+ };
+
+ if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus))
+ return 0;
+
+ data.cmd = CPU_PM_EXIT;
+ cpu_pm_pmu_common(&data);
+ if (data.ret == NOTIFY_DONE)
+ return 0;
+
+ if (data.armpmu->pmu_state != ARM_PMU_STATE_OFF &&
+ data.armpmu->plat_device) {
+ int irq = data.armpmu->percpu_irq;
+
+ if (irq > 0 && irq_is_percpu(irq))
+ cpu_pmu_enable_percpu_irq(&irq);
+
+ }
+
+ return 0;
+}
+
+static int arm_perf_stopping_cpu(unsigned int cpu, struct hlist_node *node)
+{
+ struct arm_pmu *pmu = hlist_entry_safe(node, struct arm_pmu, node);
+
+ struct cpu_pm_pmu_args data = {
+ .armpmu = pmu,
+ .cpu = (int)cpu,
+ };
+
+ if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus))
+ return 0;
+
+ data.cmd = CPU_PM_ENTER;
+ cpu_pm_pmu_common(&data);
+ /* Disarm the PMU IRQ before disappearing. */
+ if (data.armpmu->pmu_state == ARM_PMU_STATE_RUNNING &&
+ data.armpmu->plat_device) {
+ int irq = data.armpmu->percpu_irq;
+
+ if (irq > 0 && irq_is_percpu(irq))
+ cpu_pmu_disable_percpu_irq(&irq);
+
+ }
+
+ return 0;
+}
+
static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
{
int err;
@@ -834,14 +921,14 @@
if (!cpu_hw_events)
return -ENOMEM;
- err = cpuhp_state_add_instance_nocalls(CPUHP_AP_PERF_ARM_STARTING,
+ err = cpuhp_state_add_instance_nocalls(USE_CPUHP_STATE,
&cpu_pmu->node);
if (err)
goto out_free;
err = cpu_pm_pmu_register(cpu_pmu);
if (err)
- goto out_unregister;
+ goto out_unreg_perf_starting;
for_each_possible_cpu(cpu) {
struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu);
@@ -872,8 +959,8 @@
return 0;
-out_unregister:
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_STARTING,
+out_unreg_perf_starting:
+ cpuhp_state_remove_instance_nocalls(USE_CPUHP_STATE,
&cpu_pmu->node);
out_free:
free_percpu(cpu_hw_events);
@@ -883,7 +970,7 @@
static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
{
cpu_pm_pmu_unregister(cpu_pmu);
- cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_STARTING,
+ cpuhp_state_remove_instance_nocalls(USE_CPUHP_STATE,
&cpu_pmu->node);
free_percpu(cpu_pmu->hw_events);
}
@@ -1064,6 +1151,9 @@
if (!__oprofile_cpu_pmu)
__oprofile_cpu_pmu = pmu;
+ pmu->pmu_state = ARM_PMU_STATE_OFF;
+ pmu->percpu_irq = -1;
+
pr_info("enabled with %s PMU driver, %d counters available\n",
pmu->name, pmu->num_events);
@@ -1083,11 +1173,12 @@
{
int ret;
- ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_STARTING,
- "AP_PERF_ARM_STARTING",
- arm_perf_starting_cpu, NULL);
+ ret = cpuhp_setup_state_multi(USE_CPUHP_STATE,
+ USE_CPUHP_STR,
+ arm_perf_starting_cpu,
+ arm_perf_stopping_cpu);
if (ret)
- pr_err("CPU hotplug notifier for ARM PMU could not be registered: %d\n",
+ pr_err("CPU hotplug ARM PMU STOPPING registering failed: %d\n",
ret);
return ret;
}
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 92fd916..f6b99d0 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -55,6 +55,7 @@
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-v3.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qrbtc-sdm845.o
+obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-v3-660.o
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h
index 35179c8..b92bc89 100644
--- a/drivers/phy/phy-qcom-ufs-i.h
+++ b/drivers/phy/phy-qcom-ufs-i.h
@@ -97,6 +97,10 @@
struct ufs_qcom_phy_vreg vdda_pll;
struct ufs_qcom_phy_vreg vdda_phy;
struct ufs_qcom_phy_vreg vddp_ref_clk;
+
+ /* Number of lanes available (1 or 2) for Rx/Tx */
+ u32 lanes_per_direction;
+
unsigned int quirks;
/*
@@ -152,6 +156,7 @@
* and writes to QSERDES_RX_SIGDET_CNTRL attribute
* @configure_lpm: pointer to a function that configures the phy
* for low power mode.
+ * @dbg_register_dump: pointer to a function that dumps phy registers for debug.
*/
struct ufs_qcom_phy_specific_ops {
int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B);
@@ -161,6 +166,7 @@
void (*ctrl_rx_linecfg)(struct ufs_qcom_phy *phy, bool ctrl);
void (*power_control)(struct ufs_qcom_phy *phy, bool val);
int (*configure_lpm)(struct ufs_qcom_phy *phy, bool enable);
+ void (*dbg_register_dump)(struct ufs_qcom_phy *phy);
};
struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
@@ -184,5 +190,6 @@
void ufs_qcom_phy_write_tbl(struct ufs_qcom_phy *ufs_qcom_phy,
struct ufs_qcom_phy_calibration *tbl,
int tbl_size);
-
+void ufs_qcom_phy_dump_regs(struct ufs_qcom_phy *phy,
+ int offset, int len, char *prefix);
#endif
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3-660.c b/drivers/phy/phy-qcom-ufs-qmp-v3-660.c
new file mode 100644
index 0000000..9450e18
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3-660.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "phy-qcom-ufs-qmp-v3-660.h"
+
+#define UFS_PHY_NAME "ufs_phy_qmp_v3_660"
+
+static
+int ufs_qcom_phy_qmp_v3_660_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
+ bool is_rate_B)
+{
+ int err;
+ int tbl_size_A, tbl_size_B;
+ struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
+ u8 major = ufs_qcom_phy->host_ctrl_rev_major;
+ u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
+ u16 step = ufs_qcom_phy->host_ctrl_rev_step;
+
+ tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
+ tbl_B = phy_cal_table_rate_B;
+
+ if ((major == 0x3) && (minor == 0x001) && (step == 0x001)) {
+ tbl_A = phy_cal_table_rate_A_3_1_1;
+ tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_3_1_1);
+ } else {
+ dev_err(ufs_qcom_phy->dev,
+ "%s: Unknown UFS-PHY version (major 0x%x minor 0x%x step 0x%x), no calibration values\n",
+ __func__, major, minor, step);
+ err = -ENODEV;
+ goto out;
+ }
+
+ err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
+ tbl_A, tbl_size_A,
+ tbl_B, tbl_size_B,
+ is_rate_B);
+
+ if (err)
+ dev_err(ufs_qcom_phy->dev,
+ "%s: ufs_qcom_phy_calibrate() failed %d\n",
+ __func__, err);
+
+out:
+ return err;
+}
+
+static int ufs_qcom_phy_qmp_v3_660_init(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy_qmp_v3_660 *phy = phy_get_drvdata(generic_phy);
+ struct ufs_qcom_phy *phy_common = &phy->common_cfg;
+ int err;
+
+ err = ufs_qcom_phy_init_clks(generic_phy, phy_common);
+ if (err) {
+ dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common);
+ if (err) {
+ dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
+ __func__, err);
+ goto out;
+ }
+
+out:
+ return err;
+}
+
+static
+void ufs_qcom_phy_qmp_v3_660_power_control(struct ufs_qcom_phy *phy,
+ bool power_ctrl)
+{
+ if (!power_ctrl) {
+ /* apply analog power collapse */
+ writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+ /*
+ * Make sure that PHY knows its analog rail is going to be
+ * powered OFF.
+ */
+ mb();
+ } else {
+ /* bring PHY out of analog power collapse */
+ writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+
+ /*
+ * Before any transactions involving PHY, ensure PHY knows
+ * that it's analog rail is powered ON.
+ */
+ mb();
+ }
+}
+
+static inline
+void ufs_qcom_phy_qmp_v3_660_set_tx_lane_enable(struct ufs_qcom_phy *phy,
+ u32 val)
+{
+ /*
+ * v3 PHY does not have TX_LANE_ENABLE register.
+ * Implement this function so as not to propagate error to caller.
+ */
+}
+
+static
+void ufs_qcom_phy_qmp_v3_660_ctrl_rx_linecfg(struct ufs_qcom_phy *phy,
+ bool ctrl)
+{
+ u32 temp;
+
+ temp = readl_relaxed(phy->mmio + UFS_PHY_LINECFG_DISABLE);
+
+ if (ctrl) /* enable RX LineCfg */
+ temp &= ~UFS_PHY_RX_LINECFG_DISABLE_BIT;
+ else /* disable RX LineCfg */
+ temp |= UFS_PHY_RX_LINECFG_DISABLE_BIT;
+
+ writel_relaxed(temp, phy->mmio + UFS_PHY_LINECFG_DISABLE);
+ /* Make sure that RX LineCfg config applied before we return */
+ mb();
+}
+
+static inline void ufs_qcom_phy_qmp_v3_660_start_serdes(
+ struct ufs_qcom_phy *phy)
+{
+ u32 tmp;
+
+ tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
+ tmp &= ~MASK_SERDES_START;
+ tmp |= (1 << OFFSET_SERDES_START);
+ writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
+ /* Ensure register value is committed */
+ mb();
+}
+
+static int ufs_qcom_phy_qmp_v3_660_is_pcs_ready(
+ struct ufs_qcom_phy *phy_common)
+{
+ int err = 0;
+ u32 val;
+
+ err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
+ val, (val & MASK_PCS_READY), 10, 1000000);
+ if (err)
+ dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
+ __func__, err);
+ return err;
+}
+
+static void ufs_qcom_phy_qmp_v3_660_dbg_register_dump(
+ struct ufs_qcom_phy *phy)
+{
+ ufs_qcom_phy_dump_regs(phy, COM_BASE, COM_SIZE,
+ "PHY QSERDES COM Registers ");
+ ufs_qcom_phy_dump_regs(phy, PHY_BASE, PHY_SIZE,
+ "PHY Registers ");
+ ufs_qcom_phy_dump_regs(phy, RX_BASE, RX_SIZE,
+ "PHY RX0 Registers ");
+ ufs_qcom_phy_dump_regs(phy, TX_BASE, TX_SIZE,
+ "PHY TX0 Registers ");
+}
+
+struct phy_ops ufs_qcom_phy_qmp_v3_660_phy_ops = {
+ .init = ufs_qcom_phy_qmp_v3_660_init,
+ .exit = ufs_qcom_phy_exit,
+ .power_on = ufs_qcom_phy_power_on,
+ .power_off = ufs_qcom_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+struct ufs_qcom_phy_specific_ops phy_v3_660_ops = {
+ .calibrate_phy = ufs_qcom_phy_qmp_v3_660_phy_calibrate,
+ .start_serdes = ufs_qcom_phy_qmp_v3_660_start_serdes,
+ .is_physical_coding_sublayer_ready =
+ ufs_qcom_phy_qmp_v3_660_is_pcs_ready,
+ .set_tx_lane_enable = ufs_qcom_phy_qmp_v3_660_set_tx_lane_enable,
+ .ctrl_rx_linecfg = ufs_qcom_phy_qmp_v3_660_ctrl_rx_linecfg,
+ .power_control = ufs_qcom_phy_qmp_v3_660_power_control,
+ .dbg_register_dump = ufs_qcom_phy_qmp_v3_660_dbg_register_dump,
+};
+
+static int ufs_qcom_phy_qmp_v3_660_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy;
+ struct ufs_qcom_phy_qmp_v3_660 *phy;
+ int err = 0;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
+ &ufs_qcom_phy_qmp_v3_660_phy_ops,
+ &phy_v3_660_ops);
+
+ if (!generic_phy) {
+ dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
+ __func__);
+ err = -EIO;
+ goto out;
+ }
+
+ phy_set_drvdata(generic_phy, phy);
+
+ strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
+ sizeof(phy->common_cfg.name));
+
+out:
+ return err;
+}
+
+static int ufs_qcom_phy_qmp_v3_660_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy = to_phy(dev);
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+ int err = 0;
+
+ err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
+ if (err)
+ dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
+ __func__, err);
+
+ return err;
+}
+
+static const struct of_device_id ufs_qcom_phy_qmp_v3_660_of_match[] = {
+ {.compatible = "qcom,ufs-phy-qmp-v3-660"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_v3_660_of_match);
+
+static struct platform_driver ufs_qcom_phy_qmp_v3_660_driver = {
+ .probe = ufs_qcom_phy_qmp_v3_660_probe,
+ .remove = ufs_qcom_phy_qmp_v3_660_remove,
+ .driver = {
+ .of_match_table = ufs_qcom_phy_qmp_v3_660_of_match,
+ .name = "ufs_qcom_phy_qmp_v3_660",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(ufs_qcom_phy_qmp_v3_660_driver);
+
+MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP v3 660");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3-660.h b/drivers/phy/phy-qcom-ufs-qmp-v3-660.h
new file mode 100644
index 0000000..89fa5d3
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3-660.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef UFS_QCOM_PHY_QMP_V3_660_H_
+#define UFS_QCOM_PHY_QMP_V3_660_H_
+
+#include "phy-qcom-ufs-i.h"
+
+/* QCOM UFS PHY control registers */
+#define COM_BASE 0x000
+#define COM_OFF(x) (COM_BASE + x)
+#define COM_SIZE 0x1C0
+
+#define TX_BASE 0x400
+#define TX_OFF(x) (TX_BASE + x)
+#define TX_SIZE 0x128
+
+#define RX_BASE 0x600
+#define RX_OFF(x) (RX_BASE + x)
+#define RX_SIZE 0x1FC
+
+#define PHY_BASE 0xC00
+#define PHY_OFF(x) (PHY_BASE + x)
+#define PHY_SIZE 0x1B4
+
+/* UFS PHY QSERDES COM registers */
+#define QSERDES_COM_ATB_SEL1 COM_OFF(0x00)
+#define QSERDES_COM_ATB_SEL2 COM_OFF(0x04)
+#define QSERDES_COM_FREQ_UPDATE COM_OFF(0x08)
+#define QSERDES_COM_BG_TIMER COM_OFF(0x0C)
+#define QSERDES_COM_SSC_EN_CENTER COM_OFF(0x10)
+#define QSERDES_COM_SSC_ADJ_PER1 COM_OFF(0x14)
+#define QSERDES_COM_SSC_ADJ_PER2 COM_OFF(0x18)
+#define QSERDES_COM_SSC_PER1 COM_OFF(0x1C)
+#define QSERDES_COM_SSC_PER2 COM_OFF(0x20)
+#define QSERDES_COM_SSC_STEP_SIZE1 COM_OFF(0x24)
+#define QSERDES_COM_SSC_STEP_SIZE2 COM_OFF(0x28)
+#define QSERDES_COM_POST_DIV COM_OFF(0x2C)
+#define QSERDES_COM_POST_DIV_MUX COM_OFF(0x30)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x34)
+#define QSERDES_COM_CLK_ENABLE1 COM_OFF(0x38)
+#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x3C)
+#define QSERDES_COM_SYSCLK_BUF_ENABLE COM_OFF(0x40)
+#define QSERDES_COM_PLL_EN COM_OFF(0x44)
+#define QSERDES_COM_PLL_IVCO COM_OFF(0x48)
+#define QSERDES_COM_LOCK_CMP1_MODE0 COM_OFF(0X4C)
+#define QSERDES_COM_LOCK_CMP2_MODE0 COM_OFF(0X50)
+#define QSERDES_COM_LOCK_CMP3_MODE0 COM_OFF(0X54)
+#define QSERDES_COM_LOCK_CMP1_MODE1 COM_OFF(0X58)
+#define QSERDES_COM_LOCK_CMP2_MODE1 COM_OFF(0X5C)
+#define QSERDES_COM_LOCK_CMP3_MODE1 COM_OFF(0X60)
+#define QSERDES_COM_CMD_RSVD0 COM_OFF(0x64)
+#define QSERDES_COM_EP_CLOCK_DETECT_CTRL COM_OFF(0x68)
+#define QSERDES_COM_SYSCLK_DET_COMP_STATUS COM_OFF(0x6C)
+#define QSERDES_COM_BG_TRIM COM_OFF(0x70)
+#define QSERDES_COM_CLK_EP_DIV COM_OFF(0x74)
+#define QSERDES_COM_CP_CTRL_MODE0 COM_OFF(0x78)
+#define QSERDES_COM_CP_CTRL_MODE1 COM_OFF(0x7C)
+#define QSERDES_COM_CMN_RSVD1 COM_OFF(0x80)
+#define QSERDES_COM_PLL_RCTRL_MODE0 COM_OFF(0x84)
+#define QSERDES_COM_PLL_RCTRL_MODE1 COM_OFF(0x88)
+#define QSERDES_COM_CMN_RSVD2 COM_OFF(0x8C)
+#define QSERDES_COM_PLL_CCTRL_MODE0 COM_OFF(0x90)
+#define QSERDES_COM_PLL_CCTRL_MODE1 COM_OFF(0x94)
+#define QSERDES_COM_CMN_RSVD3 COM_OFF(0x98)
+#define QSERDES_COM_PLL_CNTRL COM_OFF(0x9C)
+#define QSERDES_COM_PHASE_SEL_CTRL COM_OFF(0xA0)
+#define QSERDES_COM_PHASE_SEL_DC COM_OFF(0xA4)
+#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM COM_OFF(0xA8)
+#define QSERDES_COM_SYSCLK_EN_SEL COM_OFF(0xAC)
+#define QSERDES_COM_CML_SYSCLK_SEL COM_OFF(0xB0)
+#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0xB4)
+#define QSERDES_COM_RESETSM_CNTRL2 COM_OFF(0xB8)
+#define QSERDES_COM_RESTRIM_CTRL COM_OFF(0xBC)
+#define QSERDES_COM_RESTRIM_CTRL2 COM_OFF(0xC0)
+#define QSERDES_COM_LOCK_CMP_EN COM_OFF(0xC8)
+#define QSERDES_COM_LOCK_CMP_CFG COM_OFF(0xCC)
+#define QSERDES_COM_DEC_START_MODE0 COM_OFF(0xD0)
+#define QSERDES_COM_DEC_START_MODE1 COM_OFF(0xD4)
+#define QSERDES_COM_VCOCAL_DEADMAN_CTRL COM_OFF(0xD8)
+#define QSERDES_COM_DIV_FRAC_START1_MODE0 COM_OFF(0xDC)
+#define QSERDES_COM_DIV_FRAC_START2_MODE0 COM_OFF(0xE0)
+#define QSERDES_COM_DIV_FRAC_START3_MODE0 COM_OFF(0xE4)
+#define QSERDES_COM_DIV_FRAC_START1_MODE1 COM_OFF(0xE8)
+#define QSERDES_COM_DIV_FRAC_START2_MODE1 COM_OFF(0xEC)
+#define QSERDES_COM_DIV_FRAC_START3_MODE1 COM_OFF(0xF0)
+#define QSERDES_COM_VCO_TUNE_MINVAL1 COM_OFF(0xF4)
+#define QSERDES_COM_VCO_TUNE_MINVAL2 COM_OFF(0xF8)
+#define QSERDES_COM_CMN_RSVD4 COM_OFF(0xFC)
+#define QSERDES_COM_INTEGLOOP_INITVAL COM_OFF(0x100)
+#define QSERDES_COM_INTEGLOOP_EN COM_OFF(0x104)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 COM_OFF(0x108)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 COM_OFF(0x10C)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 COM_OFF(0x110)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 COM_OFF(0x114)
+#define QSERDES_COM_VCO_TUNE_MAXVAL1 COM_OFF(0x118)
+#define QSERDES_COM_VCO_TUNE_MAXVAL2 COM_OFF(0x11C)
+#define QSERDES_COM_RES_TRIM_CONTROL2 COM_OFF(0x120)
+#define QSERDES_COM_VCO_TUNE_CTRL COM_OFF(0x124)
+#define QSERDES_COM_VCO_TUNE_MAP COM_OFF(0x128)
+#define QSERDES_COM_VCO_TUNE1_MODE0 COM_OFF(0x12C)
+#define QSERDES_COM_VCO_TUNE2_MODE0 COM_OFF(0x130)
+#define QSERDES_COM_VCO_TUNE1_MODE1 COM_OFF(0x134)
+#define QSERDES_COM_VCO_TUNE2_MODE1 COM_OFF(0x138)
+#define QSERDES_COM_VCO_TUNE_INITVAL1 COM_OFF(0x13C)
+#define QSERDES_COM_VCO_TUNE_INITVAL2 COM_OFF(0x140)
+#define QSERDES_COM_VCO_TUNE_TIMER1 COM_OFF(0x144)
+#define QSERDES_COM_VCO_TUNE_TIMER2 COM_OFF(0x148)
+#define QSERDES_COM_SAR COM_OFF(0x14C)
+#define QSERDES_COM_SAR_CLK COM_OFF(0x150)
+#define QSERDES_COM_SAR_CODE_OUT_STATUS COM_OFF(0x154)
+#define QSERDES_COM_SAR_CODE_READY_STATUS COM_OFF(0x158)
+#define QSERDES_COM_CMN_STATUS COM_OFF(0x15C)
+#define QSERDES_COM_RESET_SM_STATUS COM_OFF(0x160)
+#define QSERDES_COM_RESTRIM_CODE_STATUS COM_OFF(0x164)
+#define QSERDES_COM_PLLCAL_CODE1_STATUS COM_OFF(0x168)
+#define QSERDES_COM_PLLCAL_CODE2_STATUS COM_OFF(0x16C)
+#define QSERDES_COM_BG_CTRL COM_OFF(0x170)
+#define QSERDES_COM_CLK_SELECT COM_OFF(0x174)
+#define QSERDES_COM_HSCLK_SEL COM_OFF(0x178)
+#define QSERDES_COM_INTEGLOOP_BINCODE_STATUS COM_OFF(0x17C)
+#define QSERDES_COM_PLL_ANALOG COM_OFF(0x180)
+#define QSERDES_COM_CORECLK_DIV COM_OFF(0x184)
+#define QSERDES_COM_SW_RESET COM_OFF(0x188)
+#define QSERDES_COM_CORE_CLK_EN COM_OFF(0x18C)
+#define QSERDES_COM_C_READY_STATUS COM_OFF(0x190)
+#define QSERDES_COM_CMN_CONFIG COM_OFF(0x194)
+#define QSERDES_COM_CMN_RATE_OVERRIDE COM_OFF(0x198)
+#define QSERDES_COM_SVS_MODE_CLK_SEL COM_OFF(0x19C)
+#define QSERDES_COM_DEBUG_BUS0 COM_OFF(0x1A0)
+#define QSERDES_COM_DEBUG_BUS1 COM_OFF(0x1A4)
+#define QSERDES_COM_DEBUG_BUS2 COM_OFF(0x1A8)
+#define QSERDES_COM_DEBUG_BUS3 COM_OFF(0x1AC)
+#define QSERDES_COM_DEBUG_BUS_SEL COM_OFF(0x1B0)
+#define QSERDES_COM_CMN_MISC1 COM_OFF(0x1B4)
+#define QSERDES_COM_CORECLK_DIV_MODE1 COM_OFF(0x1BC)
+#define QSERDES_COM_CMN_RSVD5 COM_OFF(0x1C0)
+
+/* UFS PHY registers */
+#define UFS_PHY_PHY_START PHY_OFF(0x00)
+#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x04)
+#define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x34)
+#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x3C)
+#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP PHY_OFF(0xCC)
+#define UFS_PHY_LINECFG_DISABLE PHY_OFF(0x138)
+#define UFS_PHY_RX_SYM_RESYNC_CTRL PHY_OFF(0x13C)
+#define UFS_PHY_RX_SIGDET_CTRL2 PHY_OFF(0x148)
+#define UFS_PHY_RX_PWM_GEAR_BAND PHY_OFF(0x154)
+#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x168)
+
+/* UFS PHY TX registers */
+#define QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN TX_OFF(0x68)
+#define QSERDES_TX_LANE_MODE TX_OFF(0x94)
+
+/* UFS PHY RX registers */
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_HALF RX_OFF(0x30)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER RX_OFF(0x34)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN_EIGHTH RX_OFF(0x38)
+#define QSERDES_RX_UCDR_SVS_SO_GAIN RX_OFF(0x3C)
+#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN RX_OFF(0x40)
+#define QSERDES_RX_UCDR_SO_SATURATION_ENABLE RX_OFF(0x48)
+#define QSERDES_RX_RX_TERM_BW RX_OFF(0x90)
+#define QSERDES_RX_RX_EQ_GAIN1_LSB RX_OFF(0xC4)
+#define QSERDES_RX_RX_EQ_GAIN1_MSB RX_OFF(0xC8)
+#define QSERDES_RX_RX_EQ_GAIN2_LSB RX_OFF(0xCC)
+#define QSERDES_RX_RX_EQ_GAIN2_MSB RX_OFF(0xD0)
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 RX_OFF(0xD8)
+#define QSERDES_RX_SIGDET_CNTRL RX_OFF(0x114)
+#define QSERDES_RX_SIGDET_LVL RX_OFF(0x118)
+#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL RX_OFF(0x11C)
+#define QSERDES_RX_RX_INTERFACE_MODE RX_OFF(0x12C)
+
+
+#define UFS_PHY_RX_LINECFG_DISABLE_BIT BIT(1)
+
+/*
+ * This structure represents the v3 660 specific phy.
+ * common_cfg MUST remain the first field in this structure
+ * in case extra fields are added. This way, when calling
+ * get_ufs_qcom_phy() of generic phy, we can extract the
+ * common phy structure (struct ufs_qcom_phy) out of it
+ * regardless of the relevant specific phy.
+ */
+struct ufs_qcom_phy_qmp_v3_660 {
+ struct ufs_qcom_phy common_cfg;
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_3_1_1[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_CFG, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
+
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN, 0x45),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE, 0x06),
+
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_LVL, 0x24),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x40),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_BW, 0x5B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0D),
+
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IVCO, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TRIM, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_PWM_GEAR_BAND, 0x15),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_SO_SATURATION_ENABLE, 0x4B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL2, 0x6c),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03),
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x44),
+};
+
+#endif
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.c b/drivers/phy/phy-qcom-ufs-qmp-v3.c
index 6b8dbc2..0bfde0c7 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-v3.c
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, 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
@@ -20,26 +20,24 @@
int ufs_qcom_phy_qmp_v3_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
bool is_rate_B)
{
- int err;
- int tbl_size_A, tbl_size_B;
- struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
+ /*
+ * Writing PHY calibration in this order:
+ * 1. Write Rate-A calibration first (1-lane mode).
+ * 2. Write 2nd lane configuration if needed.
+ * 3. Write Rate-B calibration overrides
+ */
+ ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_rate_A,
+ ARRAY_SIZE(phy_cal_table_rate_A));
+ if (ufs_qcom_phy->lanes_per_direction == 2)
+ ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_2nd_lane,
+ ARRAY_SIZE(phy_cal_table_2nd_lane));
+ if (is_rate_B)
+ ufs_qcom_phy_write_tbl(ufs_qcom_phy, phy_cal_table_rate_B,
+ ARRAY_SIZE(phy_cal_table_rate_B));
+ /* flush buffered writes */
+ mb();
- tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
- tbl_B = phy_cal_table_rate_B;
-
- tbl_A = phy_cal_table_rate_A;
- tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
-
- err = ufs_qcom_phy_calibrate(ufs_qcom_phy,
- tbl_A, tbl_size_A,
- tbl_B, tbl_size_B,
- is_rate_B);
-
- if (err)
- dev_err(ufs_qcom_phy->dev,
- "%s: ufs_qcom_phy_calibrate() failed %d\n",
- __func__, err);
- return err;
+ return 0;
}
static int ufs_qcom_phy_qmp_v3_init(struct phy *generic_phy)
@@ -145,37 +143,20 @@
return err;
}
-static
-int ufs_qcom_phy_qmp_v3_configure_lpm(struct ufs_qcom_phy *ufs_qcom_phy,
- bool enable)
+static void ufs_qcom_phy_qmp_v3_dbg_register_dump(struct ufs_qcom_phy *phy)
{
- int err = 0;
- int tbl_size;
- struct ufs_qcom_phy_calibration *tbl = NULL;
-
- /* The default low power mode configuration is SVS2 */
- if (enable) {
- tbl_size = ARRAY_SIZE(phy_cal_table_svs2_enable);
- tbl = phy_cal_table_svs2_enable;
- } else {
- tbl_size = ARRAY_SIZE(phy_cal_table_svs2_disable);
- tbl = phy_cal_table_svs2_disable;
- }
-
- if (!tbl) {
- dev_err(ufs_qcom_phy->dev, "%s: tbl for SVS2 %s is NULL",
- __func__, enable ? "enable" : "disable");
- err = -EINVAL;
- goto out;
- }
-
- ufs_qcom_phy_write_tbl(ufs_qcom_phy, tbl, tbl_size);
-
- /* flush buffered writes */
- mb();
-
-out:
- return err;
+ ufs_qcom_phy_dump_regs(phy, COM_BASE, COM_SIZE,
+ "PHY QSERDES COM Registers ");
+ ufs_qcom_phy_dump_regs(phy, PHY_BASE, PHY_SIZE,
+ "PHY Registers ");
+ ufs_qcom_phy_dump_regs(phy, RX_BASE(0), RX_SIZE,
+ "PHY RX0 Registers ");
+ ufs_qcom_phy_dump_regs(phy, TX_BASE(0), TX_SIZE,
+ "PHY TX0 Registers ");
+ ufs_qcom_phy_dump_regs(phy, RX_BASE(1), RX_SIZE,
+ "PHY RX1 Registers ");
+ ufs_qcom_phy_dump_regs(phy, TX_BASE(1), TX_SIZE,
+ "PHY TX1 Registers ");
}
struct phy_ops ufs_qcom_phy_qmp_v3_phy_ops = {
@@ -193,7 +174,7 @@
.set_tx_lane_enable = ufs_qcom_phy_qmp_v3_set_tx_lane_enable,
.ctrl_rx_linecfg = ufs_qcom_phy_qmp_v3_ctrl_rx_linecfg,
.power_control = ufs_qcom_phy_qmp_v3_power_control,
- .configure_lpm = ufs_qcom_phy_qmp_v3_configure_lpm,
+ .dbg_register_dump = ufs_qcom_phy_qmp_v3_dbg_register_dump,
};
static int ufs_qcom_phy_qmp_v3_probe(struct platform_device *pdev)
diff --git a/drivers/phy/phy-qcom-ufs-qmp-v3.h b/drivers/phy/phy-qcom-ufs-qmp-v3.h
index e9ac76b..4851aac 100644
--- a/drivers/phy/phy-qcom-ufs-qmp-v3.h
+++ b/drivers/phy/phy-qcom-ufs-qmp-v3.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, 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
@@ -18,10 +18,18 @@
#include "phy-qcom-ufs-i.h"
/* QCOM UFS PHY control registers */
-#define COM_OFF(x) (0x000 + x)
-#define PHY_OFF(x) (0xC00 + x)
-#define TX_OFF(n, x) (0x400 + (0x400 * n) + x)
-#define RX_OFF(n, x) (0x600 + (0x400 * n) + x)
+#define COM_BASE 0x000
+#define COM_SIZE 0x18C
+#define PHY_BASE 0xC00
+#define PHY_SIZE 0x1DC
+#define TX_BASE(n) (0x400 + (0x400 * n))
+#define TX_SIZE 0x128
+#define RX_BASE(n) (0x600 + (0x400 * n))
+#define RX_SIZE 0x1FC
+#define COM_OFF(x) (COM_BASE + x)
+#define PHY_OFF(x) (PHY_BASE + x)
+#define TX_OFF(n, x) (TX_BASE(n) + x)
+#define RX_OFF(n, x) (RX_BASE(n) + x)
/* UFS PHY QSERDES COM registers */
#define QSERDES_COM_ATB_SEL1 COM_OFF(0x00)
@@ -133,9 +141,13 @@
#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x34)
#define UFS_PHY_LINECFG_DISABLE PHY_OFF(0x130)
#define UFS_PHY_RX_SYM_RESYNC_CTRL PHY_OFF(0x134)
+#define UFS_PHY_RX_MIN_HIBERN8_TIME PHY_OFF(0x138)
+#define UFS_PHY_RX_SIGDET_CTRL1 PHY_OFF(0x13C)
#define UFS_PHY_RX_SIGDET_CTRL2 PHY_OFF(0x140)
#define UFS_PHY_RX_PWM_GEAR_BAND PHY_OFF(0x14C)
#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x160)
+#define UFS_PHY_TX_MID_TERM_CTRL1 PHY_OFF(0x1BC)
+#define UFS_PHY_MULTI_LANE_CTRL1 PHY_OFF(0x1C4)
/* UFS PHY TX registers */
#define QSERDES_TX0_TRANSCEIVER_BIAS_EN TX_OFF(0, 0x5C)
@@ -143,6 +155,9 @@
#define QSERDES_TX0_LANE_MODE_2 TX_OFF(0, 0x90)
#define QSERDES_TX0_LANE_MODE_3 TX_OFF(0, 0x94)
+#define QSERDES_TX1_LANE_MODE_1 TX_OFF(1, 0x8C)
+
+
/* UFS PHY RX registers */
#define QSERDES_RX0_UCDR_SVS_SO_GAIN_HALF RX_OFF(0, 0x24)
#define QSERDES_RX0_UCDR_SVS_SO_GAIN_QUARTER RX_OFF(0, 0x28)
@@ -163,6 +178,22 @@
#define QSERDES_RX0_SIGDET_DEGLITCH_CNTRL RX_OFF(0, 0x10C)
#define QSERDES_RX0_RX_INTERFACE_MODE RX_OFF(0, 0x11C)
+#define QSERDES_RX1_UCDR_SVS_SO_GAIN_HALF RX_OFF(1, 0x24)
+#define QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER RX_OFF(1, 0x28)
+#define QSERDES_RX1_UCDR_SVS_SO_GAIN RX_OFF(1, 0x2C)
+#define QSERDES_RX1_UCDR_FASTLOCK_FO_GAIN RX_OFF(1, 0x30)
+#define QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE RX_OFF(1, 0x34)
+#define QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW RX_OFF(1, 0x3C)
+#define QSERDES_RX1_UCDR_PI_CONTROLS RX_OFF(1, 0x44)
+#define QSERDES_RX1_RX_TERM_BW RX_OFF(1, 0x7C)
+#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2 RX_OFF(1, 0xD4)
+#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3 RX_OFF(1, 0xD8)
+#define QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4 RX_OFF(1, 0xDC)
+#define QSERDES_RX1_SIGDET_CNTRL RX_OFF(1, 0x104)
+#define QSERDES_RX1_SIGDET_LVL RX_OFF(1, 0x108)
+#define QSERDES_RX1_SIGDET_DEGLITCH_CNTRL RX_OFF(1, 0x10C)
+#define QSERDES_RX1_RX_INTERFACE_MODE RX_OFF(1, 0x11C)
+
#define UFS_PHY_RX_LINECFG_DISABLE_BIT BIT(1)
/*
@@ -181,6 +212,7 @@
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x06),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xD5),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
@@ -195,22 +227,22 @@
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL1, 0xFF),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x08),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x06),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x34),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x36),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3F),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0xCB),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0xDA),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x01),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xFF),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0C),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x08),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x06),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x34),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x36),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x3F),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xB2),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xC1),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0F),
@@ -234,42 +266,33 @@
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_LARGE_AMP_DRV_LVL, 0x0A),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_SMALL_AMP_DRV_LVL, 0x02),
UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SYM_RESYNC_CTRL, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TX_MID_TERM_CTRL1, 0x43),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL1, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_MIN_HIBERN8_TIME, 0x9A), /* 8 us */
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_2nd_lane[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX1_LANE_MODE_1, 0x06),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_LVL, 0x24),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_CNTRL, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_SIGDET_DEGLITCH_CNTRL, 0x1E),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_INTERFACE_MODE, 0x40),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_FO_GAIN, 0x0B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_TERM_BW, 0x5B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL2, 0x06),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_RX_EQU_ADAPTOR_CNTRL4, 0x1D),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_HALF, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SVS_SO_GAIN, 0x04),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_SO_SATURATION_AND_ENABLE, 0x4B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_PI_CONTROLS, 0xF1),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX1_UCDR_FASTLOCK_COUNT_LOW, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_MULTI_LANE_CTRL1, 0x02),
};
static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x44),
};
-static struct ufs_qcom_phy_calibration phy_cal_table_svs2_enable[] = {
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE0, 0x14),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x14),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x0a),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x7e),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0x7f),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x06),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x7e),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x99),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x07),
- UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, 0x0b),
- UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, 0x66),
-};
-
-static struct ufs_qcom_phy_calibration phy_cal_table_svs2_disable[] = {
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE0, 0x0a),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x3f),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
- UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
- UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_MSB, 0x16),
- UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_TIMER_20US_CORECLK_STEPS_LSB, 0xcc),
-};
-
#endif
diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
index b8b9080..d18929f 100644
--- a/drivers/phy/phy-qcom-ufs.c
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -15,13 +15,15 @@
#include "phy-qcom-ufs-i.h"
#define MAX_PROP_NAME 32
-#define VDDA_PHY_MIN_UV 1000000
-#define VDDA_PHY_MAX_UV 1000000
+#define VDDA_PHY_MIN_UV 800000
+#define VDDA_PHY_MAX_UV 925000
#define VDDA_PLL_MIN_UV 1200000
#define VDDA_PLL_MAX_UV 1800000
#define VDDP_REF_CLK_MIN_UV 1200000
#define VDDP_REF_CLK_MAX_UV 1200000
+#define UFS_PHY_DEFAULT_LANES_PER_DIRECTION 1
+
static int __ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *,
const char *, bool);
static int ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *,
@@ -113,6 +115,19 @@
goto out;
}
+ if (of_property_read_u32(dev->of_node, "lanes-per-direction",
+ &common_cfg->lanes_per_direction))
+ common_cfg->lanes_per_direction =
+ UFS_PHY_DEFAULT_LANES_PER_DIRECTION;
+
+ /*
+ * UFS PHY power management is managed by its parent (UFS host
+ * controller) hence set the no the no runtime PM callbacks flag
+ * on UFS PHY device to avoid any accidental attempt to call the
+ * PM callbacks for PHY device.
+ */
+ pm_runtime_no_callbacks(&generic_phy->dev);
+
common_cfg->phy_spec_ops = phy_spec_ops;
common_cfg->dev = dev;
@@ -191,27 +206,20 @@
struct ufs_qcom_phy *phy_common)
{
int err;
- struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
- err = ufs_qcom_phy_clk_get(generic_phy, "tx_iface_clk",
- &phy_common->tx_iface_clk);
/*
* tx_iface_clk does not exist in newer version of ufs-phy HW,
* so don't return error if it is not found
*/
- if (err)
- dev_dbg(phy->dev, "%s: failed to get tx_iface_clk\n",
- __func__);
+ __ufs_qcom_phy_clk_get(generic_phy, "tx_iface_clk",
+ &phy_common->tx_iface_clk, false);
- err = ufs_qcom_phy_clk_get(generic_phy, "rx_iface_clk",
- &phy_common->rx_iface_clk);
/*
* rx_iface_clk does not exist in newer version of ufs-phy HW,
* so don't return error if it is not found
*/
- if (err)
- dev_dbg(phy->dev, "%s: failed to get rx_iface_clk\n",
- __func__);
+ __ufs_qcom_phy_clk_get(generic_phy, "rx_iface_clk",
+ &phy_common->rx_iface_clk, false);
err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk_src",
&phy_common->ref_clk_src);
@@ -246,7 +254,6 @@
struct ufs_qcom_phy *phy_common)
{
int err;
- int vdda_phy_uV;
err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_pll,
"vdda-pll");
@@ -258,10 +265,6 @@
if (err)
goto out;
- vdda_phy_uV = regulator_get_voltage(phy_common->vdda_phy.reg);
- phy_common->vdda_phy.max_uV = vdda_phy_uV;
- phy_common->vdda_phy.min_uV = vdda_phy_uV;
-
/* vddp-ref-clk-* properties are optional */
__ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vddp_ref_clk,
"vddp-ref-clk", true);
@@ -279,6 +282,14 @@
char prop_name[MAX_PROP_NAME];
+ if (dev->of_node) {
+ snprintf(prop_name, MAX_PROP_NAME, "%s-supply", name);
+ if (!of_parse_phandle(dev->of_node, prop_name, 0)) {
+ dev_dbg(dev, "No vreg data found for %s\n", prop_name);
+ return optional ? err : -ENODATA;
+ }
+ }
+
vreg->name = kstrdup(name, GFP_KERNEL);
if (!vreg->name) {
err = -ENOMEM;
@@ -786,3 +797,21 @@
return ret;
}
EXPORT_SYMBOL(ufs_qcom_phy_configure_lpm);
+
+void ufs_qcom_phy_dump_regs(struct ufs_qcom_phy *phy, int offset,
+ int len, char *prefix)
+{
+ print_hex_dump(KERN_ERR, prefix,
+ len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE,
+ 16, 4, phy->mmio + offset, len, false);
+}
+EXPORT_SYMBOL(ufs_qcom_phy_dump_regs);
+
+void ufs_qcom_phy_dbg_register_dump(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+
+ if (ufs_qcom_phy->phy_spec_ops->dbg_register_dump)
+ ufs_qcom_phy->phy_spec_ops->dbg_register_dump(ufs_qcom_phy);
+}
+EXPORT_SYMBOL(ufs_qcom_phy_dbg_register_dump);
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/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 4b576cc..67adf58 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -727,6 +727,15 @@
msm_mux_reserved79,
msm_mux_reserved80,
msm_mux_qup15,
+ msm_mux_reserved81,
+ msm_mux_reserved82,
+ msm_mux_reserved83,
+ msm_mux_reserved84,
+ msm_mux_pcie1_pwrfault,
+ msm_mux_qup5,
+ msm_mux_reserved85,
+ msm_mux_pcie1_mrl,
+ msm_mux_reserved86,
msm_mux_reserved87,
msm_mux_reserved88,
msm_mux_tsif1_clk,
@@ -751,15 +760,6 @@
msm_mux_vfr_1,
msm_mux_tgu_ch2,
msm_mux_reserved92,
- msm_mux_reserved81,
- msm_mux_reserved82,
- msm_mux_reserved83,
- msm_mux_reserved84,
- msm_mux_pcie1_pwrfault,
- msm_mux_qup5,
- msm_mux_reserved85,
- msm_mux_pcie1_mrl,
- msm_mux_reserved86,
msm_mux_tsif2_clk,
msm_mux_sdc4_clk,
msm_mux_qup7,
@@ -1681,6 +1681,33 @@
static const char * const qup15_groups[] = {
"gpio81", "gpio82", "gpio83", "gpio84",
};
+static const char * const reserved81_groups[] = {
+ "gpio81",
+};
+static const char * const reserved82_groups[] = {
+ "gpio82",
+};
+static const char * const reserved83_groups[] = {
+ "gpio83",
+};
+static const char * const reserved84_groups[] = {
+ "gpio84",
+};
+static const char * const pcie1_pwrfault_groups[] = {
+ "gpio85",
+};
+static const char * const qup5_groups[] = {
+ "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const reserved85_groups[] = {
+ "gpio85",
+};
+static const char * const pcie1_mrl_groups[] = {
+ "gpio86",
+};
+static const char * const reserved86_groups[] = {
+ "gpio86",
+};
static const char * const reserved87_groups[] = {
"gpio87",
};
@@ -1753,33 +1780,6 @@
static const char * const reserved92_groups[] = {
"gpio92",
};
-static const char * const reserved81_groups[] = {
- "gpio81",
-};
-static const char * const reserved82_groups[] = {
- "gpio82",
-};
-static const char * const reserved83_groups[] = {
- "gpio83",
-};
-static const char * const reserved84_groups[] = {
- "gpio84",
-};
-static const char * const pcie1_pwrfault_groups[] = {
- "gpio85",
-};
-static const char * const qup5_groups[] = {
- "gpio85", "gpio86", "gpio87", "gpio88",
-};
-static const char * const reserved85_groups[] = {
- "gpio85",
-};
-static const char * const pcie1_mrl_groups[] = {
- "gpio86",
-};
-static const char * const reserved86_groups[] = {
- "gpio86",
-};
static const char * const tsif2_clk_groups[] = {
"gpio93",
};
@@ -2113,6 +2113,15 @@
FUNCTION(reserved79),
FUNCTION(reserved80),
FUNCTION(qup15),
+ FUNCTION(reserved81),
+ FUNCTION(reserved82),
+ FUNCTION(reserved83),
+ FUNCTION(reserved84),
+ FUNCTION(pcie1_pwrfault),
+ FUNCTION(qup5),
+ FUNCTION(reserved85),
+ FUNCTION(pcie1_mrl),
+ FUNCTION(reserved86),
FUNCTION(reserved87),
FUNCTION(reserved88),
FUNCTION(tsif1_clk),
@@ -2137,15 +2146,6 @@
FUNCTION(vfr_1),
FUNCTION(tgu_ch2),
FUNCTION(reserved92),
- FUNCTION(reserved81),
- FUNCTION(reserved82),
- FUNCTION(reserved83),
- FUNCTION(reserved84),
- FUNCTION(pcie1_pwrfault),
- FUNCTION(qup5),
- FUNCTION(reserved85),
- FUNCTION(pcie1_mrl),
- FUNCTION(reserved86),
FUNCTION(tsif2_clk),
FUNCTION(sdc4_clk),
FUNCTION(qup7),
@@ -2418,10 +2418,10 @@
PINGROUP(147, NORTH, NA, NA, reserved147, NA, NA, NA, NA, NA, NA),
PINGROUP(148, NORTH, NA, reserved148, NA, NA, NA, NA, NA, NA, NA),
PINGROUP(149, NORTH, NA, reserved149, NA, NA, NA, NA, NA, NA, NA),
- SDC_QDSD_PINGROUP(sdc2_clk, 0x59a000, 14, 6),
- SDC_QDSD_PINGROUP(sdc2_cmd, 0x59a000, 11, 3),
- SDC_QDSD_PINGROUP(sdc2_data, 0x59a000, 9, 0),
- UFS_RESET(ufs_reset, 0x59f000),
+ SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6),
+ SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0),
+ UFS_RESET(ufs_reset, 0x99f000),
};
static const struct msm_pinctrl_soc_data sdm845_pinctrl = {
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 77e9dd7..f06fb1f 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -138,6 +138,7 @@
* struct pmic_gpio_pad - keep current GPIO settings
* @base: Address base in SPMI device.
* @irq: IRQ number which this GPIO generate.
+ * @gpio_idx: The index in GPIO's hardware number space (1-based)
* @is_enabled: Set to false when GPIO should be put in high Z state.
* @out_value: Cached pin output value
* @have_buffer: Set to true if GPIO output could be configured in push-pull,
@@ -158,6 +159,7 @@
struct pmic_gpio_pad {
u16 base;
int irq;
+ int gpio_idx;
bool is_enabled;
bool out_value;
bool have_buffer;
@@ -179,6 +181,7 @@
struct regmap *map;
struct pinctrl_dev *ctrl;
struct gpio_chip chip;
+ const char **gpio_groups;
};
static const struct pinconf_generic_params pmic_gpio_bindings[] = {
@@ -297,7 +300,9 @@
const char *const **groups,
unsigned *const num_qgroups)
{
- *groups = pmic_gpio_groups;
+ struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = state->gpio_groups;
*num_qgroups = pctldev->desc->npins;
return 0;
}
@@ -637,7 +642,7 @@
pad = pctldev->desc->pins[pin].drv_data;
- seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET);
+ seq_printf(s, " gpio%-2d:", pad->gpio_idx);
val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL);
@@ -742,13 +747,29 @@
const struct of_phandle_args *gpio_desc,
u32 *flags)
{
+ int i;
+ struct pmic_gpio_state *state = gpiochip_get_data(chip);
+ struct pinctrl_desc *desc = state->ctrl->desc;
+ struct pmic_gpio_pad *pad;
+
if (chip->of_gpio_n_cells < 2)
return -EINVAL;
if (flags)
*flags = gpio_desc->args[1];
- return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
+ for (i = 0; i < chip->ngpio; i++) {
+ pad = desc->pins[i].drv_data;
+ if (pad->gpio_idx == gpio_desc->args[0]) {
+ dev_dbg(state->dev, "gpio%-2d xlate to pin%-2d\n",
+ gpio_desc->args[0], i);
+ return i;
+ }
+ }
+
+ dev_err(state->dev, "Couldn't find pin for gpio %d\n",
+ gpio_desc->args[0]);
+ return -ENODEV;
}
static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
@@ -934,43 +955,124 @@
struct pinctrl_desc *pctrldesc;
struct pmic_gpio_pad *pad, *pads;
struct pmic_gpio_state *state;
- int ret, npins, i;
- u32 reg;
+ int ret, npins, ngpios, i, j, pin_idx;
+ int disallowed_count = 0;
+ u32 reg[2], start, size;
+ u32 *disallowed = NULL;
- ret = of_property_read_u32(dev->of_node, "reg", ®);
+ ret = of_property_read_u32_array(dev->of_node, "reg", reg, 2);
if (ret < 0) {
- dev_err(dev, "missing base address");
+ dev_err(dev, "reg property reading failed\n");
return ret;
}
+ start = reg[0];
+ size = reg[1];
- npins = platform_irq_count(pdev);
- if (!npins)
+ ngpios = size / PMIC_GPIO_ADDRESS_RANGE;
+ if (ngpios == 0) {
+ dev_err(dev, "no gpios assigned\n");
+ return -ENODEV;
+ }
+
+ if (ngpios > ARRAY_SIZE(pmic_gpio_groups)) {
+ dev_err(dev, "reg property defines %d gpios, but only %d are allowed\n",
+ ngpios, (int)ARRAY_SIZE(pmic_gpio_groups));
return -EINVAL;
- if (npins < 0)
- return npins;
+ }
- BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups));
+ if (of_find_property(dev->of_node, "qcom,gpios-disallowed",
+ &disallowed_count)) {
+ disallowed_count /= sizeof(u32);
+ if (disallowed_count == 0) {
+ dev_err(dev, "No data in gpios-disallowed\n");
+ return -EINVAL;
+ }
+
+ disallowed = kcalloc(disallowed_count, sizeof(u32), GFP_KERNEL);
+ if (disallowed == NULL)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(dev->of_node,
+ "qcom,gpios-disallowed",
+ disallowed, disallowed_count);
+ if (ret < 0) {
+ dev_err(dev, "qcom,gpios-disallowed property reading failed, ret=%d\n",
+ ret);
+ goto err_free;
+ }
+
+ for (i = 0; i < disallowed_count; i++) {
+ if (disallowed[i] >= ngpios + PMIC_GPIO_PHYSICAL_OFFSET
+ || disallowed[i] < PMIC_GPIO_PHYSICAL_OFFSET) {
+ dev_err(dev, "invalid gpio = %d specified in qcom,gpios-disallowed, supported values: %d to %d\n",
+ disallowed[i],
+ PMIC_GPIO_PHYSICAL_OFFSET,
+ ngpios - 1 + PMIC_GPIO_PHYSICAL_OFFSET);
+ ret = -EINVAL;
+ goto err_free;
+ }
+ for (j = 0; j < i; j++) {
+ if (disallowed[i] == disallowed[j]) {
+ dev_err(dev, "duplicate gpio = %d listed in qcom,gpios-disallowed\n",
+ disallowed[i]);
+ ret = -EINVAL;
+ goto err_free;
+ }
+ }
+ dev_dbg(dev, "gpio %d NOT supported\n", disallowed[i]);
+ }
+ } else {
+ disallowed_count = 0;
+ }
+
+ npins = ngpios - disallowed_count;
+ if (npins <= 0) {
+ dev_err(dev, "No pins assigned\n");
+ ret = -ENODEV;
+ goto err_free;
+ }
+ if (platform_irq_count(pdev) != npins) {
+ dev_err(dev, "%d IRQs defined but %d expected\n",
+ platform_irq_count(pdev), npins);
+ ret = -EINVAL;
+ goto err_free;
+ }
state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
- if (!state)
- return -ENOMEM;
+ if (!state) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
platform_set_drvdata(pdev, state);
state->dev = &pdev->dev;
state->map = dev_get_regmap(dev->parent, NULL);
+ state->gpio_groups = devm_kcalloc(dev, sizeof(*state->gpio_groups),
+ npins, GFP_KERNEL);
+ if (!state->gpio_groups) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
- if (!pindesc)
- return -ENOMEM;
+ if (!pindesc) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
- if (!pads)
- return -ENOMEM;
+ if (!pads) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
- if (!pctrldesc)
- return -ENOMEM;
+ if (!pctrldesc) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
pctrldesc->pctlops = &pmic_gpio_pinctrl_ops;
pctrldesc->pmxops = &pmic_gpio_pinmux_ops;
@@ -984,22 +1086,42 @@
#ifdef CONFIG_DEBUG_FS
pctrldesc->custom_conf_items = pmic_conf_items;
#endif
+ for (pin_idx = 0, i = 0; i < ngpios; i++) {
+ for (j = 0; j < disallowed_count; j++) {
+ if (i + PMIC_GPIO_PHYSICAL_OFFSET == disallowed[j])
+ break;
+ }
+ if (j != disallowed_count)
+ continue;
- for (i = 0; i < npins; i++, pindesc++) {
- pad = &pads[i];
+ pad = &pads[pin_idx];
pindesc->drv_data = pad;
- pindesc->number = i;
+ pindesc->number = pin_idx;
pindesc->name = pmic_gpio_groups[i];
- pad->irq = platform_get_irq(pdev, i);
- if (pad->irq < 0)
- return pad->irq;
+ pad->gpio_idx = i + PMIC_GPIO_PHYSICAL_OFFSET;
+ pad->irq = platform_get_irq(pdev, pin_idx);
+ if (pad->irq < 0) {
+ dev_err(state->dev,
+ "failed to get irq for gpio %d (pin %d), ret=%d\n",
+ pad->gpio_idx, pin_idx, pad->irq);
+ ret = pad->irq;
+ goto err_free;
+ }
+ /* Every pin is a group */
+ state->gpio_groups[pin_idx] = pmic_gpio_groups[i];
- pad->base = reg + i * PMIC_GPIO_ADDRESS_RANGE;
+ pad->base = start + i * PMIC_GPIO_ADDRESS_RANGE;
ret = pmic_gpio_populate(state, pad);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ dev_err(state->dev,
+ "failed to populate gpio %d, ret=%d\n",
+ i, ret);
+ goto err_free;
+ }
+ pindesc++;
+ pin_idx++;
}
state->chip = pmic_gpio_gpio_template;
@@ -1011,25 +1133,29 @@
state->chip.can_sleep = false;
state->ctrl = devm_pinctrl_register(dev, pctrldesc, state);
- if (IS_ERR(state->ctrl))
- return PTR_ERR(state->ctrl);
+ if (IS_ERR(state->ctrl)) {
+ ret = PTR_ERR(state->ctrl);
+ dev_err(state->dev, "failed to register pinctrl device, ret=%d\n",
+ ret);
+ goto err_free;
+ }
ret = gpiochip_add_data(&state->chip, state);
if (ret) {
- dev_err(state->dev, "can't add gpio chip\n");
- return ret;
+ dev_err(state->dev, "can't add gpio chip, ret=%d\n", ret);
+ goto err_free;
}
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;
+ dev_err(dev, "failed to add pin range\n, ret=%d\n", ret);
+ gpiochip_remove(&state->chip);
+ goto err_free;
}
- return 0;
+err_free:
+ kfree(disallowed);
-err_range:
- gpiochip_remove(&state->chip);
return ret;
}
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index fff8966..b7685cb 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -415,6 +415,16 @@
{
uint32_t val;
+ /*
+ * allocate new events for this channel first
+ * before submitting the new TREs.
+ * for TO_GSI channels the event ring doorbell is rang as part of
+ * interrupt handling.
+ */
+ if (ctx->evtr && ctx->props.dir == GSI_CHAN_DIR_FROM_GSI)
+ gsi_ring_evt_doorbell(ctx->evtr);
+ ctx->ring.wp = ctx->ring.wp_local;
+
/* write order MUST be MSB followed by LSB */
val = ((ctx->ring.wp_local >> 32) &
GSI_EE_n_GSI_CH_k_DOORBELL_1_WRITE_PTR_MSB_BMSK) <<
@@ -470,8 +480,8 @@
cntr = 0;
rp = gsi_readl(gsi_ctx->base +
GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(i, ee));
- rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
- GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(i, ee))) << 32;
+ rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
+
ctx->ring.rp = rp;
while (ctx->ring.rp_local != rp) {
++cntr;
@@ -1529,6 +1539,7 @@
static int gsi_validate_channel_props(struct gsi_chan_props *props)
{
uint64_t ra;
+ uint64_t last;
if (props->ch_id >= gsi_ctx->max_ch) {
GSIERR("ch_id %u invalid\n", props->ch_id);
@@ -1556,6 +1567,17 @@
return -GSI_STATUS_INVALID_PARAMS;
}
+ last = props->ring_base_addr + props->ring_len - props->re_size;
+
+ /* MSB should stay same within the ring */
+ if ((props->ring_base_addr & 0xFFFFFFFF00000000ULL) !=
+ (last & 0xFFFFFFFF00000000ULL)) {
+ GSIERR("MSB is not fixed on ring base 0x%llx size 0x%x\n",
+ props->ring_base_addr,
+ props->ring_len);
+ return -GSI_STATUS_INVALID_PARAMS;
+ }
+
if (props->prot == GSI_CHAN_PROT_GPI &&
!props->ring_base_vaddr) {
GSIERR("protocol %u requires ring base VA\n", props->prot);
@@ -2128,29 +2150,22 @@
uint16_t *num_free_re)
{
uint16_t start;
- uint16_t start_hw;
uint16_t end;
uint64_t rp;
- uint64_t rp_hw;
int ee = gsi_ctx->per.ee;
uint16_t used;
- uint16_t used_hw;
-
- rp_hw = gsi_readl(gsi_ctx->base +
- GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
- rp_hw |= ((uint64_t)gsi_readl(gsi_ctx->base +
- GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(ctx->props.ch_id, ee)))
- << 32;
if (!ctx->evtr) {
- rp = rp_hw;
+ rp = gsi_readl(gsi_ctx->base +
+ GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
+ rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
+
ctx->ring.rp = rp;
} else {
rp = ctx->ring.rp_local;
}
start = gsi_find_idx_from_addr(&ctx->ring, rp);
- start_hw = gsi_find_idx_from_addr(&ctx->ring, rp_hw);
end = gsi_find_idx_from_addr(&ctx->ring, ctx->ring.wp_local);
if (end >= start)
@@ -2158,13 +2173,7 @@
else
used = ctx->ring.max_num_elem + 1 - (start - end);
- if (end >= start_hw)
- used_hw = end - start_hw;
- else
- used_hw = ctx->ring.max_num_elem + 1 - (start_hw - end);
-
*num_free_re = ctx->ring.max_num_elem - used;
- gsi_update_ch_dp_stats(ctx, used_hw);
}
int gsi_query_channel_info(unsigned long chan_hdl,
@@ -2274,14 +2283,12 @@
rp = gsi_readl(gsi_ctx->base +
GSI_EE_n_GSI_CH_k_CNTXT_4_OFFS(ctx->props.ch_id, ee));
- rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
- GSI_EE_n_GSI_CH_k_CNTXT_5_OFFS(ctx->props.ch_id, ee))) << 32;
+ rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
ctx->ring.rp = rp;
wp = gsi_readl(gsi_ctx->base +
GSI_EE_n_GSI_CH_k_CNTXT_6_OFFS(ctx->props.ch_id, ee));
- wp |= ((uint64_t)gsi_readl(gsi_ctx->base +
- GSI_EE_n_GSI_CH_k_CNTXT_7_OFFS(ctx->props.ch_id, ee))) << 32;
+ wp |= ctx->ring.wp & 0xFFFFFFFF00000000;
ctx->ring.wp = wp;
if (ctx->props.dir == GSI_CHAN_DIR_FROM_GSI)
@@ -2353,6 +2360,8 @@
tre.re_type = GSI_RE_XFER;
} else if (xfer[i].type == GSI_XFER_ELEM_IMME_CMD) {
tre.re_type = GSI_RE_IMMD_CMD;
+ } else if (xfer[i].type == GSI_XFER_ELEM_NOP) {
+ tre.re_type = GSI_RE_NOP;
} else {
GSIERR("chan_hdl=%lu bad RE type=%u\n", chan_hdl,
xfer[i].type);
@@ -2420,6 +2429,9 @@
return -GSI_STATUS_UNSUPPORTED_OP;
}
+ if (ctx->ring.wp == ctx->ring.wp_local)
+ return GSI_STATUS_SUCCESS;
+
gsi_ring_chan_doorbell(ctx);
return GSI_STATUS_SUCCESS;
@@ -2457,19 +2469,22 @@
}
spin_lock_irqsave(&ctx->evtr->ring.slock, flags);
- rp = gsi_readl(gsi_ctx->base +
- GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(ctx->evtr->id, ee));
- rp |= ((uint64_t)gsi_readl(gsi_ctx->base +
- GSI_EE_n_EV_CH_k_CNTXT_5_OFFS(ctx->evtr->id, ee))) << 32;
- ctx->evtr->ring.rp = rp;
- if (rp == ctx->evtr->ring.rp_local) {
+ if (ctx->evtr->ring.rp == ctx->evtr->ring.rp_local) {
+ /* update rp to see of we have anything new to process */
+ rp = gsi_readl(gsi_ctx->base +
+ GSI_EE_n_EV_CH_k_CNTXT_4_OFFS(ctx->evtr->id, ee));
+ rp |= ctx->ring.rp & 0xFFFFFFFF00000000;
+
+ ctx->evtr->ring.rp = rp;
+ }
+
+ if (ctx->evtr->ring.rp == ctx->evtr->ring.rp_local) {
spin_unlock_irqrestore(&ctx->evtr->ring.slock, flags);
ctx->stats.poll_empty++;
return GSI_STATUS_POLL_EMPTY;
}
gsi_process_evt_re(ctx->evtr, notify, false);
- gsi_ring_evt_doorbell(ctx->evtr);
spin_unlock_irqrestore(&ctx->evtr->ring.slock, flags);
ctx->stats.poll_ok++;
diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h
index f53a4bd..32fb178 100644
--- a/drivers/platform/msm/gsi/gsi.h
+++ b/drivers/platform/msm/gsi/gsi.h
@@ -209,6 +209,7 @@
enum gsi_re_type {
GSI_RE_XFER = 0x2,
GSI_RE_IMMD_CMD = 0x3,
+ GSI_RE_NOP = 0x4,
};
struct __packed gsi_tre {
diff --git a/drivers/platform/msm/gsi/gsi_dbg.c b/drivers/platform/msm/gsi/gsi_dbg.c
index 717c8917..b1d1dfa 100644
--- a/drivers/platform/msm/gsi/gsi_dbg.c
+++ b/drivers/platform/msm/gsi/gsi_dbg.c
@@ -490,11 +490,6 @@
goto error;
}
- if (gsi_ctx->chan[ch_id].props.prot == GSI_CHAN_PROT_GPI) {
- TERR("valid for non GPI channels only\n");
- goto error;
- }
-
if (gsi_ctx->chan[ch_id].enable_dp_stats == enable) {
TERR("ch_%d: already enabled/disabled\n", ch_id);
return -EFAULT;
@@ -631,7 +626,7 @@
else
used_hw = ctx->ring.max_num_elem + 1 - (start_hw - end_hw);
- TERR("ch %d used %d\n", ctx->props.ch_id, used_hw);
+ TDBG("ch %d used %d\n", ctx->props.ch_id, used_hw);
gsi_update_ch_dp_stats(ctx, used_hw);
}
@@ -641,7 +636,6 @@
for (ch_id = 0; ch_id < gsi_ctx->max_ch; ch_id++) {
if (gsi_ctx->chan[ch_id].allocated &&
- gsi_ctx->chan[ch_id].props.prot != GSI_CHAN_PROT_GPI &&
gsi_ctx->chan[ch_id].enable_dp_stats)
gsi_dbg_update_ch_dp_stats(&gsi_ctx->chan[ch_id]);
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 20b73d8..ca63518 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2245,7 +2245,8 @@
reg_write.pipeline_clear_options =
IPAHAL_HPS_CLEAR;
reg_write.offset =
- ipahal_get_reg_ofst(IPA_ENDP_STATUS_n);
+ ipahal_get_reg_n_ofst(IPA_ENDP_STATUS_n,
+ ep_idx);
ipahal_get_status_ep_valmask(
ipa3_get_ep_mapping(IPA_CLIENT_APPS_LAN_CONS),
&valmask);
@@ -2845,6 +2846,13 @@
}
}
+ /* allocate the common PROD event ring */
+ if (ipa3_alloc_common_event_ring()) {
+ IPAERR("ipa3_alloc_common_event_ring failed.\n");
+ result = -EPERM;
+ goto fail_ch20_wa;
+ }
+
/* CMD OUT (AP->IPA) */
memset(&sys_in, 0, sizeof(struct ipa_sys_connect_params));
sys_in.client = IPA_CLIENT_APPS_CMD_PROD;
@@ -4239,6 +4247,52 @@
return 0;
}
+static int ipa3_alloc_pkt_init(void)
+{
+ struct ipa_mem_buffer mem;
+ struct ipahal_imm_cmd_pyld *cmd_pyld;
+ struct ipahal_imm_cmd_ip_packet_init cmd = {0};
+ int i;
+
+ cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
+ &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct IMM cmd\n");
+ return -ENOMEM;
+ }
+
+ mem.size = cmd_pyld->len * ipa3_ctx->ipa_num_pipes;
+ mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
+ &mem.phys_base, GFP_KERNEL);
+ if (!mem.base) {
+ IPAERR("failed to alloc DMA buff of size %d\n", mem.size);
+ ipahal_destroy_imm_cmd(cmd_pyld);
+ return -ENOMEM;
+ }
+ ipahal_destroy_imm_cmd(cmd_pyld);
+
+ memset(mem.base, 0, mem.size);
+ for (i = 0; i < ipa3_ctx->ipa_num_pipes; i++) {
+ cmd.destination_pipe_index = i;
+ cmd_pyld = ipahal_construct_imm_cmd(IPA_IMM_CMD_IP_PACKET_INIT,
+ &cmd, false);
+ if (!cmd_pyld) {
+ IPAERR("failed to construct IMM cmd\n");
+ dma_free_coherent(ipa3_ctx->pdev,
+ mem.size,
+ mem.base,
+ mem.phys_base);
+ return -ENOMEM;
+ }
+ memcpy(mem.base + i * cmd_pyld->len, cmd_pyld->data,
+ cmd_pyld->len);
+ ipa3_ctx->pkt_init_imm[i] = mem.phys_base + i * cmd_pyld->len;
+ ipahal_destroy_imm_cmd(cmd_pyld);
+ }
+
+ return 0;
+}
+
/**
* ipa3_pre_init() - Initialize the IPA Driver.
* This part contains all initialization which doesn't require IPA HW, such
@@ -4648,6 +4702,13 @@
goto fail_create_apps_resource;
}
+ result = ipa3_alloc_pkt_init();
+ if (result) {
+ IPAERR("Failed to alloc pkt_init payload\n");
+ result = -ENODEV;
+ goto fail_create_apps_resource;
+ }
+
if (ipa3_ctx->ipa_hw_type >= IPA_HW_v3_5)
ipa3_enable_dcd();
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 9bb3e0e..343cc14 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -69,6 +69,9 @@
#define IPA_GSI_CH_20_WA_VIRT_CHAN 29
#define IPA_DEFAULT_SYS_YELLOW_WM 32
+#define IPA_REPL_XFER_THRESH 10
+
+#define IPA_TX_SEND_COMPL_NOP_DELAY_NS (2 * 1000 * 1000)
/*
* The transport descriptor size was changed to GSI_CHAN_RE_SIZE_16B, but
@@ -183,106 +186,64 @@
{
struct ipa3_tx_pkt_wrapper *tx_pkt;
struct ipa3_sys_context *sys;
+ struct ipa3_tx_pkt_wrapper *this_pkt;
tx_pkt = container_of(work, struct ipa3_tx_pkt_wrapper, work);
sys = tx_pkt->sys;
-
+ spin_lock_bh(&sys->spinlock);
+ this_pkt = list_first_entry(&sys->head_desc_list,
+ struct ipa3_tx_pkt_wrapper, link);
+ while (tx_pkt != this_pkt) {
+ spin_unlock_bh(&sys->spinlock);
+ ipa3_wq_write_done_common(sys, this_pkt);
+ spin_lock_bh(&sys->spinlock);
+ this_pkt = list_first_entry(&sys->head_desc_list,
+ struct ipa3_tx_pkt_wrapper, link);
+ }
+ spin_unlock_bh(&sys->spinlock);
ipa3_wq_write_done_common(sys, tx_pkt);
}
-/**
- * ipa3_send_one() - Send a single descriptor
- * @sys: system pipe context
- * @desc: descriptor to send
- * @in_atomic: whether caller is in atomic context
- *
- * - Allocate tx_packet wrapper
- * - transfer data to the IPA
- * - after the transfer was done the user will be notified via provided
- * callback
- *
- * Return codes: 0: success, -EFAULT: failure
- */
-int ipa3_send_one(struct ipa3_sys_context *sys, struct ipa3_desc *desc,
- bool in_atomic)
+
+static void ipa3_send_nop_desc(struct work_struct *work)
{
+ struct ipa3_sys_context *sys = container_of(work,
+ struct ipa3_sys_context, work);
+ struct gsi_xfer_elem nop_xfer;
struct ipa3_tx_pkt_wrapper *tx_pkt;
- struct gsi_xfer_elem gsi_xfer;
- int result;
- dma_addr_t dma_address;
- u32 mem_flag = GFP_ATOMIC;
- if (unlikely(!in_atomic))
- mem_flag = GFP_KERNEL;
-
- tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache, mem_flag);
+ IPADBG_LOW("gsi send NOP for ch: %lu\n", sys->ep->gsi_chan_hdl);
+ tx_pkt = kmem_cache_zalloc(ipa3_ctx->tx_pkt_wrapper_cache, GFP_KERNEL);
if (!tx_pkt) {
IPAERR("failed to alloc tx wrapper\n");
- goto fail_mem_alloc;
- }
-
- if (!desc->dma_address_valid) {
- dma_address = dma_map_single(ipa3_ctx->pdev, desc->pyld,
- desc->len, DMA_TO_DEVICE);
- } else {
- dma_address = desc->dma_address;
- tx_pkt->no_unmap_dma = true;
- }
- if (!dma_address) {
- IPAERR("failed to DMA wrap\n");
- goto fail_dma_map;
+ queue_work(sys->wq, &sys->work);
+ return;
}
INIT_LIST_HEAD(&tx_pkt->link);
- tx_pkt->type = desc->type;
- tx_pkt->cnt = 1; /* only 1 desc in this "set" */
-
- tx_pkt->mem.phys_base = dma_address;
- tx_pkt->mem.base = desc->pyld;
- tx_pkt->mem.size = desc->len;
- tx_pkt->sys = sys;
- tx_pkt->callback = desc->callback;
- tx_pkt->user1 = desc->user1;
- tx_pkt->user2 = desc->user2;
-
- memset(&gsi_xfer, 0, sizeof(gsi_xfer));
- gsi_xfer.addr = dma_address;
- gsi_xfer.flags |= GSI_XFER_FLAG_EOT;
- gsi_xfer.xfer_user_data = tx_pkt;
- if (desc->type == IPA_IMM_CMD_DESC) {
- gsi_xfer.len = desc->opcode;
- gsi_xfer.type = GSI_XFER_ELEM_IMME_CMD;
- } else {
- gsi_xfer.len = desc->len;
- gsi_xfer.type = GSI_XFER_ELEM_DATA;
- }
-
+ tx_pkt->cnt = 1;
INIT_WORK(&tx_pkt->work, ipa3_wq_write_done);
-
+ tx_pkt->no_unmap_dma = true;
+ tx_pkt->sys = sys;
spin_lock_bh(&sys->spinlock);
list_add_tail(&tx_pkt->link, &sys->head_desc_list);
+ spin_unlock_bh(&sys->spinlock);
- result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
- &gsi_xfer, true);
- if (result != GSI_STATUS_SUCCESS) {
- IPAERR("GSI xfer failed.\n");
- goto fail_transport_send;
+ memset(&nop_xfer, 0, sizeof(nop_xfer));
+ nop_xfer.type = GSI_XFER_ELEM_NOP;
+ nop_xfer.flags = GSI_XFER_FLAG_EOT;
+ nop_xfer.xfer_user_data = tx_pkt;
+ if (gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1, &nop_xfer, true)) {
+ IPAERR("gsi_queue_xfer for ch:%lu failed\n",
+ sys->ep->gsi_chan_hdl);
+ queue_work(sys->wq, &sys->work);
+ return;
}
+ sys->len_pending_xfer = 0;
- spin_unlock_bh(&sys->spinlock);
-
- return 0;
-
-fail_transport_send:
- list_del(&tx_pkt->link);
- spin_unlock_bh(&sys->spinlock);
- dma_unmap_single(ipa3_ctx->pdev, dma_address, desc->len, DMA_TO_DEVICE);
-fail_dma_map:
- kmem_cache_free(ipa3_ctx->tx_pkt_wrapper_cache, tx_pkt);
-fail_mem_alloc:
- return -EFAULT;
}
+
/**
* ipa3_send() - Send multiple descriptors in one HW transaction
* @sys: system pipe context
@@ -437,19 +398,21 @@
}
if (i == (num_desc - 1)) {
- gsi_xfer_elem_array[i].flags |=
- GSI_XFER_FLAG_EOT;
- if (sys->ep->client == IPA_CLIENT_APPS_WAN_PROD
- && sys->policy == IPA_POLICY_INTR_MODE)
+ if (!sys->use_comm_evt_ring) {
+ gsi_xfer_elem_array[i].flags |=
+ GSI_XFER_FLAG_EOT;
gsi_xfer_elem_array[i].flags |=
GSI_XFER_FLAG_BEI;
+ }
gsi_xfer_elem_array[i].xfer_user_data =
tx_pkt_first;
- } else
- gsi_xfer_elem_array[i].flags |=
- GSI_XFER_FLAG_CHAIN;
+ } else {
+ gsi_xfer_elem_array[i].flags |=
+ GSI_XFER_FLAG_CHAIN;
+ }
}
+ IPADBG_LOW("ch:%lu queue xfer\n", sys->ep->gsi_chan_hdl);
result = gsi_queue_xfer(sys->ep->gsi_chan_hdl, num_desc,
gsi_xfer_elem_array, true);
if (result != GSI_STATUS_SUCCESS) {
@@ -459,6 +422,16 @@
kfree(gsi_xfer_elem_array);
spin_unlock_bh(&sys->spinlock);
+
+ /* set the timer for sending the NOP descriptor */
+ if (sys->use_comm_evt_ring && !hrtimer_active(&sys->db_timer)) {
+ ktime_t time = ktime_set(0, IPA_TX_SEND_COMPL_NOP_DELAY_NS);
+
+ IPADBG_LOW("scheduling timer for ch %lu\n",
+ sys->ep->gsi_chan_hdl);
+ hrtimer_start(&sys->db_timer, time, HRTIMER_MODE_REL);
+ }
+
return 0;
failure:
@@ -491,6 +464,25 @@
}
/**
+ * ipa3_send_one() - Send a single descriptor
+ * @sys: system pipe context
+ * @desc: descriptor to send
+ * @in_atomic: whether caller is in atomic context
+ *
+ * - Allocate tx_packet wrapper
+ * - transfer data to the IPA
+ * - after the transfer was done the SPS will
+ * notify the sending user via ipa_sps_irq_comp_tx()
+ *
+ * Return codes: 0: success, -EFAULT: failure
+ */
+int ipa3_send_one(struct ipa3_sys_context *sys, struct ipa3_desc *desc,
+ bool in_atomic)
+{
+ return ipa3_send(sys, 1, desc, in_atomic);
+}
+
+/**
* ipa3_transport_irq_cmd_ack - callback function which will be called by
* the transport driver after an immediate command is complete.
* @user1: pointer to the descriptor of the transfer
@@ -771,15 +763,14 @@
IPA_ACTIVE_CLIENTS_INC_SIMPLE();
do {
cnt = ipa3_handle_rx_core(sys, true, true);
- if (cnt == 0) {
+ if (cnt == 0)
inactive_cycles++;
- trace_idle_sleep_enter3(sys->ep->client);
- usleep_range(POLLING_MIN_SLEEP_RX,
- POLLING_MAX_SLEEP_RX);
- trace_idle_sleep_exit3(sys->ep->client);
- } else {
+ else
inactive_cycles = 0;
- }
+
+ trace_idle_sleep_enter3(sys->ep->client);
+ usleep_range(POLLING_MIN_SLEEP_RX, POLLING_MAX_SLEEP_RX);
+ trace_idle_sleep_exit3(sys->ep->client);
} while (inactive_cycles <= POLLING_INACTIVITY_RX);
trace_poll_to_intr3(sys->ep->client);
@@ -808,6 +799,15 @@
ipa3_handle_rx(sys);
}
+enum hrtimer_restart ipa3_ring_doorbell_timer_fn(struct hrtimer *param)
+{
+ struct ipa3_sys_context *sys = container_of(param,
+ struct ipa3_sys_context, db_timer);
+
+ queue_work(sys->wq, &sys->work);
+ return HRTIMER_NORESTART;
+}
+
/**
* ipa3_setup_sys_pipe() - Setup an IPA GPI pipe and perform
* IPA EP configuration
@@ -889,6 +889,9 @@
INIT_LIST_HEAD(&ep->sys->head_desc_list);
INIT_LIST_HEAD(&ep->sys->rcycl_list);
spin_lock_init(&ep->sys->spinlock);
+ hrtimer_init(&ep->sys->db_timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ ep->sys->db_timer.function = ipa3_ring_doorbell_timer_fn;
} else {
memset(ep->sys, 0, offsetof(struct ipa3_sys_context, ep));
}
@@ -1071,7 +1074,10 @@
}
/* free event ring only when it is present */
- if (ep->gsi_evt_ring_hdl != ~0) {
+ if (ep->sys->use_comm_evt_ring) {
+ ipa3_ctx->gsi_evt_comm_ring_rem +=
+ ep->gsi_mem_info.chan_ring_len;
+ } else if (ep->gsi_evt_ring_hdl != ~0) {
result = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl);
if (result != GSI_STATUS_SUCCESS) {
IPAERR("Failed to reset evt ring: %d.\n",
@@ -1145,7 +1151,7 @@
dev_kfree_skb_any(skb);
}
-static void ipa3_tx_cmd_comp(void *user1, int user2)
+void ipa3_tx_cmd_comp(void *user1, int user2)
{
ipahal_destroy_imm_cmd(user1);
}
@@ -1180,7 +1186,6 @@
struct ipa3_desc *desc;
struct ipa3_desc _desc[3];
int dst_ep_idx;
- struct ipahal_imm_cmd_ip_packet_init cmd;
struct ipahal_imm_cmd_pyld *cmd_pyld = NULL;
struct ipa3_sys_context *sys;
int src_ep_idx;
@@ -1267,54 +1272,58 @@
if (dst_ep_idx != -1) {
/* SW data path */
- cmd.destination_pipe_index = dst_ep_idx;
- cmd_pyld = ipahal_construct_imm_cmd(
- IPA_IMM_CMD_IP_PACKET_INIT, &cmd, true);
- if (unlikely(!cmd_pyld)) {
- IPAERR("failed to construct ip_packet_init imm cmd\n");
- goto fail_mem;
+ data_idx = 0;
+ if (sys->policy == IPA_POLICY_NOINTR_MODE) {
+ /*
+ * For non-interrupt mode channel (where there is no
+ * event ring) TAG STATUS are used for completion
+ * notification. IPA will generate a status packet with
+ * tag info as a result of the TAG STATUS command.
+ */
+ desc[data_idx].opcode =
+ ipahal_imm_cmd_get_opcode(
+ IPA_IMM_CMD_IP_PACKET_TAG_STATUS);
+ desc[data_idx].type = IPA_IMM_CMD_DESC;
+ desc[data_idx].callback = ipa3_tag_destroy_imm;
+ data_idx++;
}
-
- /* the tag field will be populated in ipa3_send() function */
- desc[0].opcode = ipahal_imm_cmd_get_opcode(
- IPA_IMM_CMD_IP_PACKET_TAG_STATUS);
- desc[0].type = IPA_IMM_CMD_DESC;
- desc[0].callback = ipa3_tag_destroy_imm;
- desc[1].opcode =
+ desc[data_idx].opcode =
ipahal_imm_cmd_get_opcode(IPA_IMM_CMD_IP_PACKET_INIT);
- desc[1].pyld = cmd_pyld->data;
- desc[1].len = cmd_pyld->len;
- desc[1].type = IPA_IMM_CMD_DESC;
- desc[1].callback = ipa3_tx_cmd_comp;
- desc[1].user1 = cmd_pyld;
- desc[2].pyld = skb->data;
- desc[2].len = skb_headlen(skb);
- desc[2].type = IPA_DATA_DESC_SKB;
- desc[2].callback = ipa3_tx_comp_usr_notify_release;
- desc[2].user1 = skb;
- desc[2].user2 = (meta && meta->pkt_init_dst_ep_valid &&
+ desc[data_idx].dma_address_valid = true;
+ desc[data_idx].dma_address = ipa3_ctx->pkt_init_imm[dst_ep_idx];
+ desc[data_idx].type = IPA_IMM_CMD_DESC;
+ desc[data_idx].callback = NULL;
+ data_idx++;
+ desc[data_idx].pyld = skb->data;
+ desc[data_idx].len = skb_headlen(skb);
+ desc[data_idx].type = IPA_DATA_DESC_SKB;
+ desc[data_idx].callback = ipa3_tx_comp_usr_notify_release;
+ desc[data_idx].user1 = skb;
+ desc[data_idx].user2 = (meta && meta->pkt_init_dst_ep_valid &&
meta->pkt_init_dst_ep_remote) ?
src_ep_idx :
dst_ep_idx;
if (meta && meta->dma_address_valid) {
- desc[2].dma_address_valid = true;
- desc[2].dma_address = meta->dma_address;
+ desc[data_idx].dma_address_valid = true;
+ desc[data_idx].dma_address = meta->dma_address;
}
+ data_idx++;
for (f = 0; f < num_frags; f++) {
- desc[3+f].frag = &skb_shinfo(skb)->frags[f];
- desc[3+f].type = IPA_DATA_DESC_SKB_PAGED;
- desc[3+f].len = skb_frag_size(desc[3+f].frag);
+ desc[data_idx + f].frag = &skb_shinfo(skb)->frags[f];
+ desc[data_idx + f].type = IPA_DATA_DESC_SKB_PAGED;
+ desc[data_idx + f].len =
+ skb_frag_size(desc[data_idx + f].frag);
}
/* don't free skb till frag mappings are released */
if (num_frags) {
- desc[3+f-1].callback = desc[2].callback;
- desc[3+f-1].user1 = desc[2].user1;
- desc[3+f-1].user2 = desc[2].user2;
- desc[2].callback = NULL;
+ desc[data_idx + f - 1].callback = desc[2].callback;
+ desc[data_idx + f - 1].user1 = desc[2].user1;
+ desc[data_idx + f - 1].user2 = desc[2].user2;
+ desc[data_idx - 1].callback = NULL;
}
- if (ipa3_send(sys, num_frags + 3, desc, true)) {
+ if (ipa3_send(sys, num_frags + data_idx, desc, true)) {
IPAERR("fail to send skb %p num_frags %u SWP\n",
skb, num_frags);
goto fail_send;
@@ -1699,12 +1708,21 @@
gsi_xfer_elem_one.xfer_user_data = rx_pkt;
ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl,
- 1, &gsi_xfer_elem_one, true);
+ 1, &gsi_xfer_elem_one, false);
if (ret != GSI_STATUS_SUCCESS) {
IPAERR("failed to provide buffer: %d\n",
ret);
goto fail_provide_rx_buffer;
}
+
+ /*
+ * As doorbell is a costly operation, notify to GSI
+ * of new buffers if threshold is exceeded
+ */
+ if (++sys->len_pending_xfer >= IPA_REPL_XFER_THRESH) {
+ sys->len_pending_xfer = 0;
+ gsi_start_xfer(sys->ep->gsi_chan_hdl);
+ }
}
return;
@@ -1719,7 +1737,7 @@
fail_skb_alloc:
kmem_cache_free(ipa3_ctx->rx_pkt_wrapper_cache, rx_pkt);
fail_kmem_cache_alloc:
- if (rx_len_cached == 0)
+ if (rx_len_cached - sys->len_pending_xfer == 0)
queue_delayed_work(sys->wq, &sys->replenish_rx_work,
msecs_to_jiffies(1));
}
@@ -1794,12 +1812,21 @@
gsi_xfer_elem_one.xfer_user_data = rx_pkt;
ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl,
- 1, &gsi_xfer_elem_one, true);
+ 1, &gsi_xfer_elem_one, false);
if (ret != GSI_STATUS_SUCCESS) {
IPAERR("failed to provide buffer: %d\n",
ret);
goto fail_provide_rx_buffer;
}
+
+ /*
+ * As doorbell is a costly operation, notify to GSI
+ * of new buffers if threshold is exceeded
+ */
+ if (++sys->len_pending_xfer >= IPA_REPL_XFER_THRESH) {
+ sys->len_pending_xfer = 0;
+ gsi_start_xfer(sys->ep->gsi_chan_hdl);
+ }
}
return;
@@ -1815,7 +1842,7 @@
INIT_LIST_HEAD(&rx_pkt->link);
spin_unlock_bh(&sys->spinlock);
fail_kmem_cache_alloc:
- if (rx_len_cached == 0)
+ if (rx_len_cached - sys->len_pending_xfer == 0)
queue_delayed_work(sys->wq, &sys->replenish_rx_work,
msecs_to_jiffies(1));
}
@@ -1848,12 +1875,22 @@
gsi_xfer_elem_one.xfer_user_data = rx_pkt;
ret = gsi_queue_xfer(sys->ep->gsi_chan_hdl, 1,
- &gsi_xfer_elem_one, true);
+ &gsi_xfer_elem_one, false);
if (ret != GSI_STATUS_SUCCESS) {
IPAERR("failed to provide buffer: %d\n",
ret);
break;
}
+
+ /*
+ * As doorbell is a costly operation, notify to GSI
+ * of new buffers if threshold is exceeded
+ */
+ if (++sys->len_pending_xfer >= IPA_REPL_XFER_THRESH) {
+ sys->len_pending_xfer = 0;
+ gsi_start_xfer(sys->ep->gsi_chan_hdl);
+ }
+
rx_len_cached = ++sys->len;
curr = (curr + 1) % sys->repl.capacity;
/* ensure write is done before setting head index */
@@ -1863,7 +1900,8 @@
queue_work(sys->repl_wq, &sys->repl_work);
- if (rx_len_cached <= IPA_DEFAULT_SYS_YELLOW_WM) {
+ if (rx_len_cached - sys->len_pending_xfer
+ <= IPA_DEFAULT_SYS_YELLOW_WM) {
if (sys->ep->client == IPA_CLIENT_APPS_WAN_CONS)
IPA_STATS_INC_CNT(ipa3_ctx->stats.wan_rx_empty);
else if (sys->ep->client == IPA_CLIENT_APPS_LAN_CONS)
@@ -2641,6 +2679,7 @@
if (in->client == IPA_CLIENT_APPS_CMD_PROD ||
in->client == IPA_CLIENT_APPS_WAN_PROD) {
sys->policy = IPA_POLICY_INTR_MODE;
+ sys->use_comm_evt_ring = false;
return 0;
}
@@ -2652,12 +2691,12 @@
if (IPA_CLIENT_IS_PROD(in->client)) {
if (sys->ep->skip_ep_cfg) {
sys->policy = IPA_POLICY_INTR_POLL_MODE;
+ sys->use_comm_evt_ring = true;
atomic_set(&sys->curr_polling_state, 0);
} else {
- sys->policy = IPA_POLICY_NOINTR_MODE;
- sys->ep->status.status_en = true;
- sys->ep->status.status_ep = ipa3_get_ep_mapping(
- IPA_CLIENT_APPS_LAN_CONS);
+ sys->policy = IPA_POLICY_INTR_MODE;
+ sys->use_comm_evt_ring = true;
+ INIT_WORK(&sys->work, ipa3_send_nop_desc);
}
} else {
if (in->client == IPA_CLIENT_APPS_LAN_CONS ||
@@ -3325,6 +3364,46 @@
}
}
+int ipa3_alloc_common_event_ring(void)
+{
+ struct gsi_evt_ring_props gsi_evt_ring_props;
+ dma_addr_t evt_dma_addr;
+ int result;
+
+ memset(&gsi_evt_ring_props, 0, sizeof(gsi_evt_ring_props));
+ gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV;
+ gsi_evt_ring_props.intr = GSI_INTR_IRQ;
+ gsi_evt_ring_props.re_size = GSI_EVT_RING_RE_SIZE_16B;
+
+ gsi_evt_ring_props.ring_len = IPA_COMMON_EVENT_RING_SIZE;
+
+ gsi_evt_ring_props.ring_base_vaddr =
+ dma_alloc_coherent(ipa3_ctx->pdev,
+ gsi_evt_ring_props.ring_len, &evt_dma_addr, GFP_KERNEL);
+ if (!gsi_evt_ring_props.ring_base_vaddr) {
+ IPAERR("fail to dma alloc %u bytes\n",
+ gsi_evt_ring_props.ring_len);
+ return -ENOMEM;
+ }
+ gsi_evt_ring_props.ring_base_addr = evt_dma_addr;
+ gsi_evt_ring_props.int_modt = 0;
+ gsi_evt_ring_props.int_modc = 1; /* moderation comes from channel*/
+ gsi_evt_ring_props.rp_update_addr = 0;
+ gsi_evt_ring_props.exclusive = false;
+ gsi_evt_ring_props.err_cb = ipa_gsi_evt_ring_err_cb;
+ gsi_evt_ring_props.user_data = NULL;
+
+ result = gsi_alloc_evt_ring(&gsi_evt_ring_props,
+ ipa3_ctx->gsi_dev_hdl, &ipa3_ctx->gsi_evt_comm_hdl);
+ if (result) {
+ IPAERR("gsi_alloc_evt_ring failed %d\n", result);
+ return result;
+ }
+ ipa3_ctx->gsi_evt_comm_ring_rem = IPA_COMMON_EVENT_RING_SIZE;
+
+ return 0;
+}
+
static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
struct ipa3_ep_context *ep)
{
@@ -3344,11 +3423,18 @@
evt_dma_addr = 0;
ep->gsi_evt_ring_hdl = ~0;
memset(&gsi_evt_ring_props, 0, sizeof(gsi_evt_ring_props));
- /*
- * allocate event ring for all interrupt-policy
- * pipes and IPA consumers pipes
- */
- if (ep->sys->policy != IPA_POLICY_NOINTR_MODE ||
+ if (ep->sys->use_comm_evt_ring) {
+ if (ipa3_ctx->gsi_evt_comm_ring_rem < 2 * in->desc_fifo_sz) {
+ IPAERR("not enough space in common event ring\n");
+ IPAERR("available: %d needed: %d\n",
+ ipa3_ctx->gsi_evt_comm_ring_rem,
+ 2 * in->desc_fifo_sz);
+ WARN_ON(1);
+ return -EFAULT;
+ }
+ ipa3_ctx->gsi_evt_comm_ring_rem -= (2 * in->desc_fifo_sz);
+ ep->gsi_evt_ring_hdl = ipa3_ctx->gsi_evt_comm_hdl;
+ } else if (ep->sys->policy != IPA_POLICY_NOINTR_MODE ||
IPA_CLIENT_IS_CONS(ep->client)) {
gsi_evt_ring_props.intf = GSI_EVT_CHTYPE_GPI_EV;
gsi_evt_ring_props.intr = GSI_INTR_IRQ;
@@ -3375,10 +3461,7 @@
gsi_evt_ring_props.ring_base_vaddr;
gsi_evt_ring_props.int_modt = IPA_GSI_EVT_RING_INT_MODT;
- if (ep->client == IPA_CLIENT_APPS_WAN_PROD)
- gsi_evt_ring_props.int_modc = 248;
- else
- gsi_evt_ring_props.int_modc = 1;
+ gsi_evt_ring_props.int_modc = 1;
IPADBG("client=%d moderation threshold cycles=%u cnt=%u\n",
ep->client,
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 1a0d3ad..7419a64 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -45,6 +45,7 @@
#define IPA3_MAX_NUM_PIPES 31
#define IPA_SYS_DESC_FIFO_SZ 0x800
#define IPA_SYS_TX_DATA_DESC_FIFO_SZ 0x1000
+#define IPA_COMMON_EVENT_RING_SIZE 0x7C00
#define IPA_LAN_RX_HEADER_LENGTH (2)
#define IPA_QMAP_HEADER_LENGTH (4)
#define IPA_DL_CHECKSUM_LENGTH (8)
@@ -591,9 +592,11 @@
*/
struct ipa3_sys_context {
u32 len;
+ u32 len_pending_xfer;
atomic_t curr_polling_state;
struct delayed_work switch_to_intr_work;
enum ipa3_sys_pipe_policy policy;
+ bool use_comm_evt_ring;
int (*pyld_hdlr)(struct sk_buff *skb, struct ipa3_sys_context *sys);
struct sk_buff * (*get_skb)(unsigned int len, gfp_t flags);
void (*free_skb)(struct sk_buff *skb);
@@ -616,6 +619,7 @@
struct list_head head_desc_list;
struct list_head rcycl_list;
spinlock_t spinlock;
+ struct hrtimer db_timer;
struct workqueue_struct *wq;
struct workqueue_struct *repl_wq;
struct ipa3_status_stats *status_stat;
@@ -702,6 +706,7 @@
* @user1: cookie1 for above callback
* @user2: cookie2 for above callback
* @xfer_done: completion object for sync completion
+ * @skip_db_ring: specifies whether GSI doorbell should not be rang
*/
struct ipa3_desc {
enum ipa3_desc_type type;
@@ -715,6 +720,7 @@
void *user1;
int user2;
struct completion xfer_done;
+ bool skip_db_ring;
};
/**
@@ -1133,6 +1139,8 @@
struct workqueue_struct *transport_power_mgmt_wq;
bool tag_process_before_gating;
struct ipa3_transport_pm transport_pm;
+ unsigned long gsi_evt_comm_hdl;
+ u32 gsi_evt_comm_ring_rem;
u32 clnt_hdl_cmd;
u32 clnt_hdl_data_in;
u32 clnt_hdl_data_out;
@@ -1165,6 +1173,7 @@
u32 curr_ipa_clk_rate;
bool q6_proxy_clk_vote_valid;
u32 ipa_num_pipes;
+ dma_addr_t pkt_init_imm[IPA3_MAX_NUM_PIPES];
struct ipa3_wlan_comm_memb wc_memb;
@@ -1971,4 +1980,5 @@
struct device *ipa3_get_pdev(void);
void ipa3_enable_dcd(void);
void ipa3_disable_prefetch(enum ipa_client_type client);
+int ipa3_alloc_common_event_ring(void);
#endif /* _IPA3_I_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
index c69a3d0..799246b 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
@@ -1207,6 +1207,8 @@
IPADBG("Skipping endpoint configuration.\n");
}
+ ipa3_enable_data_path(ipa_ep_idx);
+
out->clnt_hdl = ipa_ep_idx;
if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client))
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/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c
index a74d8ca..d16e3e8 100644
--- a/drivers/power/supply/power_supply_core.c
+++ b/drivers/power/supply/power_supply_core.c
@@ -665,7 +665,7 @@
.set_cur_state = ps_set_cur_charge_cntl_limit,
};
-static int psy_register_cooler(struct power_supply *psy)
+static int psy_register_cooler(struct device *dev, struct power_supply *psy)
{
int i;
@@ -673,7 +673,13 @@
for (i = 0; i < psy->desc->num_properties; i++) {
if (psy->desc->properties[i] ==
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT) {
- psy->tcd = thermal_cooling_device_register(
+ if (dev)
+ psy->tcd = thermal_of_cooling_device_register(
+ dev_of_node(dev),
+ (char *)psy->desc->name,
+ psy, &psy_tcd_ops);
+ else
+ psy->tcd = thermal_cooling_device_register(
(char *)psy->desc->name,
psy, &psy_tcd_ops);
return PTR_ERR_OR_ZERO(psy->tcd);
@@ -698,7 +704,7 @@
{
}
-static int psy_register_cooler(struct power_supply *psy)
+static int psy_register_cooler(struct device *dev, struct power_supply *psy)
{
return 0;
}
@@ -770,7 +776,7 @@
if (rc)
goto register_thermal_failed;
- rc = psy_register_cooler(psy);
+ rc = psy_register_cooler(parent, psy);
if (rc)
goto register_cooler_failed;
diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c
index cf8f000..dbe2a08 100644
--- a/drivers/regulator/qpnp-labibb-regulator.c
+++ b/drivers/regulator/qpnp-labibb-regulator.c
@@ -19,16 +19,19 @@
#include <linux/kernel.h>
#include <linux/regmap.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/spmi.h>
#include <linux/platform_device.h>
#include <linux/string.h>
+#include <linux/workqueue.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/qpnp/qpnp-revid.h>
+#include <linux/regulator/qpnp-labibb-regulator.h>
#define QPNP_LABIBB_REGULATOR_DRIVER_NAME "qcom,qpnp-labibb-regulator"
@@ -594,6 +597,7 @@
const struct lab_ver_ops *lab_ver_ops;
struct mutex bus_mutex;
enum qpnp_labibb_mode mode;
+ struct work_struct lab_vreg_ok_work;
bool standalone;
bool ttw_en;
bool in_ttw_mode;
@@ -603,10 +607,13 @@
bool ttw_force_lab_on;
bool skip_2nd_swire_cmd;
bool pfm_enable;
+ bool notify_lab_vreg_ok_sts;
u32 swire_2nd_cmd_delay;
u32 swire_ibb_ps_enable_delay;
};
+static RAW_NOTIFIER_HEAD(labibb_notifier);
+
struct ibb_ver_ops {
int (*set_default_voltage)(struct qpnp_labibb *labibb,
bool use_default);
@@ -2124,6 +2131,36 @@
return rc;
}
+static void qpnp_lab_vreg_notifier_work(struct work_struct *work)
+{
+ int rc = 0;
+ u16 retries = 1000, dly = 5000;
+ u8 val;
+ struct qpnp_labibb *labibb = container_of(work, struct qpnp_labibb,
+ lab_vreg_ok_work);
+
+ while (retries--) {
+ rc = qpnp_labibb_read(labibb, labibb->lab_base +
+ REG_LAB_STATUS1, &val, 1);
+ if (rc < 0) {
+ pr_err("read register %x failed rc = %d\n",
+ REG_LAB_STATUS1, rc);
+ return;
+ }
+
+ if (val & LAB_STATUS1_VREG_OK) {
+ raw_notifier_call_chain(&labibb_notifier,
+ LAB_VREG_OK, NULL);
+ break;
+ }
+
+ usleep_range(dly, dly + 100);
+ }
+
+ if (!retries)
+ pr_err("LAB_VREG_OK not set, failed to notify\n");
+}
+
static int qpnp_labibb_regulator_enable(struct qpnp_labibb *labibb)
{
int rc;
@@ -2326,6 +2363,9 @@
labibb->lab_vreg.vreg_enabled = 1;
}
+ if (labibb->notify_lab_vreg_ok_sts)
+ schedule_work(&labibb->lab_vreg_ok_work);
+
return 0;
}
@@ -2578,6 +2618,9 @@
return rc;
}
+ labibb->notify_lab_vreg_ok_sts = of_property_read_bool(of_node,
+ "qcom,notify-lab-vreg-ok-sts");
+
rc = of_property_read_u32(of_node, "qcom,qpnp-lab-soft-start",
&(labibb->lab_vreg.soft_start));
if (!rc) {
@@ -3817,6 +3860,8 @@
goto fail_registration;
}
}
+
+ INIT_WORK(&labibb->lab_vreg_ok_work, qpnp_lab_vreg_notifier_work);
dev_set_drvdata(&pdev->dev, labibb);
pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d swire_control=%d\n",
labibb->lab_vreg.vreg_enabled,
@@ -3834,6 +3879,18 @@
return rc;
}
+int qpnp_labibb_notifier_register(struct notifier_block *nb)
+{
+ return raw_notifier_chain_register(&labibb_notifier, nb);
+}
+EXPORT_SYMBOL(qpnp_labibb_notifier_register);
+
+int qpnp_labibb_notifier_unregister(struct notifier_block *nb)
+{
+ return raw_notifier_chain_unregister(&labibb_notifier, nb);
+}
+EXPORT_SYMBOL(qpnp_labibb_notifier_unregister);
+
static int qpnp_labibb_regulator_remove(struct platform_device *pdev)
{
struct qpnp_labibb *labibb = dev_get_drvdata(&pdev->dev);
@@ -3843,6 +3900,8 @@
regulator_unregister(labibb->lab_vreg.rdev);
if (labibb->ibb_vreg.rdev)
regulator_unregister(labibb->ibb_vreg.rdev);
+
+ cancel_work_sync(&labibb->lab_vreg_ok_work);
}
return 0;
}
diff --git a/drivers/regulator/qpnp-lcdb-regulator.c b/drivers/regulator/qpnp-lcdb-regulator.c
index a08ade6..aef28db 100644
--- a/drivers/regulator/qpnp-lcdb-regulator.c
+++ b/drivers/regulator/qpnp-lcdb-regulator.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
@@ -31,6 +32,13 @@
#define INT_RT_STATUS_REG 0x10
#define VREG_OK_RT_STS_BIT BIT(0)
+#define SC_ERROR_RT_STS_BIT BIT(1)
+
+#define LCDB_STS3_REG 0x0A
+#define LDO_VREG_OK_BIT BIT(7)
+
+#define LCDB_STS4_REG 0x0B
+#define NCP_VREG_OK_BIT BIT(7)
#define LCDB_AUTO_TOUCH_WAKE_CTL_REG 0x40
#define EN_AUTO_TOUCH_WAKE_BIT BIT(7)
@@ -185,14 +193,21 @@
struct platform_device *pdev;
struct regmap *regmap;
u32 base;
+ int sc_irq;
/* TTW params */
bool ttw_enable;
bool ttw_mode_sw;
+ /* top level DT params */
+ bool force_module_reenable;
+
/* status parameters */
bool lcdb_enabled;
bool settings_saved;
+ bool lcdb_sc_disable;
+ int sc_count;
+ ktime_t sc_module_enable_time;
struct mutex lcdb_mutex;
struct mutex read_write_mutex;
@@ -569,8 +584,11 @@
int rc = 0, timeout, delay;
u8 val = 0;
- if (lcdb->lcdb_enabled)
+ if (lcdb->lcdb_enabled || lcdb->lcdb_sc_disable) {
+ pr_debug("lcdb_enabled=%d lcdb_sc_disable=%d\n",
+ lcdb->lcdb_enabled, lcdb->lcdb_sc_disable);
return 0;
+ }
if (lcdb->ttw_enable) {
rc = qpnp_lcdb_ttw_exit(lcdb);
@@ -588,6 +606,23 @@
goto fail_enable;
}
+ if (lcdb->force_module_reenable) {
+ val = 0;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to enable lcdb rc= %d\n", rc);
+ goto fail_enable;
+ }
+ val = MODULE_EN_BIT;
+ rc = qpnp_lcdb_write(lcdb, lcdb->base + LCDB_ENABLE_CTL1_REG,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to disable lcdb rc= %d\n", rc);
+ goto fail_enable;
+ }
+ }
+
/* poll for vreg_ok */
timeout = 10;
delay = lcdb->bst.soft_start_us + lcdb->ldo.soft_start_us +
@@ -656,6 +691,111 @@
return rc;
}
+#define LCDB_SC_RESET_CNT_DLY_US 1000000
+#define LCDB_SC_CNT_MAX 10
+static int qpnp_lcdb_handle_sc_event(struct qpnp_lcdb *lcdb)
+{
+ int rc = 0;
+ s64 elapsed_time_us;
+
+ mutex_lock(&lcdb->lcdb_mutex);
+ rc = qpnp_lcdb_disable(lcdb);
+ if (rc < 0) {
+ pr_err("Failed to disable lcdb rc=%d\n", rc);
+ goto unlock_mutex;
+ }
+
+ /* Check if the SC re-occurred immediately */
+ elapsed_time_us = ktime_us_delta(ktime_get(),
+ lcdb->sc_module_enable_time);
+ if (elapsed_time_us > LCDB_SC_RESET_CNT_DLY_US) {
+ lcdb->sc_count = 0;
+ } else if (lcdb->sc_count > LCDB_SC_CNT_MAX) {
+ pr_err("SC trigged %d times, disabling LCDB forever!\n",
+ lcdb->sc_count);
+ lcdb->lcdb_sc_disable = true;
+ goto unlock_mutex;
+ }
+ lcdb->sc_count++;
+ lcdb->sc_module_enable_time = ktime_get();
+
+ /* delay for SC to clear */
+ usleep_range(10000, 10100);
+
+ rc = qpnp_lcdb_enable(lcdb);
+ if (rc < 0)
+ pr_err("Failed to enable lcdb rc=%d\n", rc);
+
+unlock_mutex:
+ mutex_unlock(&lcdb->lcdb_mutex);
+ return rc;
+}
+
+static irqreturn_t qpnp_lcdb_sc_irq_handler(int irq, void *data)
+{
+ struct qpnp_lcdb *lcdb = data;
+ int rc;
+ u8 val, val2[2] = {0};
+
+ rc = qpnp_lcdb_read(lcdb, lcdb->base + INT_RT_STATUS_REG, &val, 1);
+ if (rc < 0)
+ goto irq_handled;
+
+ if (val & SC_ERROR_RT_STS_BIT) {
+ rc = qpnp_lcdb_read(lcdb,
+ lcdb->base + LCDB_MISC_CTL_REG, &val, 1);
+ if (rc < 0)
+ goto irq_handled;
+
+ if (val & EN_TOUCH_WAKE_BIT) {
+ /* blanking time */
+ usleep_range(300, 310);
+ /*
+ * The status registers need to written with any value
+ * before reading
+ */
+ rc = qpnp_lcdb_write(lcdb,
+ lcdb->base + LCDB_STS3_REG, val2, 2);
+ if (rc < 0)
+ goto irq_handled;
+
+ rc = qpnp_lcdb_read(lcdb,
+ lcdb->base + LCDB_STS3_REG, val2, 2);
+ if (rc < 0)
+ goto irq_handled;
+
+ if (!(val2[0] & LDO_VREG_OK_BIT) ||
+ !(val2[1] & NCP_VREG_OK_BIT)) {
+ rc = qpnp_lcdb_handle_sc_event(lcdb);
+ if (rc < 0) {
+ pr_err("Failed to handle SC rc=%d\n",
+ rc);
+ goto irq_handled;
+ }
+ }
+ } else {
+ /* blanking time */
+ usleep_range(2000, 2100);
+ /* Read the SC status again to confirm true SC */
+ rc = qpnp_lcdb_read(lcdb,
+ lcdb->base + INT_RT_STATUS_REG, &val, 1);
+ if (rc < 0)
+ goto irq_handled;
+
+ if (val & SC_ERROR_RT_STS_BIT) {
+ rc = qpnp_lcdb_handle_sc_event(lcdb);
+ if (rc < 0) {
+ pr_err("Failed to handle SC rc=%d\n",
+ rc);
+ goto irq_handled;
+ }
+ }
+ }
+ }
+irq_handled:
+ return IRQ_HANDLED;
+}
+
#define MIN_BST_VOLTAGE_MV 4700
#define MAX_BST_VOLTAGE_MV 6250
#define MIN_VOLTAGE_MV 4000
@@ -1534,6 +1674,18 @@
return rc;
}
+ if (lcdb->sc_irq >= 0) {
+ lcdb->sc_count = 0;
+ rc = devm_request_threaded_irq(lcdb->dev, lcdb->sc_irq,
+ NULL, qpnp_lcdb_sc_irq_handler, IRQF_ONESHOT,
+ "qpnp_lcdb_sc_irq", lcdb);
+ if (rc < 0) {
+ pr_err("Unable to request sc(%d) irq rc=%d\n",
+ lcdb->sc_irq, rc);
+ return rc;
+ }
+ }
+
if (!is_lcdb_enabled(lcdb)) {
rc = qpnp_lcdb_read(lcdb, lcdb->base +
LCDB_MODULE_RDY_REG, &val, 1);
@@ -1590,6 +1742,9 @@
}
}
+ lcdb->force_module_reenable = of_property_read_bool(node,
+ "qcom,force-module-reenable");
+
if (of_property_read_bool(node, "qcom,ttw-enable")) {
rc = qpnp_lcdb_parse_ttw(lcdb);
if (rc < 0) {
@@ -1599,6 +1754,10 @@
lcdb->ttw_enable = true;
}
+ lcdb->sc_irq = platform_get_irq_byname(lcdb->pdev, "sc-irq");
+ if (lcdb->sc_irq < 0)
+ pr_debug("sc irq is not defined\n");
+
return rc;
}
diff --git a/drivers/regulator/qpnp-oledb-regulator.c b/drivers/regulator/qpnp-oledb-regulator.c
index 8d017fb..c012f37 100644
--- a/drivers/regulator/qpnp-oledb-regulator.c
+++ b/drivers/regulator/qpnp-oledb-regulator.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/spmi.h>
@@ -24,6 +25,8 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#include <linux/regulator/qpnp-labibb-regulator.h>
+#include <linux/qpnp/qpnp-pbs.h>
#define QPNP_OLEDB_REGULATOR_DRIVER_NAME "qcom,qpnp-oledb-regulator"
#define OLEDB_VOUT_STEP_MV 100
@@ -91,6 +94,12 @@
#define OLEDB_ENABLE_NLIMIT_BIT_SHIFT 7
#define OLEDB_NLIMIT_PGM_MASK GENMASK(1, 0)
+#define OLEDB_SPARE_CTL 0xE9
+#define OLEDB_FORCE_PD_CTL_SPARE_BIT BIT(7)
+
+#define OLEDB_PD_PBS_TRIGGER_BIT BIT(0)
+
+#define OLEDB_SEC_UNLOCK_CODE 0xA5
#define OLEDB_PSM_HYS_CTRL_MIN 13
#define OLEDB_PSM_HYS_CTRL_MAX 26
@@ -150,6 +159,9 @@
struct qpnp_oledb_psm_ctl psm_ctl;
struct qpnp_oledb_pfm_ctl pfm_ctl;
struct qpnp_oledb_fast_precharge_ctl fast_prechg_ctl;
+ struct notifier_block oledb_nb;
+ struct mutex bus_lock;
+ struct device_node *pbs_dev_node;
u32 base;
u8 mod_enable;
@@ -168,6 +180,7 @@
bool ext_pin_control;
bool dynamic_ext_pinctl_config;
bool pbs_control;
+ bool force_pd_control;
};
static const u16 oledb_warmup_dly_ns[] = {6700, 13300, 26700, 53400};
@@ -184,11 +197,13 @@
int rc = 0;
struct platform_device *pdev = oledb->pdev;
+ mutex_lock(&oledb->bus_lock);
rc = regmap_bulk_read(oledb->regmap, address, val, count);
if (rc)
pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n",
address, to_spmi_device(pdev->dev.parent)->usid, rc);
+ mutex_unlock(&oledb->bus_lock);
return rc;
}
@@ -197,6 +212,7 @@
{
int rc;
+ mutex_lock(&oledb->bus_lock);
rc = regmap_update_bits(oledb->regmap, address, mask, val);
if (rc < 0)
pr_err("Failed to write address 0x%04X, rc = %d\n",
@@ -205,6 +221,31 @@
pr_debug("Wrote 0x%02X to addr 0x%04X\n",
val, address);
+ mutex_unlock(&oledb->bus_lock);
+ return rc;
+}
+
+#define OLEDB_SEC_ACCESS 0xD0
+static int qpnp_oledb_sec_masked_write(struct qpnp_oledb *oledb, u16 address,
+ u8 mask, u8 val)
+{
+ int rc = 0;
+ u8 sec_val = OLEDB_SEC_UNLOCK_CODE;
+ u16 sec_reg_addr = (address & 0xFF00) | OLEDB_SEC_ACCESS;
+
+ mutex_lock(&oledb->bus_lock);
+ rc = regmap_write(oledb->regmap, sec_reg_addr, sec_val);
+ if (rc < 0) {
+ pr_err("register %x failed rc = %d\n", sec_reg_addr, rc);
+ goto error;
+ }
+
+ rc = regmap_update_bits(oledb->regmap, address, mask, val);
+ if (rc < 0)
+ pr_err("spmi write failed: addr=%03X, rc=%d\n", address, rc);
+
+error:
+ mutex_unlock(&oledb->bus_lock);
return rc;
}
@@ -214,6 +255,7 @@
int rc = 0;
struct platform_device *pdev = oledb->pdev;
+ mutex_lock(&oledb->bus_lock);
rc = regmap_bulk_write(oledb->regmap, address, val, count);
if (rc)
pr_err("Failed to write address=0x%02x sid=0x%02x rc=%d\n",
@@ -222,7 +264,8 @@
pr_debug("Wrote 0x%02X to addr 0x%04X\n",
*val, address);
- return 0;
+ mutex_unlock(&oledb->bus_lock);
+ return rc;
}
static int qpnp_oledb_regulator_enable(struct regulator_dev *rdev)
@@ -285,6 +328,8 @@
static int qpnp_oledb_regulator_disable(struct regulator_dev *rdev)
{
int rc = 0;
+ u8 trigger_bitmap = OLEDB_PD_PBS_TRIGGER_BIT;
+ u8 val;
struct qpnp_oledb *oledb = rdev_get_drvdata(rdev);
@@ -314,6 +359,27 @@
pr_debug("Register-control mode, module disabled\n");
}
+ if (oledb->force_pd_control) {
+ rc = qpnp_oledb_read(oledb, oledb->base + OLEDB_SPARE_CTL,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to read OLEDB_SPARE_CTL rc=%d\n", rc);
+ return rc;
+ }
+
+ if (val & OLEDB_FORCE_PD_CTL_SPARE_BIT) {
+ rc = qpnp_pbs_trigger_event(oledb->pbs_dev_node,
+ trigger_bitmap);
+ if (rc < 0) {
+ pr_err("Failed to trigger the PBS sequence\n");
+ return rc;
+ }
+ pr_debug("PBS event triggered\n");
+ } else {
+ pr_debug("OLEDB_SPARE_CTL register bit not set\n");
+ }
+ }
+
oledb->mod_enable = false;
return rc;
@@ -1034,6 +1100,18 @@
oledb->pbs_control =
of_property_read_bool(of_node, "qcom,pbs-control");
+ oledb->force_pd_control =
+ of_property_read_bool(of_node, "qcom,force-pd-control");
+
+ if (oledb->force_pd_control) {
+ oledb->pbs_dev_node = of_parse_phandle(of_node,
+ "qcom,pbs-client", 0);
+ if (!oledb->pbs_dev_node) {
+ pr_err("Missing qcom,pbs-client property\n");
+ return -EINVAL;
+ }
+ }
+
oledb->current_voltage = -EINVAL;
rc = of_property_read_u32(of_node, "qcom,oledb-init-voltage-mv",
&oledb->current_voltage);
@@ -1116,6 +1194,52 @@
return rc;
}
+static int qpnp_oledb_force_pulldown_config(struct qpnp_oledb *oledb)
+{
+ int rc = 0;
+ u8 val;
+
+ rc = qpnp_oledb_sec_masked_write(oledb, oledb->base +
+ OLEDB_SPARE_CTL, OLEDB_FORCE_PD_CTL_SPARE_BIT, 0);
+ if (rc < 0) {
+ pr_err("Failed to write SPARE_CTL rc=%d\n", rc);
+ return rc;
+ }
+
+ val = 1;
+ rc = qpnp_oledb_write(oledb, oledb->base + OLEDB_PD_CTL,
+ &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to write PD_CTL rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = qpnp_oledb_masked_write(oledb, oledb->base +
+ OLEDB_SWIRE_CONTROL, OLEDB_EN_SWIRE_PD_UPD_BIT, 0);
+ if (rc < 0)
+ pr_err("Failed to write SWIRE_CTL for pbs mode rc=%d\n",
+ rc);
+
+ return rc;
+}
+
+static int qpnp_labibb_notifier_cb(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ int rc = 0;
+ struct qpnp_oledb *oledb = container_of(nb, struct qpnp_oledb,
+ oledb_nb);
+
+ if (action == LAB_VREG_OK) {
+ /* Disable SWIRE pull down control and enable via spmi mode */
+ rc = qpnp_oledb_force_pulldown_config(oledb);
+ if (rc < 0)
+ return NOTIFY_STOP;
+ }
+
+ return NOTIFY_OK;
+}
+
static int qpnp_oledb_regulator_probe(struct platform_device *pdev)
{
int rc = 0;
@@ -1143,6 +1267,7 @@
return rc;
}
+ mutex_init(&(oledb->bus_lock));
oledb->base = val;
rc = qpnp_oledb_parse_dt(oledb);
if (rc < 0) {
@@ -1156,18 +1281,47 @@
return rc;
}
+ if (oledb->force_pd_control) {
+ oledb->oledb_nb.notifier_call = qpnp_labibb_notifier_cb;
+ rc = qpnp_labibb_notifier_register(&oledb->oledb_nb);
+ if (rc < 0) {
+ pr_err("Failed to register qpnp_labibb_notifier_cb\n");
+ return rc;
+ }
+ }
+
rc = qpnp_oledb_register_regulator(oledb);
- if (!rc)
- pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d cuurent_voltage=%d mV\n",
+ if (rc < 0) {
+ pr_err("Failed to register regulator rc=%d\n", rc);
+ goto out;
+ }
+ pr_info("OLEDB registered successfully, ext_pin_en=%d mod_en=%d current_voltage=%d mV\n",
oledb->ext_pin_control, oledb->mod_enable,
oledb->current_voltage);
+ return 0;
+
+out:
+ if (oledb->force_pd_control) {
+ rc = qpnp_labibb_notifier_unregister(&oledb->oledb_nb);
+ if (rc < 0)
+ pr_err("Failed to unregister lab_vreg_ok notifier\n");
+ }
return rc;
}
static int qpnp_oledb_regulator_remove(struct platform_device *pdev)
{
- return 0;
+ int rc = 0;
+ struct qpnp_oledb *oledb = platform_get_drvdata(pdev);
+
+ if (oledb->force_pd_control) {
+ rc = qpnp_labibb_notifier_unregister(&oledb->oledb_nb);
+ if (rc < 0)
+ pr_err("Failed to unregister lab_vreg_ok notifier\n");
+ }
+
+ return rc;
}
const struct of_device_id qpnp_oledb_regulator_match_table[] = {
diff --git a/drivers/scsi/ufs/ufs-debugfs.c b/drivers/scsi/ufs/ufs-debugfs.c
index 6607fd4..bc2d2d4 100644
--- a/drivers/scsi/ufs/ufs-debugfs.c
+++ b/drivers/scsi/ufs/ufs-debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, 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
@@ -1412,8 +1412,10 @@
struct ufs_hba *hba = filp->f_mapping->host->i_private;
unsigned long flags;
- spin_lock_irqsave(hba->host->host_lock, flags);
+ pm_runtime_get_sync(hba->dev);
+ ufshcd_hold(hba, false);
+ spin_lock_irqsave(hba->host->host_lock, flags);
/*
* simulating a dummy error in order to "convince"
* eh_work to actually reset the controller
@@ -1421,9 +1423,13 @@
hba->saved_err |= INT_FATAL_ERRORS;
hba->silence_err_logs = true;
schedule_work(&hba->eh_work);
-
spin_unlock_irqrestore(hba->host->host_lock, flags);
+ flush_work(&hba->eh_work);
+
+ ufshcd_release(hba, false);
+ pm_runtime_put_sync(hba->dev);
+
return cnt;
}
@@ -1471,8 +1477,8 @@
void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
if (!hba) {
- dev_err(hba->dev, "%s: NULL hba, exiting", __func__);
- goto err_no_root;
+ pr_err("%s: NULL hba, exiting", __func__);
+ return;
}
hba->debugfs_files.debugfs_root = debugfs_create_dir(dev_name(hba->dev),
diff --git a/drivers/scsi/ufs/ufs-qcom-debugfs.c b/drivers/scsi/ufs/ufs-qcom-debugfs.c
index 8532439..4547a6d 100644
--- a/drivers/scsi/ufs/ufs-qcom-debugfs.c
+++ b/drivers/scsi/ufs/ufs-qcom-debugfs.c
@@ -67,6 +67,7 @@
static int ufs_qcom_dbg_testbus_en_set(void *data, u64 attr_id)
{
struct ufs_qcom_host *host = data;
+ int ret = 0;
if (!host)
return -EINVAL;
@@ -76,7 +77,13 @@
else
host->dbg_print_en &= ~UFS_QCOM_DBG_PRINT_TEST_BUS_EN;
- return ufs_qcom_testbus_config(host);
+ pm_runtime_get_sync(host->hba->dev);
+ ufshcd_hold(host->hba, false);
+ ret = ufs_qcom_testbus_config(host);
+ ufshcd_release(host->hba, false);
+ pm_runtime_put_sync(host->hba->dev);
+
+ return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(ufs_qcom_dbg_testbus_en_ops,
@@ -142,7 +149,11 @@
* Sanity check of the {major, minor} tuple is done in the
* config function
*/
+ pm_runtime_get_sync(host->hba->dev);
+ ufshcd_hold(host->hba, false);
ret = ufs_qcom_testbus_config(host);
+ ufshcd_release(host->hba, false);
+ pm_runtime_put_sync(host->hba->dev);
if (!ret)
dev_dbg(host->hba->dev,
"%s: New configuration: major=%d, minor=%d\n",
diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c
index 1ba4f2b..814d1dc 100644
--- a/drivers/scsi/ufs/ufs-qcom-ice.c
+++ b/drivers/scsi/ufs/ufs-qcom-ice.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
@@ -14,6 +14,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/blkdev.h>
+#include <linux/spinlock.h>
#include <crypto/ice.h>
#include "ufs-qcom-ice.h"
@@ -168,13 +169,23 @@
static void ufs_qcom_ice_cfg_work(struct work_struct *work)
{
+ unsigned long flags;
struct ice_data_setting ice_set;
struct ufs_qcom_host *qcom_host =
container_of(work, struct ufs_qcom_host, ice_cfg_work);
+ struct request *req_pending = NULL;
- if (!qcom_host->ice.vops->config_start || !qcom_host->req_pending)
+ if (!qcom_host->ice.vops->config_start)
return;
+ spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
+ req_pending = qcom_host->req_pending;
+ if (!req_pending) {
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+
/*
* config_start is called again as previous attempt returned -EAGAIN,
* this call shall now take care of the necessary key setup.
@@ -185,12 +196,17 @@
qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
qcom_host->req_pending, &ice_set, false);
+ spin_lock_irqsave(&qcom_host->ice_work_lock, flags);
+ qcom_host->req_pending = NULL;
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+
/*
* Resume with requests processing. We assume config_start has been
* successful, but even if it wasn't we still must resume in order to
* allow for the request to be retried.
*/
ufshcd_scsi_unblock_requests(qcom_host->hba);
+
}
/**
@@ -246,6 +262,7 @@
struct ice_data_setting ice_set;
char cmd_op = cmd->cmnd[0];
int err;
+ unsigned long flags;
if (!qcom_host->ice.pdev || !qcom_host->ice.vops) {
dev_dbg(qcom_host->hba->dev, "%s: ice device is not enabled\n",
@@ -255,6 +272,10 @@
if (qcom_host->ice.vops->config_start) {
memset(&ice_set, 0, sizeof(ice_set));
+
+ spin_lock_irqsave(
+ &qcom_host->ice_work_lock, flags);
+
err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
cmd->request, &ice_set, true);
if (err) {
@@ -272,19 +293,41 @@
dev_dbg(qcom_host->hba->dev,
"%s: scheduling task for ice setup\n",
__func__);
- qcom_host->req_pending = cmd->request;
- if (schedule_work(&qcom_host->ice_cfg_work))
+
+ if (!qcom_host->req_pending) {
ufshcd_scsi_block_requests(
qcom_host->hba);
+ qcom_host->req_pending = cmd->request;
+
+ if (!schedule_work(
+ &qcom_host->ice_cfg_work)) {
+ qcom_host->req_pending = NULL;
+
+ spin_unlock_irqrestore(
+ &qcom_host->ice_work_lock,
+ flags);
+
+ ufshcd_scsi_unblock_requests(
+ qcom_host->hba);
+ return err;
+ }
+ }
+
} else {
- dev_err(qcom_host->hba->dev,
- "%s: error in ice_vops->config %d\n",
- __func__, err);
+ if (err != -EBUSY)
+ dev_err(qcom_host->hba->dev,
+ "%s: error in ice_vops->config %d\n",
+ __func__, err);
}
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock,
+ flags);
+
return err;
}
+ spin_unlock_irqrestore(&qcom_host->ice_work_lock, flags);
+
if (ufs_qcom_is_data_cmd(cmd_op, true))
*enable = !ice_set.encr_bypass;
else if (ufs_qcom_is_data_cmd(cmd_op, false))
@@ -320,6 +363,7 @@
unsigned int bypass = 0;
struct request *req;
char cmd_op;
+ unsigned long flags;
if (!qcom_host->ice.pdev || !qcom_host->ice.vops) {
dev_dbg(dev, "%s: ice device is not enabled\n", __func__);
@@ -339,7 +383,8 @@
req = cmd->request;
if (req->bio)
- lba = req->bio->bi_iter.bi_sector;
+ lba = (req->bio->bi_iter.bi_sector) >>
+ UFS_QCOM_ICE_TR_DATA_UNIT_4_KB;
slot = req->tag;
if (slot < 0 || slot > qcom_host->hba->nutrs) {
@@ -348,8 +393,13 @@
return -EINVAL;
}
- memset(&ice_set, 0, sizeof(ice_set));
+
if (qcom_host->ice.vops->config_start) {
+ memset(&ice_set, 0, sizeof(ice_set));
+
+ spin_lock_irqsave(
+ &qcom_host->ice_work_lock, flags);
+
err = qcom_host->ice.vops->config_start(qcom_host->ice.pdev,
req, &ice_set, true);
if (err) {
@@ -364,13 +414,44 @@
* request processing.
*/
if (err == -EAGAIN) {
- qcom_host->req_pending = req;
- if (schedule_work(&qcom_host->ice_cfg_work))
+
+ dev_dbg(qcom_host->hba->dev,
+ "%s: scheduling task for ice setup\n",
+ __func__);
+
+ if (!qcom_host->req_pending) {
ufshcd_scsi_block_requests(
+ qcom_host->hba);
+ qcom_host->req_pending = cmd->request;
+ if (!schedule_work(
+ &qcom_host->ice_cfg_work)) {
+ qcom_host->req_pending = NULL;
+
+ spin_unlock_irqrestore(
+ &qcom_host->ice_work_lock,
+ flags);
+
+ ufshcd_scsi_unblock_requests(
qcom_host->hba);
+ return err;
+ }
+ }
+
+ } else {
+ if (err != -EBUSY)
+ dev_err(qcom_host->hba->dev,
+ "%s: error in ice_vops->config %d\n",
+ __func__, err);
}
- goto out;
+
+ spin_unlock_irqrestore(
+ &qcom_host->ice_work_lock, flags);
+
+ return err;
}
+
+ spin_unlock_irqrestore(
+ &qcom_host->ice_work_lock, flags);
}
cmd_op = cmd->cmnd[0];
@@ -390,6 +471,7 @@
bypass = ice_set.decr_bypass ? UFS_QCOM_ICE_ENABLE_BYPASS :
UFS_QCOM_ICE_DISABLE_BYPASS;
+
/* Configure ICE index */
ctrl_info_val =
(ice_set.crypto_data.key_index &
@@ -398,8 +480,7 @@
/* Configure data unit size of transfer request */
ctrl_info_val |=
- (UFS_QCOM_ICE_TR_DATA_UNIT_4_KB &
- MASK_UFS_QCOM_ICE_CTRL_INFO_CDU)
+ UFS_QCOM_ICE_TR_DATA_UNIT_4_KB
<< OFFSET_UFS_QCOM_ICE_CTRL_INFO_CDU;
/* Configure ICE bypass mode */
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 9706273..d326b80 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -33,6 +33,9 @@
#include "ufs-qcom-ice.h"
#include "ufs-qcom-debugfs.h"
+#define MAX_PROP_SIZE 32
+#define VDDP_REF_CLK_MIN_UV 1200000
+#define VDDP_REF_CLK_MAX_UV 1200000
/* TODO: further tuning for this parameter may be required */
#define UFS_QCOM_PM_QOS_UNVOTE_TIMEOUT_US (10000) /* microseconds */
@@ -97,13 +100,10 @@
int err = 0;
clk = devm_clk_get(dev, name);
- if (IS_ERR(clk)) {
+ if (IS_ERR(clk))
err = PTR_ERR(clk);
- dev_err(dev, "%s: failed to get %s err %d",
- __func__, name, err);
- } else {
+ else
*clk_out = clk;
- }
return err;
}
@@ -182,20 +182,29 @@
err = ufs_qcom_host_clk_get(dev,
"rx_lane0_sync_clk", &host->rx_l0_sync_clk);
- if (err)
+ if (err) {
+ dev_err(dev, "%s: failed to get rx_lane0_sync_clk, err %d",
+ __func__, err);
goto out;
+ }
err = ufs_qcom_host_clk_get(dev,
"tx_lane0_sync_clk", &host->tx_l0_sync_clk);
- if (err)
+ if (err) {
+ dev_err(dev, "%s: failed to get tx_lane0_sync_clk, err %d",
+ __func__, err);
goto out;
+ }
/* In case of single lane per direction, don't read lane1 clocks */
if (host->hba->lanes_per_direction > 1) {
err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
&host->rx_l1_sync_clk);
- if (err)
+ if (err) {
+ dev_err(dev, "%s: failed to get rx_lane1_sync_clk, err %d",
+ __func__, err);
goto out;
+ }
/* The tx lane1 clk could be muxed, hence keep this optional */
ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
@@ -387,8 +396,9 @@
/**
* Returns zero for success and non-zero in case of a failure
*/
-static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
- u32 hs, u32 rate, bool update_link_startup_timer)
+static int __ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
+ u32 hs, u32 rate, bool update_link_startup_timer,
+ bool is_pre_scale_up)
{
int ret = 0;
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -435,8 +445,12 @@
}
list_for_each_entry(clki, &hba->clk_list_head, list) {
- if (!strcmp(clki->name, "core_clk"))
- core_clk_rate = clk_get_rate(clki->clk);
+ if (!strcmp(clki->name, "core_clk")) {
+ if (is_pre_scale_up)
+ core_clk_rate = clki->max_freq;
+ else
+ core_clk_rate = clk_get_rate(clki->clk);
+ }
}
/* If frequency is smaller than 1MHz, set to 1MHz */
@@ -533,6 +547,13 @@
return ret;
}
+static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
+ u32 hs, u32 rate, bool update_link_startup_timer)
+{
+ return __ufs_qcom_cfg_timers(hba, gear, hs, rate,
+ update_link_startup_timer, false);
+}
+
static int ufs_qcom_link_startup_pre_change(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
@@ -666,40 +687,105 @@
return err;
}
+
+static int ufs_qcom_config_vreg(struct device *dev,
+ struct ufs_vreg *vreg, bool on)
+{
+ int ret = 0;
+ struct regulator *reg;
+ int min_uV, uA_load;
+
+ if (!vreg) {
+ WARN_ON(1);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ reg = vreg->reg;
+ if (regulator_count_voltages(reg) > 0) {
+ min_uV = on ? vreg->min_uV : 0;
+ ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
+ if (ret) {
+ dev_err(dev, "%s: %s set voltage failed, err=%d\n",
+ __func__, vreg->name, ret);
+ goto out;
+ }
+
+ uA_load = on ? vreg->max_uA : 0;
+ ret = regulator_set_load(vreg->reg, uA_load);
+ if (ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+static int ufs_qcom_enable_vreg(struct device *dev, struct ufs_vreg *vreg)
+{
+ int ret = 0;
+
+ if (vreg->enabled)
+ return ret;
+
+ ret = ufs_qcom_config_vreg(dev, vreg, true);
+ if (ret)
+ goto out;
+
+ ret = regulator_enable(vreg->reg);
+ if (ret)
+ goto out;
+
+ vreg->enabled = true;
+out:
+ return ret;
+}
+
+static int ufs_qcom_disable_vreg(struct device *dev, struct ufs_vreg *vreg)
+{
+ int ret = 0;
+
+ if (!vreg->enabled)
+ return ret;
+
+ ret = regulator_disable(vreg->reg);
+ if (ret)
+ goto out;
+
+ ret = ufs_qcom_config_vreg(dev, vreg, false);
+ if (ret)
+ goto out;
+
+ vreg->enabled = false;
+out:
+ return ret;
+}
+
static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
int ret = 0;
- if (ufs_qcom_is_link_off(hba)) {
- /*
- * Disable the tx/rx lane symbol clocks before PHY is
- * powered down as the PLL source should be disabled
- * after downstream clocks are disabled.
- */
- ufs_qcom_disable_lane_clks(host);
- phy_power_off(phy);
- ret = ufs_qcom_ice_suspend(host);
- if (ret)
- dev_err(hba->dev, "%s: failed ufs_qcom_ice_suspend %d\n",
- __func__, ret);
-
- /* Assert PHY soft reset */
- ufs_qcom_assert_reset(hba);
- goto out;
- }
-
/*
- * If UniPro link is not active, PHY ref_clk, main PHY analog power
- * rail and low noise analog power rail for PLL can be switched off.
+ * If UniPro link is not active or OFF, PHY ref_clk, main PHY analog
+ * power rail and low noise analog power rail for PLL can be
+ * switched off.
*/
if (!ufs_qcom_is_link_active(hba)) {
ufs_qcom_disable_lane_clks(host);
phy_power_off(phy);
- ufs_qcom_ice_suspend(host);
- }
+ if (host->vddp_ref_clk && ufs_qcom_is_link_off(hba))
+ ret = ufs_qcom_disable_vreg(hba->dev,
+ host->vddp_ref_clk);
+ ufs_qcom_ice_suspend(host);
+
+ if (ufs_qcom_is_link_off(hba)) {
+ /* Assert PHY soft reset */
+ ufs_qcom_assert_reset(hba);
+ goto out;
+ }
+ }
/* Unvote PM QoS */
ufs_qcom_pm_qos_suspend(host);
@@ -720,6 +806,11 @@
goto out;
}
+ if (host->vddp_ref_clk && (hba->rpm_lvl > UFS_PM_LVL_3 ||
+ hba->spm_lvl > UFS_PM_LVL_3))
+ ufs_qcom_enable_vreg(hba->dev,
+ host->vddp_ref_clk);
+
err = ufs_qcom_enable_lane_clks(host);
if (err)
goto out;
@@ -739,7 +830,35 @@
static int ufs_qcom_full_reset(struct ufs_hba *hba)
{
- return -ENOTSUPP;
+ int ret = -ENOTSUPP;
+
+ if (!hba->core_reset) {
+ dev_err(hba->dev, "%s: failed, err = %d\n", __func__,
+ ret);
+ goto out;
+ }
+
+ ret = reset_control_assert(hba->core_reset);
+ if (ret) {
+ dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ /*
+ * The hardware requirement for delay between assert/deassert
+ * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to
+ * ~125us (4/32768). To be on the safe side add 200us delay.
+ */
+ usleep_range(200, 210);
+
+ ret = reset_control_deassert(hba->core_reset);
+ if (ret)
+ dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n",
+ __func__, ret);
+
+out:
+ return ret;
}
#ifdef CONFIG_SCSI_UFS_QCOM_ICE
@@ -757,7 +876,8 @@
/* Use request LBA as the DUN value */
if (req->bio)
- *dun = req->bio->bi_iter.bi_sector;
+ *dun = (req->bio->bi_iter.bi_sector) >>
+ UFS_QCOM_ICE_TR_DATA_UNIT_4_KB;
ret = ufs_qcom_ice_req_setup(host, lrbp->cmd, cc_index, enable);
@@ -978,7 +1098,7 @@
}
}
-static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+static int __ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
{
int err = 0;
@@ -1009,7 +1129,7 @@
vote = ufs_qcom_get_bus_vote(host, mode);
if (vote >= 0)
- err = ufs_qcom_set_bus_vote(host, vote);
+ err = __ufs_qcom_set_bus_vote(host, vote);
else
err = vote;
@@ -1020,6 +1140,35 @@
return err;
}
+static int ufs_qcom_set_bus_vote(struct ufs_hba *hba, bool on)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ int vote, err;
+
+ /*
+ * In case ufs_qcom_init() is not yet done, simply ignore.
+ * This ufs_qcom_set_bus_vote() shall be called from
+ * ufs_qcom_init() after init is done.
+ */
+ if (!host)
+ return 0;
+
+ if (on) {
+ vote = host->bus_vote.saved_vote;
+ if (vote == host->bus_vote.min_bw_vote)
+ ufs_qcom_update_bus_bw_vote(host);
+ } else {
+ vote = host->bus_vote.min_bw_vote;
+ }
+
+ err = __ufs_qcom_set_bus_vote(host, vote);
+ if (err)
+ dev_err(hba->dev, "%s: set bus vote failed %d\n",
+ __func__, err);
+
+ return err;
+}
+
static ssize_t
show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1096,7 +1245,7 @@
return 0;
}
-static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+static int ufs_qcom_set_bus_vote(struct ufs_hba *hba, bool on)
{
return 0;
}
@@ -1373,7 +1522,6 @@
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err;
- int vote = 0;
/*
* In case ufs_qcom_init() is not yet done, simply ignore.
@@ -1398,9 +1546,6 @@
/* enable the device ref clock for HS mode*/
if (ufshcd_is_hs_mode(&hba->pwr_info))
ufs_qcom_dev_ref_clk_ctrl(host, true);
- vote = host->bus_vote.saved_vote;
- if (vote == host->bus_vote.min_bw_vote)
- ufs_qcom_update_bus_bw_vote(host);
err = ufs_qcom_ice_resume(host);
if (err)
@@ -1412,21 +1557,19 @@
/* M-PHY RMMI interface clocks can be turned off */
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
- if (!ufs_qcom_is_link_active(hba)) {
- if (!is_gating_context)
- /* turn off UFS local PHY ref_clk */
- ufs_qcom_phy_disable_ref_clk(host->generic_phy);
+ /*
+ * If auto hibern8 is supported then the link will already
+ * be in hibern8 state and the ref clock can be gated.
+ */
+ if (ufshcd_is_auto_hibern8_supported(hba) ||
+ !ufs_qcom_is_link_active(hba)) {
+ /* turn off UFS local PHY ref_clk */
+ ufs_qcom_phy_disable_ref_clk(host->generic_phy);
/* disable device ref_clk */
ufs_qcom_dev_ref_clk_ctrl(host, false);
}
- vote = host->bus_vote.min_bw_vote;
}
- err = ufs_qcom_set_bus_vote(host, vote);
- if (err)
- dev_err(hba->dev, "%s: set bus vote failed %d\n",
- __func__, err);
-
out:
return err;
}
@@ -1850,6 +1993,57 @@
dev_err(hba->dev, "invalid host index %d\n", id);
}
+static int ufs_qcom_parse_reg_info(struct ufs_qcom_host *host, char *name,
+ struct ufs_vreg **out_vreg)
+{
+ int ret = 0;
+ char prop_name[MAX_PROP_SIZE];
+ struct ufs_vreg *vreg = NULL;
+ struct device *dev = host->hba->dev;
+ struct device_node *np = dev->of_node;
+
+ if (!np) {
+ dev_err(dev, "%s: non DT initialization\n", __func__);
+ goto out;
+ }
+
+ snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name);
+ if (!of_parse_phandle(np, prop_name, 0)) {
+ dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n",
+ __func__, prop_name);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+ if (!vreg)
+ return -ENOMEM;
+
+ vreg->name = name;
+
+ snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
+ ret = of_property_read_u32(np, prop_name, &vreg->max_uA);
+ if (ret) {
+ dev_err(dev, "%s: unable to find %s err %d\n",
+ __func__, prop_name, ret);
+ goto out;
+ }
+
+ vreg->reg = devm_regulator_get(dev, vreg->name);
+ if (IS_ERR(vreg->reg)) {
+ ret = PTR_ERR(vreg->reg);
+ dev_err(dev, "%s: %s get failed, err=%d\n",
+ __func__, vreg->name, ret);
+ }
+ vreg->min_uV = VDDP_REF_CLK_MIN_UV;
+ vreg->max_uV = VDDP_REF_CLK_MAX_UV;
+
+out:
+ if (!ret)
+ *out_vreg = vreg;
+ return ret;
+}
+
/**
* ufs_qcom_init - bind phy with controller
* @hba: host controller instance
@@ -1877,14 +2071,9 @@
/* Make a two way bind between the qcom host and the hba */
host->hba = hba;
- ufshcd_set_variant(hba, host);
+ spin_lock_init(&host->ice_work_lock);
- /*
- * voting/devoting device ref_clk source is time consuming hence
- * skip devoting it during aggressive clock gating. This clock
- * will still be gated off during runtime suspend.
- */
- hba->no_ref_clk_gating = true;
+ ufshcd_set_variant(hba, host);
err = ufs_qcom_ice_get_dev(host);
if (err == -EPROBE_DEFER) {
@@ -1969,14 +2158,24 @@
ufs_qcom_phy_save_controller_version(host->generic_phy,
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
+ err = ufs_qcom_parse_reg_info(host, "qcom,vddp-ref-clk",
+ &host->vddp_ref_clk);
phy_init(host->generic_phy);
err = phy_power_on(host->generic_phy);
if (err)
goto out_unregister_bus;
+ if (host->vddp_ref_clk) {
+ err = ufs_qcom_enable_vreg(dev, host->vddp_ref_clk);
+ if (err) {
+ dev_err(dev, "%s: failed enabling ref clk supply: %d\n",
+ __func__, err);
+ goto out_disable_phy;
+ }
+ }
err = ufs_qcom_init_lane_clks(host);
if (err)
- goto out_disable_phy;
+ goto out_disable_vddp;
ufs_qcom_parse_lpm(host);
if (host->disable_lpm)
@@ -1984,6 +2183,7 @@
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
+ ufs_qcom_set_bus_vote(hba, true);
ufs_qcom_setup_clocks(hba, true, false);
host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN;
@@ -1999,6 +2199,9 @@
goto out;
+out_disable_vddp:
+ if (host->vddp_ref_clk)
+ ufs_qcom_disable_vreg(dev, host->vddp_ref_clk);
out_disable_phy:
phy_power_off(host->generic_phy);
out_unregister_bus:
@@ -2049,79 +2252,21 @@
return err;
}
-static inline int ufs_qcom_configure_lpm(struct ufs_hba *hba, bool enable)
-{
- struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
- int err = 0;
-
- /* The default low power mode configuration is SVS2 */
- if (!ufs_qcom_cap_svs2(host))
- goto out;
-
- /*
- * The link should be put in hibern8 state before
- * configuring the PHY to enter/exit SVS2 mode.
- */
- err = ufshcd_uic_hibern8_enter(hba);
- if (err)
- goto out;
-
- err = ufs_qcom_phy_configure_lpm(phy, enable);
- if (err)
- goto out;
-
- err = ufshcd_uic_hibern8_exit(hba);
-out:
- return err;
-}
-
static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
-
- if (!ufs_qcom_cap_qunipro(host))
- return 0;
-
- return ufs_qcom_configure_lpm(hba, false);
-}
-
-static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
-{
- struct ufs_qcom_host *host = ufshcd_get_variant(hba);
-
- if (!ufs_qcom_cap_qunipro(host))
- return 0;
-
- /* set unipro core clock cycles to 150 and clear clock divider */
- return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150);
-}
-
-static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba)
-{
- struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- u32 core_clk_ctrl_reg;
+ struct ufs_pa_layer_attr *attr = &host->dev_req_params;
int err = 0;
if (!ufs_qcom_cap_qunipro(host))
goto out;
- err = ufs_qcom_configure_lpm(hba, true);
- if (err)
- goto out;
+ if (attr)
+ __ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx,
+ attr->hs_rate, false, true);
- err = ufshcd_dme_get(hba,
- UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
- &core_clk_ctrl_reg);
-
- /* make sure CORE_CLK_DIV_EN is cleared */
- if (!err &&
- (core_clk_ctrl_reg & DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT)) {
- core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;
- err = ufshcd_dme_set(hba,
- UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
- core_clk_ctrl_reg);
- }
+ /* set unipro core clock cycles to 150 and clear clock divider */
+ err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150);
out:
return err;
}
@@ -2129,11 +2274,16 @@
static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ struct ufs_pa_layer_attr *attr = &host->dev_req_params;
int err = 0;
if (!ufs_qcom_cap_qunipro(host))
return 0;
+ if (attr)
+ ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx,
+ attr->hs_rate, false);
+
if (ufs_qcom_cap_svs2(host))
/*
* For SVS2 set unipro core clock cycles to 37 and
@@ -2154,30 +2304,17 @@
bool scale_up, enum ufs_notify_change_status status)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params;
int err = 0;
switch (status) {
case PRE_CHANGE:
if (scale_up)
err = ufs_qcom_clk_scale_up_pre_change(hba);
- else
- err = ufs_qcom_clk_scale_down_pre_change(hba);
break;
case POST_CHANGE:
- if (scale_up)
- err = ufs_qcom_clk_scale_up_post_change(hba);
- else
+ if (!scale_up)
err = ufs_qcom_clk_scale_down_post_change(hba);
- if (err || !dev_req_params)
- goto out;
-
- ufs_qcom_cfg_timers(hba,
- dev_req_params->gear_rx,
- dev_req_params->pwr_rx,
- dev_req_params->hs_rate,
- false);
ufs_qcom_update_bus_bw_vote(host);
break;
default:
@@ -2186,7 +2323,6 @@
break;
}
-out:
return err;
}
@@ -2277,17 +2413,21 @@
static void ufs_qcom_enable_test_bus(struct ufs_qcom_host *host)
{
- if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+ if (host->dbg_print_en & UFS_QCOM_DBG_PRINT_TEST_BUS_EN) {
+ ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN,
+ UFS_REG_TEST_BUS_EN, REG_UFS_CFG1);
ufshcd_rmwl(host->hba, TEST_BUS_EN, TEST_BUS_EN, REG_UFS_CFG1);
- else
+ } else {
+ ufshcd_rmwl(host->hba, UFS_REG_TEST_BUS_EN, 0, REG_UFS_CFG1);
ufshcd_rmwl(host->hba, TEST_BUS_EN, 0, REG_UFS_CFG1);
+ }
}
static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
{
/* provide a legal default configuration */
- host->testbus.select_major = TSTBUS_UAWM;
- host->testbus.select_minor = 1;
+ host->testbus.select_major = TSTBUS_UNIPRO;
+ host->testbus.select_minor = 37;
}
static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
@@ -2304,7 +2444,7 @@
* mappings of select_minor, since there is no harm in
* configuring a non-existent select_minor
*/
- if (host->testbus.select_minor > 0x1F) {
+ if (host->testbus.select_minor > 0xFF) {
dev_err(host->hba->dev,
"%s: 0x%05X is not a legal testbus option\n",
__func__, host->testbus.select_minor);
@@ -2314,6 +2454,11 @@
return true;
}
+/*
+ * The caller of this function must make sure that the controller
+ * is out of runtime suspend and appropriate clocks are enabled
+ * before accessing.
+ */
int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
{
int reg;
@@ -2373,7 +2518,8 @@
break;
case TSTBUS_UNIPRO:
reg = UFS_UNIPRO_CFG;
- offset = 1;
+ offset = 20;
+ mask = 0xFFF;
break;
/*
* No need for a default case, since
@@ -2383,8 +2529,6 @@
}
mask <<= offset;
- pm_runtime_get_sync(host->hba->dev);
- ufshcd_hold(host->hba, false);
ufshcd_rmwl(host->hba, TEST_BUS_SEL,
(u32)host->testbus.select_major << 19,
REG_UFS_CFG1);
@@ -2392,8 +2536,11 @@
(u32)host->testbus.select_minor << offset,
reg);
ufs_qcom_enable_test_bus(host);
- ufshcd_release(host->hba, false);
- pm_runtime_put_sync(host->hba->dev);
+ /*
+ * Make sure the test bus configuration is
+ * committed before returning.
+ */
+ mb();
return 0;
}
@@ -2403,15 +2550,47 @@
ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
}
-static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
+static void ufs_qcom_print_unipro_testbus(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ u32 *testbus = NULL;
+ int i, nminor = 256, testbus_len = nminor * sizeof(u32);
+
+ testbus = kmalloc(testbus_len, GFP_KERNEL);
+ if (!testbus)
+ return;
+
+ host->testbus.select_major = TSTBUS_UNIPRO;
+ for (i = 0; i < nminor; i++) {
+ host->testbus.select_minor = i;
+ ufs_qcom_testbus_config(host);
+ testbus[i] = ufshcd_readl(hba, UFS_TEST_BUS);
+ }
+ print_hex_dump(KERN_ERR, "UNIPRO_TEST_BUS ", DUMP_PREFIX_OFFSET,
+ 16, 4, testbus, testbus_len, false);
+ kfree(testbus);
+}
+
+static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba, bool no_sleep)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ struct phy *phy = host->generic_phy;
ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
"HCI Vendor Specific Registers ");
-
ufs_qcom_print_hw_debug_reg_all(hba, NULL, ufs_qcom_dump_regs_wrapper);
+
+ if (no_sleep)
+ return;
+
+ /* sleep a bit intermittently as we are dumping too much data */
+ usleep_range(1000, 1100);
ufs_qcom_testbus_read(hba);
+ usleep_range(1000, 1100);
+ ufs_qcom_print_unipro_testbus(hba);
+ usleep_range(1000, 1100);
+ ufs_qcom_phy_dbg_register_dump(phy);
+ usleep_range(1000, 1100);
ufs_qcom_ice_print_regs(host);
}
@@ -2436,6 +2615,7 @@
.full_reset = ufs_qcom_full_reset,
.update_sec_cfg = ufs_qcom_update_sec_cfg,
.get_scale_down_gear = ufs_qcom_get_scale_down_gear,
+ .set_bus_vote = ufs_qcom_set_bus_vote,
.dbg_register_dump = ufs_qcom_dump_dbg_regs,
#ifdef CONFIG_DEBUG_FS
.add_debugfs = ufs_qcom_dbg_add_debugfs,
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 42e7aad8..792ae42 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, 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
@@ -100,6 +100,7 @@
#define QUNIPRO_SEL UFS_BIT(0)
#define TEST_BUS_EN BIT(18)
#define TEST_BUS_SEL GENMASK(22, 19)
+#define UFS_REG_TEST_BUS_EN BIT(30)
/* bit definitions for REG_UFS_CFG2 register */
#define UAWM_HW_CGC_EN (1 << 0)
@@ -369,8 +370,10 @@
u32 dbg_print_en;
struct ufs_qcom_testbus testbus;
+ spinlock_t ice_work_lock;
struct work_struct ice_cfg_work;
struct request *req_pending;
+ struct ufs_vreg *vddp_ref_clk;
};
static inline u32
diff --git a/drivers/scsi/ufs/ufs_quirks.c b/drivers/scsi/ufs/ufs_quirks.c
index b22a4c4..3210d60 100644
--- a/drivers/scsi/ufs/ufs_quirks.c
+++ b/drivers/scsi/ufs/ufs_quirks.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2016, 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
@@ -30,6 +30,20 @@
UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL,
UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME),
UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
+ UFS_FIX(UFS_VENDOR_SKHYNIX, "hB8aL1",
+ UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+ UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8aL1",
+ UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+ UFS_FIX(UFS_VENDOR_SKHYNIX, "hD8aL1",
+ UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+ UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8aM1",
+ UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+ UFS_FIX(UFS_VENDOR_SKHYNIX, "h08aM1",
+ UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+ UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8GL1",
+ UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
+ UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8HL1",
+ UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH),
END_FIX
};
diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h
index f7182ed..e7a59d4 100644
--- a/drivers/scsi/ufs/ufs_quirks.h
+++ b/drivers/scsi/ufs/ufs_quirks.h
@@ -1,4 +1,4 @@
-/* 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
@@ -130,6 +130,14 @@
*/
#define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 7)
+/*
+ * Some UFS devices may stop responding after switching from HS-G1 to HS-G3.
+ * Also, it is found that these devices work fine if we do 2 steps switch:
+ * HS-G1 to HS-G2 followed by HS-G2 to HS-G3. Enabling this quirk for such
+ * device would apply this 2 steps gear switch workaround.
+ */
+#define UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH (1 << 8)
+
struct ufs_hba;
void ufs_advertise_fixup_device(struct ufs_hba *hba);
diff --git a/drivers/scsi/ufs/ufs_test.c b/drivers/scsi/ufs/ufs_test.c
index 8953722e8..d41871a 100644
--- a/drivers/scsi/ufs/ufs_test.c
+++ b/drivers/scsi/ufs/ufs_test.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, 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
@@ -689,13 +689,13 @@
__blk_put_request(test_iosched->req_q, test_rq->rq);
spin_unlock_irqrestore(&test_iosched->lock, flags);
- test_iosched_free_test_req_data_buffer(test_rq);
- kfree(test_rq);
-
if (err)
pr_err("%s: request %d completed, err=%d", __func__,
test_rq->req_id, err);
+ test_iosched_free_test_req_data_buffer(test_rq);
+ kfree(test_rq);
+
check_test_completion(test_iosched);
}
@@ -984,14 +984,14 @@
return;
}
- test_iosched_free_test_req_data_buffer(test_rq);
- kfree(test_rq);
- utd->completed_req_count++;
-
if (err)
pr_err("%s: request %d completed, err=%d", __func__,
test_rq->req_id, err);
+ test_iosched_free_test_req_data_buffer(test_rq);
+ kfree(test_rq);
+ utd->completed_req_count++;
+
check_test_completion(test_iosched);
}
@@ -1007,7 +1007,7 @@
static int run_long_test(struct test_iosched *test_iosched)
{
int ret = 0;
- int direction, num_bios_per_request;
+ int direction, num_bios_per_request = 1;
static unsigned int inserted_requests;
u32 sector, seed, num_bios, seq_sector_delta;
struct ufs_test_data *utd = test_iosched->blk_dev_test_data;
@@ -1028,14 +1028,12 @@
/* Set test parameters */
switch (test_iosched->test_info.testcase) {
case UFS_TEST_LONG_RANDOM_READ:
- num_bios_per_request = 1;
utd->long_test_num_reqs = (utd->sector_range * SECTOR_SIZE) /
(LONG_RAND_TEST_REQ_RATIO * TEST_BIO_SIZE *
num_bios_per_request);
direction = READ;
break;
case UFS_TEST_LONG_RANDOM_WRITE:
- num_bios_per_request = 1;
utd->long_test_num_reqs = (utd->sector_range * SECTOR_SIZE) /
(LONG_RAND_TEST_REQ_RATIO * TEST_BIO_SIZE *
num_bios_per_request);
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 9c8473e..de6ecbd 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -40,6 +40,22 @@
#include "ufshcd.h"
#include "ufshcd-pltfrm.h"
+static int ufshcd_parse_reset_info(struct ufs_hba *hba)
+{
+ int ret = 0;
+
+ hba->core_reset = devm_reset_control_get(hba->dev,
+ "core_reset");
+ if (IS_ERR(hba->core_reset)) {
+ ret = PTR_ERR(hba->core_reset);
+ dev_err(hba->dev, "core_reset unavailable,err = %d\n",
+ ret);
+ hba->core_reset = NULL;
+ }
+
+ return ret;
+}
+
static int ufshcd_parse_clock_info(struct ufs_hba *hba)
{
int ret = 0;
@@ -297,6 +313,20 @@
hba->dev_ref_clk_freq = REF_CLK_FREQ_26_MHZ;
}
+static int ufshcd_parse_pinctrl_info(struct ufs_hba *hba)
+{
+ int ret = 0;
+
+ /* Try to obtain pinctrl handle */
+ hba->pctrl = devm_pinctrl_get(hba->dev);
+ if (IS_ERR(hba->pctrl)) {
+ ret = PTR_ERR(hba->pctrl);
+ hba->pctrl = NULL;
+ }
+
+ return ret;
+}
+
#ifdef CONFIG_SMP
/**
* ufshcd_pltfrm_suspend - suspend power management function
@@ -401,6 +431,20 @@
goto dealloc_host;
}
+ err = ufshcd_parse_reset_info(hba);
+ if (err) {
+ dev_err(&pdev->dev, "%s: reset parse failed %d\n",
+ __func__, err);
+ goto dealloc_host;
+ }
+
+ err = ufshcd_parse_pinctrl_info(hba);
+ if (err) {
+ dev_dbg(&pdev->dev, "%s: unable to parse pinctrl data %d\n",
+ __func__, err);
+ /* let's not fail the probe */
+ }
+
ufshcd_parse_dev_ref_clk_freq(hba);
ufshcd_parse_pm_levels(hba);
ufshcd_parse_gear_limits(hba);
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 7552357..712de81 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -47,6 +47,7 @@
#include "ufshci.h"
#include "ufs_quirks.h"
#include "ufs-debugfs.h"
+#include "ufs-qcom.h"
#define CREATE_TRACE_POINTS
#include <trace/events/ufs.h>
@@ -367,7 +368,7 @@
}
static irqreturn_t ufshcd_intr(int irq, void *__hba);
-static void ufshcd_tmc_handler(struct ufs_hba *hba);
+static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba);
static void ufshcd_async_scan(void *data, async_cookie_t cookie);
static int ufshcd_reset_and_restore(struct ufs_hba *hba);
static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd);
@@ -389,6 +390,28 @@
static void ufshcd_release_all(struct ufs_hba *hba);
static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba);
static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba);
+static int ufshcd_devfreq_target(struct device *dev,
+ unsigned long *freq, u32 flags);
+static int ufshcd_devfreq_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *stat);
+
+#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
+static struct devfreq_simple_ondemand_data ufshcd_ondemand_data = {
+ .upthreshold = 35,
+ .downdifferential = 30,
+ .simple_scaling = 1,
+};
+
+static void *gov_data = &ufshcd_ondemand_data;
+#else
+static void *gov_data;
+#endif
+
+static struct devfreq_dev_profile ufs_devfreq_profile = {
+ .polling_ms = 40,
+ .target = ufshcd_devfreq_target,
+ .get_dev_status = ufshcd_devfreq_get_dev_status,
+};
static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag)
{
@@ -441,10 +464,67 @@
}
EXPORT_SYMBOL(ufshcd_scsi_block_requests);
+static int ufshcd_device_reset_ctrl(struct ufs_hba *hba, bool ctrl)
+{
+ int ret = 0;
+
+ if (!hba->pctrl)
+ return 0;
+
+ /* Assert reset if ctrl == true */
+ if (ctrl)
+ ret = pinctrl_select_state(hba->pctrl,
+ pinctrl_lookup_state(hba->pctrl, "dev-reset-assert"));
+ else
+ ret = pinctrl_select_state(hba->pctrl,
+ pinctrl_lookup_state(hba->pctrl, "dev-reset-deassert"));
+
+ if (ret < 0)
+ dev_err(hba->dev, "%s: %s failed with err %d\n",
+ __func__, ctrl ? "Assert" : "Deassert", ret);
+
+ return ret;
+}
+
+static inline int ufshcd_assert_device_reset(struct ufs_hba *hba)
+{
+ return ufshcd_device_reset_ctrl(hba, true);
+}
+
+static inline int ufshcd_deassert_device_reset(struct ufs_hba *hba)
+{
+ return ufshcd_device_reset_ctrl(hba, false);
+}
+
+static int ufshcd_reset_device(struct ufs_hba *hba)
+{
+ int ret;
+
+ /* reset the connected UFS device */
+ ret = ufshcd_assert_device_reset(hba);
+ if (ret)
+ goto out;
+ /*
+ * The reset signal is active low.
+ * The UFS device shall detect more than or equal to 1us of positive
+ * or negative RST_n pulse width.
+ * To be on safe side, keep the reset low for atleast 10us.
+ */
+ usleep_range(10, 15);
+
+ ret = ufshcd_deassert_device_reset(hba);
+ if (ret)
+ goto out;
+ /* same as assert, wait for atleast 10us after deassert */
+ usleep_range(10, 15);
+out:
+ return ret;
+}
+
/* replace non-printable or non-ASCII characters with spaces */
static inline void ufshcd_remove_non_printable(char *val)
{
- if (!val)
+ if (!val || !*val)
return;
if (*val < 0x20 || *val > 0x7e)
@@ -534,7 +614,7 @@
}
}
-static void ufshcd_print_host_regs(struct ufs_hba *hba)
+static inline void __ufshcd_print_host_regs(struct ufs_hba *hba, bool no_sleep)
{
if (!(hba->ufshcd_dbg_print & UFSHCD_DBG_PRINT_HOST_REGS_EN))
return;
@@ -567,7 +647,12 @@
ufshcd_print_clk_freqs(hba);
- ufshcd_vops_dbg_register_dump(hba);
+ ufshcd_vops_dbg_register_dump(hba, no_sleep);
+}
+
+static void ufshcd_print_host_regs(struct ufs_hba *hba)
+{
+ __ufshcd_print_host_regs(hba, false);
}
static
@@ -1172,6 +1257,12 @@
return ret;
}
+static inline void ufshcd_cancel_gate_work(struct ufs_hba *hba)
+{
+ hrtimer_cancel(&hba->clk_gating.gate_hrtimer);
+ cancel_work_sync(&hba->clk_gating.gate_work);
+}
+
static void ufshcd_ungate_work(struct work_struct *work)
{
int ret;
@@ -1179,7 +1270,7 @@
struct ufs_hba *hba = container_of(work, struct ufs_hba,
clk_gating.ungate_work);
- cancel_delayed_work_sync(&hba->clk_gating.gate_work);
+ ufshcd_cancel_gate_work(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
if (hba->clk_gating.state == CLKS_ON) {
@@ -1250,14 +1341,18 @@
}
break;
case REQ_CLKS_OFF:
- if (cancel_delayed_work(&hba->clk_gating.gate_work)) {
+ /*
+ * If the timer was active but the callback was not running
+ * we have nothing to do, just change state and return.
+ */
+ if (hrtimer_try_to_cancel(&hba->clk_gating.gate_hrtimer) == 1) {
hba->clk_gating.state = CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
break;
}
/*
- * If we here, it means gating work is either done or
+ * If we are here, it means gating work is either done or
* currently running. Hence, fall through to cancel gating
* work and to enable clocks.
*/
@@ -1266,7 +1361,8 @@
hba->clk_gating.state = REQ_CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
- schedule_work(&hba->clk_gating.ungate_work);
+ queue_work(hba->clk_gating.ungating_workq,
+ &hba->clk_gating.ungate_work);
/*
* fall through to check if we should wait for this
* work to be done or not.
@@ -1297,11 +1393,18 @@
static void ufshcd_gate_work(struct work_struct *work)
{
struct ufs_hba *hba = container_of(work, struct ufs_hba,
- clk_gating.gate_work.work);
+ clk_gating.gate_work);
unsigned long flags;
spin_lock_irqsave(hba->host->host_lock, flags);
- if (hba->clk_gating.is_suspended) {
+ /*
+ * In case you are here to cancel this work the gating state
+ * would be marked as REQ_CLKS_ON. In this case save time by
+ * skipping the gating work and exit after changing the clock
+ * state to CLKS_ON.
+ */
+ if (hba->clk_gating.is_suspended ||
+ (hba->clk_gating.state == REQ_CLKS_ON)) {
hba->clk_gating.state = CLKS_ON;
trace_ufshcd_clk_gating(dev_name(hba->dev),
hba->clk_gating.state);
@@ -1335,7 +1438,12 @@
ufshcd_set_link_hibern8(hba);
}
- if (!ufshcd_is_link_active(hba) && !hba->no_ref_clk_gating)
+ /*
+ * If auto hibern8 is supported then the link will already
+ * be in hibern8 state and the ref clock can be gated.
+ */
+ if ((ufshcd_is_auto_hibern8_supported(hba) ||
+ !ufshcd_is_link_active(hba)) && !hba->no_ref_clk_gating)
ufshcd_disable_clocks(hba, true);
else
/* If link is active, device ref_clk can't be switched off */
@@ -1383,8 +1491,9 @@
hba->clk_gating.state = REQ_CLKS_OFF;
trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state);
- schedule_delayed_work(&hba->clk_gating.gate_work,
- msecs_to_jiffies(hba->clk_gating.delay_ms));
+ hrtimer_start(&hba->clk_gating.gate_hrtimer,
+ ms_to_ktime(hba->clk_gating.delay_ms),
+ HRTIMER_MODE_REL);
}
void ufshcd_release(struct ufs_hba *hba, bool no_sched)
@@ -1512,36 +1621,57 @@
return count;
}
+static enum hrtimer_restart ufshcd_clkgate_hrtimer_handler(
+ struct hrtimer *timer)
+{
+ struct ufs_hba *hba = container_of(timer, struct ufs_hba,
+ clk_gating.gate_hrtimer);
+
+ schedule_work(&hba->clk_gating.gate_work);
+
+ return HRTIMER_NORESTART;
+}
+
static void ufshcd_init_clk_gating(struct ufs_hba *hba)
{
struct ufs_clk_gating *gating = &hba->clk_gating;
+ char wq_name[sizeof("ufs_clk_ungating_00")];
hba->clk_gating.state = CLKS_ON;
if (!ufshcd_is_clkgating_allowed(hba))
return;
- INIT_DELAYED_WORK(&gating->gate_work, ufshcd_gate_work);
+ /*
+ * Disable hibern8 during clk gating if
+ * auto hibern8 is supported
+ */
+ if (ufshcd_is_auto_hibern8_supported(hba))
+ hba->caps &= ~UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
+
+ INIT_WORK(&gating->gate_work, ufshcd_gate_work);
INIT_WORK(&gating->ungate_work, ufshcd_ungate_work);
+ /*
+ * Clock gating work must be executed only after auto hibern8
+ * timeout has expired in the hardware or after aggressive
+ * hibern8 on idle software timeout. Using jiffy based low
+ * resolution delayed work is not reliable to guarantee this,
+ * hence use a high resolution timer to make sure we schedule
+ * the gate work precisely more than hibern8 timeout.
+ *
+ * Always make sure gating->delay_ms > hibern8_on_idle->delay_ms
+ */
+ hrtimer_init(&gating->gate_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ gating->gate_hrtimer.function = ufshcd_clkgate_hrtimer_handler;
+
+ snprintf(wq_name, ARRAY_SIZE(wq_name), "ufs_clk_ungating_%d",
+ hba->host->host_no);
+ hba->clk_gating.ungating_workq = create_singlethread_workqueue(wq_name);
gating->is_enabled = true;
- /*
- * Scheduling the delayed work after 1 jiffies will make the work to
- * get schedule any time from 0ms to 1000/HZ ms which is not desirable
- * for hibern8 enter work as it may impact the performance if it gets
- * scheduled almost immediately. Hence make sure that hibern8 enter
- * work gets scheduled atleast after 2 jiffies (any time between
- * 1000/HZ ms to 2000/HZ ms).
- */
- gating->delay_ms_pwr_save = jiffies_to_msecs(
- max_t(unsigned long,
- msecs_to_jiffies(UFSHCD_CLK_GATING_DELAY_MS_PWR_SAVE),
- 2));
- gating->delay_ms_perf = jiffies_to_msecs(
- max_t(unsigned long,
- msecs_to_jiffies(UFSHCD_CLK_GATING_DELAY_MS_PERF),
- 2));
+ gating->delay_ms_pwr_save = UFSHCD_CLK_GATING_DELAY_MS_PWR_SAVE;
+ gating->delay_ms_perf = UFSHCD_CLK_GATING_DELAY_MS_PERF;
/* start with performance mode */
gating->delay_ms = gating->delay_ms_perf;
@@ -1598,8 +1728,9 @@
device_remove_file(hba->dev, &hba->clk_gating.delay_attr);
}
device_remove_file(hba->dev, &hba->clk_gating.enable_attr);
+ ufshcd_cancel_gate_work(hba);
cancel_work_sync(&hba->clk_gating.ungate_work);
- cancel_delayed_work_sync(&hba->clk_gating.gate_work);
+ destroy_workqueue(hba->clk_gating.ungating_workq);
}
static void ufshcd_set_auto_hibern8_timer(struct ufs_hba *hba, u32 delay)
@@ -1910,6 +2041,7 @@
return;
if (ufshcd_is_auto_hibern8_supported(hba)) {
+ hba->hibern8_on_idle.delay_ms = 1;
hba->hibern8_on_idle.state = AUTO_HIBERN8;
/*
* Disable SW hibern8 enter on idle in case
@@ -1917,13 +2049,13 @@
*/
hba->caps &= ~UFSHCD_CAP_HIBERN8_ENTER_ON_IDLE;
} else {
+ hba->hibern8_on_idle.delay_ms = 10;
INIT_DELAYED_WORK(&hba->hibern8_on_idle.enter_work,
ufshcd_hibern8_enter_work);
INIT_WORK(&hba->hibern8_on_idle.exit_work,
ufshcd_hibern8_exit_work);
}
- hba->hibern8_on_idle.delay_ms = 10;
hba->hibern8_on_idle.is_enabled = true;
hba->hibern8_on_idle.delay_attr.show =
@@ -2360,9 +2492,6 @@
goto out;
req_desc->header.dword_0 |= cc_index | UTRD_CRYPTO_ENABLE;
- if (lrbp->cmd->request && lrbp->cmd->request->bio)
- dun = lrbp->cmd->request->bio->bi_iter.bi_sector;
-
req_desc->header.dword_1 = (u32)(dun & 0xFFFFFFFF);
req_desc->header.dword_3 = (u32)((dun >> 32) & 0xFFFFFFFF);
out:
@@ -2587,6 +2716,61 @@
}
/**
+ * ufshcd_get_write_lock - synchronize between shutdown, scaling &
+ * arrival of requests
+ * @hba: ufs host
+ *
+ * Lock is predominantly held by shutdown context thus, ensuring
+ * that no requests from any other context may sneak through.
+ */
+static inline void ufshcd_get_write_lock(struct ufs_hba *hba)
+{
+ down_write(&hba->lock);
+}
+
+/**
+ * ufshcd_get_read_lock - synchronize between shutdown, scaling &
+ * arrival of requests
+ * @hba: ufs host
+ *
+ * Returns 1 if acquired, < 0 on contention
+ *
+ * After shutdown's initiated, allow requests only directed to the
+ * well known device lun. The sync between scaling & issue is maintained
+ * as is and this restructuring syncs shutdown with these too.
+ */
+static int ufshcd_get_read_lock(struct ufs_hba *hba, u64 lun)
+{
+ int err = 0;
+
+ err = down_read_trylock(&hba->lock);
+ if (err > 0)
+ goto out;
+ /* let requests for well known device lun to go through */
+ if (ufshcd_scsi_to_upiu_lun(lun) == UFS_UPIU_UFS_DEVICE_WLUN)
+ return 0;
+ else if (!ufshcd_is_shutdown_ongoing(hba))
+ return -EAGAIN;
+ else
+ return -EPERM;
+
+out:
+ return err;
+}
+
+/**
+ * ufshcd_put_read_lock - synchronize between shutdown, scaling &
+ * arrival of requests
+ * @hba: ufs host
+ *
+ * Returns none
+ */
+static inline void ufshcd_put_read_lock(struct ufs_hba *hba)
+{
+ up_read(&hba->lock);
+}
+
+/**
* ufshcd_queuecommand - main entry point for SCSI requests
* @cmd: command from SCSI Midlayer
* @done: call back function
@@ -2600,9 +2784,13 @@
unsigned long flags;
int tag;
int err = 0;
+ bool has_read_lock = false;
hba = shost_priv(host);
+ if (!cmd || !cmd->request || !hba)
+ return -EINVAL;
+
tag = cmd->request->tag;
if (!ufshcd_valid_tag(hba, tag)) {
dev_err(hba->dev,
@@ -2611,10 +2799,27 @@
BUG();
}
- if (!down_read_trylock(&hba->clk_scaling_lock))
- return SCSI_MLQUEUE_HOST_BUSY;
+ err = ufshcd_get_read_lock(hba, cmd->device->lun);
+ if (unlikely(err < 0)) {
+ if (err == -EPERM) {
+ set_host_byte(cmd, DID_ERROR);
+ cmd->scsi_done(cmd);
+ return 0;
+ }
+ if (err == -EAGAIN)
+ return SCSI_MLQUEUE_HOST_BUSY;
+ } else if (err == 1) {
+ has_read_lock = true;
+ }
spin_lock_irqsave(hba->host->host_lock, flags);
+
+ /* if error handling is in progress, return host busy */
+ if (ufshcd_eh_in_progress(hba)) {
+ err = SCSI_MLQUEUE_HOST_BUSY;
+ goto out_unlock;
+ }
+
switch (hba->ufshcd_state) {
case UFSHCD_STATE_OPERATIONAL:
break;
@@ -2632,13 +2837,6 @@
cmd->scsi_done(cmd);
goto out_unlock;
}
-
- /* if error handling is in progress, don't issue commands */
- if (ufshcd_eh_in_progress(hba)) {
- set_host_byte(cmd, DID_ERROR);
- cmd->scsi_done(cmd);
- goto out_unlock;
- }
spin_unlock_irqrestore(hba->host->host_lock, flags);
hba->req_abort_count = 0;
@@ -2679,13 +2877,12 @@
ufshcd_vops_pm_qos_req_start(hba, cmd->request);
/* IO svc time latency histogram */
- if (hba != NULL && cmd->request != NULL) {
- if (hba->latency_hist_enabled &&
- (cmd->request->cmd_type == REQ_TYPE_FS)) {
- cmd->request->lat_hist_io_start = ktime_get();
- cmd->request->lat_hist_enabled = 1;
- } else
- cmd->request->lat_hist_enabled = 0;
+ if (hba->latency_hist_enabled &&
+ (cmd->request->cmd_type == REQ_TYPE_FS)) {
+ cmd->request->lat_hist_io_start = ktime_get();
+ cmd->request->lat_hist_enabled = 1;
+ } else {
+ cmd->request->lat_hist_enabled = 0;
}
WARN_ON(hba->clk_gating.state != CLKS_ON);
@@ -2764,7 +2961,8 @@
out_unlock:
spin_unlock_irqrestore(hba->host->host_lock, flags);
out:
- up_read(&hba->clk_scaling_lock);
+ if (has_read_lock)
+ ufshcd_put_read_lock(hba);
return err;
}
@@ -2956,7 +3154,12 @@
struct completion wait;
unsigned long flags;
- down_read(&hba->clk_scaling_lock);
+ /*
+ * May get invoked from shutdown and IOCTL contexts.
+ * In shutdown context, it comes in with lock acquired.
+ */
+ if (!ufshcd_is_shutdown_ongoing(hba))
+ down_read(&hba->lock);
/*
* Get free slot, sleep if slots are unavailable.
@@ -2989,7 +3192,8 @@
out_put_tag:
ufshcd_put_dev_cmd_tag(hba, tag);
wake_up(&hba->dev_cmd.tag_wq);
- up_read(&hba->clk_scaling_lock);
+ if (!ufshcd_is_shutdown_ongoing(hba))
+ up_read(&hba->lock);
return err;
}
@@ -3466,7 +3670,7 @@
goto out;
}
- buff_ascii = kmalloc(ascii_len, GFP_KERNEL);
+ buff_ascii = kzalloc(ascii_len, GFP_KERNEL);
if (!buff_ascii) {
dev_err(hba->dev, "%s: Failed allocating %d bytes\n",
__func__, ascii_len);
@@ -3929,8 +4133,12 @@
ret = (status != PWR_OK) ? status : -1;
}
out:
- if (ret)
+ if (ret) {
ufsdbg_set_err_state(hba);
+ ufshcd_print_host_state(hba);
+ ufshcd_print_pwr_info(hba);
+ ufshcd_print_host_regs(hba);
+ }
ufshcd_save_tstamp_of_last_dme_cmd(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -3954,17 +4162,17 @@
ufshcd_hold_all(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
- if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
- ret = -EBUSY;
- goto out;
- }
-
/*
* Wait for all the outstanding tasks/transfer requests.
* Verify by checking the doorbell registers are clear.
*/
start = ktime_get();
do {
+ if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
+ ret = -EBUSY;
+ goto out;
+ }
+
tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
if (!tm_doorbell && !tr_doorbell) {
@@ -4036,32 +4244,50 @@
static int ufshcd_link_recovery(struct ufs_hba *hba)
{
- int ret;
+ int ret = 0;
unsigned long flags;
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->ufshcd_state = UFSHCD_STATE_RESET;
- ufshcd_set_eh_in_progress(hba);
+ /*
+ * Check if there is any race with fatal error handling.
+ * If so, wait for it to complete. Even though fatal error
+ * handling does reset and restore in some cases, don't assume
+ * anything out of it. We are just avoiding race here.
+ */
+ do {
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (!(work_pending(&hba->eh_work) ||
+ hba->ufshcd_state == UFSHCD_STATE_RESET))
+ break;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
+ flush_work(&hba->eh_work);
+ } while (1);
+
+
+ /*
+ * we don't know if previous reset had really reset the host controller
+ * or not. So let's force reset here to be sure.
+ */
+ hba->ufshcd_state = UFSHCD_STATE_ERROR;
+ hba->force_host_reset = true;
+ schedule_work(&hba->eh_work);
+
+ /* wait for the reset work to finish */
+ do {
+ if (!(work_pending(&hba->eh_work) ||
+ hba->ufshcd_state == UFSHCD_STATE_RESET))
+ break;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
+ flush_work(&hba->eh_work);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ } while (1);
+
+ if (!((hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) &&
+ ufshcd_is_link_active(hba)))
+ ret = -ENOLINK;
spin_unlock_irqrestore(hba->host->host_lock, flags);
- ret = ufshcd_vops_full_reset(hba);
- if (ret)
- dev_warn(hba->dev,
- "full reset returned %d, trying to recover the link\n",
- ret);
-
- ret = ufshcd_host_reset_and_restore(hba);
-
- spin_lock_irqsave(hba->host->host_lock, flags);
- if (ret)
- hba->ufshcd_state = UFSHCD_STATE_ERROR;
- ufshcd_clear_eh_in_progress(hba);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
-
- if (ret)
- dev_err(hba->dev, "%s: link recovery failed, err %d",
- __func__, ret);
-
return ret;
}
@@ -4076,7 +4302,13 @@
trace_ufshcd_profile_hibern8(dev_name(hba->dev), "enter",
ktime_to_us(ktime_sub(ktime_get(), start)), ret);
- if (ret) {
+ /*
+ * Do full reinit if enter failed or if LINERESET was detected during
+ * Hibern8 operation. After LINERESET, link moves to default PWM-G1
+ * mode hence full reinit is required to move link to HS speeds.
+ */
+ if (ret || hba->full_init_linereset) {
+ hba->full_init_linereset = false;
ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_ENTER);
dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d",
__func__, ret);
@@ -4084,8 +4316,7 @@
* If link recovery fails then return error so that caller
* don't retry the hibern8 enter again.
*/
- if (ufshcd_link_recovery(hba))
- ret = -ENOLINK;
+ ret = ufshcd_link_recovery(hba);
} else {
dev_dbg(hba->dev, "%s: Hibern8 Enter at %lld us", __func__,
ktime_to_us(ktime_get()));
@@ -4121,6 +4352,7 @@
trace_ufshcd_profile_hibern8(dev_name(hba->dev), "exit",
ktime_to_us(ktime_sub(ktime_get(), start)), ret);
+ /* Do full reinit if exit failed */
if (ret) {
ufshcd_update_error_stats(hba, UFS_ERR_HIBERN8_EXIT);
dev_err(hba->dev, "%s: hibern8 exit failed. ret = %d",
@@ -4642,6 +4874,7 @@
out:
if (ret)
dev_err(hba->dev, "link startup failed %d\n", ret);
+
return ret;
}
@@ -5023,7 +5256,12 @@
dev_err(hba->dev,
"OCS error from controller = %x for tag %d\n",
ocs, lrbp->task_tag);
- ufshcd_print_host_regs(hba);
+ /*
+ * This is called in interrupt context, hence avoid sleep
+ * while printing debug registers. Also print only the minimum
+ * debug registers needed to debug OCS failure.
+ */
+ __ufshcd_print_host_regs(hba, true);
ufshcd_print_host_state(hba);
break;
} /* end of switch */
@@ -5045,19 +5283,48 @@
* ufshcd_uic_cmd_compl - handle completion of uic command
* @hba: per adapter instance
* @intr_status: interrupt status generated by the controller
+ *
+ * Returns
+ * IRQ_HANDLED - If interrupt is valid
+ * IRQ_NONE - If invalid interrupt
*/
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
+static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
{
+ irqreturn_t retval = IRQ_NONE;
+
if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
hba->active_uic_cmd->argument2 |=
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
ufshcd_get_dme_attr_val(hba);
complete(&hba->active_uic_cmd->done);
+ retval = IRQ_HANDLED;
}
- if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done)
- complete(hba->uic_async_done);
+ if (intr_status & UFSHCD_UIC_PWR_MASK) {
+ if (hba->uic_async_done) {
+ complete(hba->uic_async_done);
+ retval = IRQ_HANDLED;
+ } else if (ufshcd_is_auto_hibern8_supported(hba)) {
+ /*
+ * If uic_async_done flag is not set then this
+ * is an Auto hibern8 err interrupt.
+ * Perform a host reset followed by a full
+ * link recovery.
+ */
+ hba->ufshcd_state = UFSHCD_STATE_ERROR;
+ hba->force_host_reset = true;
+ dev_err(hba->dev, "%s: Auto Hibern8 %s failed - status: 0x%08x, upmcrs: 0x%08x\n",
+ __func__, (intr_status & UIC_HIBERNATE_ENTER) ?
+ "Enter" : "Exit",
+ intr_status, ufshcd_get_upmcrs(hba));
+ __ufshcd_print_host_regs(hba, true);
+ ufshcd_print_host_state(hba);
+ schedule_work(&hba->eh_work);
+ retval = IRQ_HANDLED;
+ }
+ }
+ return retval;
}
/**
@@ -5201,8 +5468,12 @@
/**
* ufshcd_transfer_req_compl - handle SCSI and query command completion
* @hba: per adapter instance
+ *
+ * Returns
+ * IRQ_HANDLED - If interrupt is valid
+ * IRQ_NONE - If invalid interrupt
*/
-static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
+static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba)
{
unsigned long completed_reqs;
u32 tr_doorbell;
@@ -5220,7 +5491,12 @@
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
completed_reqs = tr_doorbell ^ hba->outstanding_reqs;
- __ufshcd_transfer_req_compl(hba, completed_reqs);
+ if (completed_reqs) {
+ __ufshcd_transfer_req_compl(hba, completed_reqs);
+ return IRQ_HANDLED;
+ } else {
+ return IRQ_NONE;
+ }
}
/**
@@ -5637,17 +5913,32 @@
int err = 0;
int tag;
bool needs_reset = false;
+ bool clks_enabled = false;
hba = container_of(work, struct ufs_hba, eh_work);
- ufsdbg_set_err_state(hba);
- pm_runtime_get_sync(hba->dev);
- ufshcd_hold_all(hba);
-
spin_lock_irqsave(hba->host->host_lock, flags);
+ ufsdbg_set_err_state(hba);
+
if (hba->ufshcd_state == UFSHCD_STATE_RESET)
goto out;
+ /*
+ * Make sure the clocks are ON before we proceed with err
+ * handling. For the majority of cases err handler would be
+ * run with clocks ON. There is a possibility that the err
+ * handler was scheduled due to auto hibern8 error interrupt,
+ * in which case the clocks could be gated or be in the
+ * process of gating when the err handler runs.
+ */
+ if (unlikely((hba->clk_gating.state != CLKS_ON) &&
+ ufshcd_is_auto_hibern8_supported(hba))) {
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ ufshcd_hold(hba, false);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ clks_enabled = true;
+ }
+
hba->ufshcd_state = UFSHCD_STATE_RESET;
ufshcd_set_eh_in_progress(hba);
@@ -5674,14 +5965,18 @@
dev_err(hba->dev, "%s: saved_err 0x%x saved_uic_err 0x%x",
__func__, hba->saved_err, hba->saved_uic_err);
if (!hba->silence_err_logs) {
+ /* release lock as print host regs sleeps */
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
ufshcd_print_host_regs(hba);
ufshcd_print_host_state(hba);
ufshcd_print_pwr_info(hba);
ufshcd_print_tmrs(hba, hba->outstanding_tasks);
+ spin_lock_irqsave(hba->host->host_lock, flags);
}
}
- if ((hba->saved_err & INT_FATAL_ERRORS) || hba->saved_ce_err ||
+ if ((hba->saved_err & INT_FATAL_ERRORS)
+ || hba->saved_ce_err || hba->force_host_reset ||
((hba->saved_err & UIC_ERROR) &&
(hba->saved_uic_err & (UFSHCD_UIC_DL_PA_INIT_ERROR |
UFSHCD_UIC_DL_NAC_RECEIVED_ERROR |
@@ -5769,6 +6064,7 @@
hba->saved_err = 0;
hba->saved_uic_err = 0;
hba->saved_ce_err = 0;
+ hba->force_host_reset = false;
}
skip_err_handling:
@@ -5780,12 +6076,12 @@
}
hba->silence_err_logs = false;
- ufshcd_clear_eh_in_progress(hba);
+
+ if (clks_enabled)
+ __ufshcd_release(hba, false);
out:
+ ufshcd_clear_eh_in_progress(hba);
spin_unlock_irqrestore(hba->host->host_lock, flags);
- ufshcd_scsi_unblock_requests(hba);
- ufshcd_release_all(hba);
- pm_runtime_put_sync(hba->dev);
}
static void ufshcd_update_uic_reg_hist(struct ufs_uic_err_reg_hist *reg_hist,
@@ -5799,16 +6095,20 @@
/**
* ufshcd_update_uic_error - check and set fatal UIC error flags.
* @hba: per-adapter instance
+ *
+ * Returns
+ * IRQ_HANDLED - If interrupt is valid
+ * IRQ_NONE - If invalid interrupt
*/
-static void ufshcd_update_uic_error(struct ufs_hba *hba)
+static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba)
{
u32 reg;
+ irqreturn_t retval = IRQ_NONE;
/* PHY layer lane error */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER);
- /* Ignore LINERESET indication, as this is not an error */
if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) &&
- (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) {
+ (reg & UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK)) {
/*
* To know whether this error is fatal or not, DB timeout
* must be checked but this error is handled separately.
@@ -5816,61 +6116,95 @@
dev_dbg(hba->dev, "%s: UIC Lane error reported, reg 0x%x\n",
__func__, reg);
ufshcd_update_uic_reg_hist(&hba->ufs_stats.pa_err, reg);
+
+ /*
+ * Don't ignore LINERESET indication during hibern8
+ * enter operation.
+ */
+ if (reg & UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR) {
+ struct uic_command *cmd = hba->active_uic_cmd;
+
+ if (cmd) {
+ if (cmd->command == UIC_CMD_DME_HIBER_ENTER) {
+ dev_err(hba->dev, "%s: LINERESET during hibern8 enter, reg 0x%x\n",
+ __func__, reg);
+ hba->full_init_linereset = true;
+ }
+ }
+ }
+ retval |= IRQ_HANDLED;
}
/* PA_INIT_ERROR is fatal and needs UIC reset */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER);
- if (reg)
+ if ((reg & UIC_DATA_LINK_LAYER_ERROR) &&
+ (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) {
ufshcd_update_uic_reg_hist(&hba->ufs_stats.dl_err, reg);
- if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) {
- hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
- } else if (hba->dev_info.quirks &
- UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
- if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED)
- hba->uic_error |=
- UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
- else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT)
- hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR;
+ if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) {
+ hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR;
+ } else if (hba->dev_info.quirks &
+ UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) {
+ if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED)
+ hba->uic_error |=
+ UFSHCD_UIC_DL_NAC_RECEIVED_ERROR;
+ else if (reg &
+ UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT)
+ hba->uic_error |=
+ UFSHCD_UIC_DL_TCx_REPLAY_ERROR;
+ }
+ retval |= IRQ_HANDLED;
}
/* UIC NL/TL/DME errors needs software retry */
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER);
- if (reg) {
+ if ((reg & UIC_NETWORK_LAYER_ERROR) &&
+ (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) {
ufshcd_update_uic_reg_hist(&hba->ufs_stats.nl_err, reg);
hba->uic_error |= UFSHCD_UIC_NL_ERROR;
+ retval |= IRQ_HANDLED;
}
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER);
- if (reg) {
+ if ((reg & UIC_TRANSPORT_LAYER_ERROR) &&
+ (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) {
ufshcd_update_uic_reg_hist(&hba->ufs_stats.tl_err, reg);
hba->uic_error |= UFSHCD_UIC_TL_ERROR;
+ retval |= IRQ_HANDLED;
}
reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME);
- if (reg) {
+ if ((reg & UIC_DME_ERROR) &&
+ (reg & UIC_DME_ERROR_CODE_MASK)) {
ufshcd_update_uic_reg_hist(&hba->ufs_stats.dme_err, reg);
hba->uic_error |= UFSHCD_UIC_DME_ERROR;
+ retval |= IRQ_HANDLED;
}
dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n",
__func__, hba->uic_error);
+ return retval;
}
/**
* ufshcd_check_errors - Check for errors that need s/w attention
* @hba: per-adapter instance
+ *
+ * Returns
+ * IRQ_HANDLED - If interrupt is valid
+ * IRQ_NONE - If invalid interrupt
*/
-static void ufshcd_check_errors(struct ufs_hba *hba)
+static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba)
{
bool queue_eh_work = false;
+ irqreturn_t retval = IRQ_NONE;
if (hba->errors & INT_FATAL_ERRORS || hba->ce_error)
queue_eh_work = true;
if (hba->errors & UIC_ERROR) {
hba->uic_error = 0;
- ufshcd_update_uic_error(hba);
+ retval = ufshcd_update_uic_error(hba);
if (hba->uic_error)
queue_eh_work = true;
}
@@ -5886,12 +6220,16 @@
/* handle fatal errors only when link is functional */
if (hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) {
- /* block commands from scsi mid-layer */
- __ufshcd_scsi_block_requests(hba);
+ /*
+ * Set error handling in progress flag early so that we
+ * don't issue new requests any more.
+ */
+ ufshcd_set_eh_in_progress(hba);
hba->ufshcd_state = UFSHCD_STATE_ERROR;
schedule_work(&hba->eh_work);
}
+ retval |= IRQ_HANDLED;
}
/*
* if (!queue_eh_work) -
@@ -5899,28 +6237,44 @@
* itself without s/w intervention or errors that will be
* handled by the SCSI core layer.
*/
+ return retval;
}
/**
* ufshcd_tmc_handler - handle task management function completion
* @hba: per adapter instance
+ *
+ * Returns
+ * IRQ_HANDLED - If interrupt is valid
+ * IRQ_NONE - If invalid interrupt
*/
-static void ufshcd_tmc_handler(struct ufs_hba *hba)
+static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba)
{
u32 tm_doorbell;
tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks;
- wake_up(&hba->tm_wq);
+ if (hba->tm_condition) {
+ wake_up(&hba->tm_wq);
+ return IRQ_HANDLED;
+ } else {
+ return IRQ_NONE;
+ }
}
/**
* ufshcd_sl_intr - Interrupt service routine
* @hba: per adapter instance
* @intr_status: contains interrupts generated by the controller
+ *
+ * Returns
+ * IRQ_HANDLED - If interrupt is valid
+ * IRQ_NONE - If invalid interrupt
*/
-static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
+static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
{
+ irqreturn_t retval = IRQ_NONE;
+
ufsdbg_error_inject_dispatcher(hba,
ERR_INJECT_INTR, intr_status, &intr_status);
@@ -5928,16 +6282,18 @@
hba->errors = UFSHCD_ERROR_MASK & intr_status;
if (hba->errors || hba->ce_error)
- ufshcd_check_errors(hba);
+ retval |= ufshcd_check_errors(hba);
if (intr_status & UFSHCD_UIC_MASK)
- ufshcd_uic_cmd_compl(hba, intr_status);
+ retval |= ufshcd_uic_cmd_compl(hba, intr_status);
if (intr_status & UTP_TASK_REQ_COMPL)
- ufshcd_tmc_handler(hba);
+ retval |= ufshcd_tmc_handler(hba);
if (intr_status & UTP_TRANSFER_REQ_COMPL)
- ufshcd_transfer_req_compl(hba);
+ retval |= ufshcd_transfer_req_compl(hba);
+
+ return retval;
}
/**
@@ -5945,27 +6301,44 @@
* @irq: irq number
* @__hba: pointer to adapter instance
*
- * Returns IRQ_HANDLED - If interrupt is valid
- * IRQ_NONE - If invalid interrupt
+ * Returns
+ * IRQ_HANDLED - If interrupt is valid
+ * IRQ_NONE - If invalid interrupt
*/
static irqreturn_t ufshcd_intr(int irq, void *__hba)
{
u32 intr_status, enabled_intr_status;
irqreturn_t retval = IRQ_NONE;
struct ufs_hba *hba = __hba;
+ int retries = hba->nutrs;
spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
- enabled_intr_status =
- intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
- if (intr_status)
- ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+ /*
+ * There could be max of hba->nutrs reqs in flight and in worst case
+ * if the reqs get finished 1 by 1 after the interrupt status is
+ * read, make sure we handle them by checking the interrupt status
+ * again in a loop until we process all of the reqs before returning.
+ */
+ do {
+ enabled_intr_status =
+ intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+ if (intr_status)
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+ if (enabled_intr_status)
+ retval |= ufshcd_sl_intr(hba, enabled_intr_status);
- if (enabled_intr_status) {
- ufshcd_sl_intr(hba, enabled_intr_status);
- retval = IRQ_HANDLED;
+ intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+ } while (intr_status && --retries);
+
+ if (retval == IRQ_NONE) {
+ dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x\n",
+ __func__, intr_status);
+ ufshcd_hex_dump(hba, "host regs: ", hba->mmio_base,
+ UFSHCI_REG_SPACE_SIZE);
}
+
spin_unlock(hba->host->host_lock);
return retval;
}
@@ -6391,6 +6764,16 @@
int retries = MAX_HOST_RESET_RETRIES;
do {
+ err = ufshcd_vops_full_reset(hba);
+ if (err)
+ dev_warn(hba->dev, "%s: full reset returned %d\n",
+ __func__, err);
+
+ err = ufshcd_reset_device(hba);
+ if (err)
+ dev_warn(hba->dev, "%s: device reset failed. err %d\n",
+ __func__, err);
+
err = ufshcd_host_reset_and_restore(hba);
} while (err && --retries);
@@ -6420,13 +6803,12 @@
*/
static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd)
{
- int err;
+ int err = SUCCESS;
unsigned long flags;
struct ufs_hba *hba;
hba = shost_priv(cmd->device->host);
- ufshcd_hold_all(hba);
/*
* Check if there is any race with fatal error handling.
* If so, wait for it to complete. Even though fatal error
@@ -6439,29 +6821,37 @@
hba->ufshcd_state == UFSHCD_STATE_RESET))
break;
spin_unlock_irqrestore(hba->host->host_lock, flags);
- dev_dbg(hba->dev, "%s: reset in progress\n", __func__);
+ dev_err(hba->dev, "%s: reset in progress - 1\n", __func__);
flush_work(&hba->eh_work);
} while (1);
- hba->ufshcd_state = UFSHCD_STATE_RESET;
- ufshcd_set_eh_in_progress(hba);
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ /*
+ * we don't know if previous reset had really reset the host controller
+ * or not. So let's force reset here to be sure.
+ */
+ hba->ufshcd_state = UFSHCD_STATE_ERROR;
+ hba->force_host_reset = true;
+ schedule_work(&hba->eh_work);
- ufshcd_update_error_stats(hba, UFS_ERR_EH);
- err = ufshcd_reset_and_restore(hba);
+ /* wait for the reset work to finish */
+ do {
+ if (!(work_pending(&hba->eh_work) ||
+ hba->ufshcd_state == UFSHCD_STATE_RESET))
+ break;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ dev_err(hba->dev, "%s: reset in progress - 2\n", __func__);
+ flush_work(&hba->eh_work);
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ } while (1);
- spin_lock_irqsave(hba->host->host_lock, flags);
- if (!err) {
- err = SUCCESS;
- hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL;
- } else {
+ if (!((hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) &&
+ ufshcd_is_link_active(hba))) {
err = FAILED;
hba->ufshcd_state = UFSHCD_STATE_ERROR;
}
- ufshcd_clear_eh_in_progress(hba);
+
spin_unlock_irqrestore(hba->host->host_lock, flags);
- ufshcd_release_all(hba);
return err;
}
@@ -6978,11 +7368,6 @@
if (ret)
goto out;
- /* Enable auto hibern8 if supported */
- if (ufshcd_is_auto_hibern8_supported(hba))
- ufshcd_set_auto_hibern8_timer(hba,
- hba->hibern8_on_idle.delay_ms);
-
/* Debug counters initialization */
ufshcd_clear_dbg_ufs_stats(hba);
/* set the default level for urgent bkops */
@@ -7064,20 +7449,38 @@
if (ufshcd_scsi_add_wlus(hba))
goto out;
+ /* Initialize devfreq after UFS device is detected */
+ if (ufshcd_is_clkscaling_supported(hba)) {
+ memcpy(&hba->clk_scaling.saved_pwr_info.info,
+ &hba->pwr_info, sizeof(struct ufs_pa_layer_attr));
+ hba->clk_scaling.saved_pwr_info.is_valid = true;
+ hba->clk_scaling.is_scaled_up = true;
+ if (!hba->devfreq) {
+ hba->devfreq = devfreq_add_device(hba->dev,
+ &ufs_devfreq_profile,
+ "simple_ondemand",
+ gov_data);
+ if (IS_ERR(hba->devfreq)) {
+ ret = PTR_ERR(hba->devfreq);
+ dev_err(hba->dev, "Unable to register with devfreq %d\n",
+ ret);
+ goto out;
+ }
+ }
+ hba->clk_scaling.is_allowed = true;
+ }
+
scsi_scan_host(hba->host);
pm_runtime_put_sync(hba->dev);
}
- /* Resume devfreq after UFS device is detected */
- if (ufshcd_is_clkscaling_supported(hba)) {
- memcpy(&hba->clk_scaling.saved_pwr_info.info, &hba->pwr_info,
- sizeof(struct ufs_pa_layer_attr));
- hba->clk_scaling.saved_pwr_info.is_valid = true;
- hba->clk_scaling.is_scaled_up = true;
- ufshcd_resume_clkscaling(hba);
- hba->clk_scaling.is_allowed = true;
- }
-
+ /*
+ * Enable auto hibern8 if supported, after full host and
+ * device initialization.
+ */
+ if (ufshcd_is_auto_hibern8_supported(hba))
+ ufshcd_set_auto_hibern8_timer(hba,
+ hba->hibern8_on_idle.delay_ms);
out:
/*
* If we failed to initialize the device or the device is not
@@ -7670,6 +8073,13 @@
if (!head || list_empty(head))
goto out;
+ /* call vendor specific bus vote before enabling the clocks */
+ if (on) {
+ ret = ufshcd_vops_set_bus_vote(hba, on);
+ if (ret)
+ return ret;
+ }
+
/*
* vendor specific setup_clocks ops may depend on clocks managed by
* this standard driver hence call the vendor specific setup_clocks
@@ -7708,11 +8118,24 @@
* this standard driver hence call the vendor specific setup_clocks
* after enabling the clocks managed here.
*/
- if (on)
+ if (on) {
ret = ufshcd_vops_setup_clocks(hba, on, is_gating_context);
+ if (ret)
+ goto out;
+ }
+
+ /*
+ * call vendor specific bus vote to remove the vote after
+ * disabling the clocks.
+ */
+ if (!on)
+ ret = ufshcd_vops_set_bus_vote(hba, on);
out:
if (ret) {
+ if (on)
+ /* Can't do much if this fails */
+ (void) ufshcd_vops_set_bus_vote(hba, false);
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
clk_disable_unprepare(clki->clk);
@@ -7884,7 +8307,8 @@
ufshcd_variant_hba_exit(hba);
ufshcd_setup_vreg(hba, false);
if (ufshcd_is_clkscaling_supported(hba)) {
- ufshcd_suspend_clkscaling(hba);
+ if (hba->devfreq)
+ ufshcd_suspend_clkscaling(hba);
destroy_workqueue(hba->clk_scaling.workq);
}
ufshcd_disable_clocks(hba, false);
@@ -8335,9 +8759,13 @@
goto vendor_suspend;
}
} else if (ufshcd_is_link_off(hba)) {
- ret = ufshcd_host_reset_and_restore(hba);
/*
- * ufshcd_host_reset_and_restore() should have already
+ * A full initialization of the host and the device is required
+ * since the link was put to off during suspend.
+ */
+ ret = ufshcd_reset_and_restore(hba);
+ /*
+ * ufshcd_reset_and_restore() should have already
* set the link state as active
*/
if (ret || !ufshcd_is_link_active(hba))
@@ -8676,6 +9104,35 @@
ufshcd_add_spm_lvl_sysfs_nodes(hba);
}
+static void ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
+{
+ bool suspend = false;
+ unsigned long flags;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ if (hba->clk_scaling.is_allowed) {
+ hba->clk_scaling.is_allowed = false;
+ suspend = true;
+ }
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ /**
+ * Scaling may be scheduled before, hence make sure it
+ * doesn't race with shutdown
+ */
+ if (ufshcd_is_clkscaling_supported(hba)) {
+ device_remove_file(hba->dev, &hba->clk_scaling.enable_attr);
+ cancel_work_sync(&hba->clk_scaling.suspend_work);
+ cancel_work_sync(&hba->clk_scaling.resume_work);
+ if (suspend)
+ ufshcd_suspend_clkscaling(hba);
+ }
+
+ /* Unregister so that devfreq_monitor can't race with shutdown */
+ if (hba->devfreq)
+ devfreq_remove_device(hba->devfreq);
+}
+
/**
* ufshcd_shutdown - shutdown routine
* @hba: per adapter instance
@@ -8686,11 +9143,35 @@
*/
int ufshcd_shutdown(struct ufs_hba *hba)
{
- /*
- * TODO: This function should send the power down notification to
- * UFS device and then power off the UFS link. But we need to be sure
- * that there will not be any new UFS requests issued after this.
+ int ret = 0;
+
+ if (ufshcd_is_ufs_dev_poweroff(hba) && ufshcd_is_link_off(hba))
+ goto out;
+
+ pm_runtime_get_sync(hba->dev);
+ ufshcd_hold_all(hba);
+ ufshcd_mark_shutdown_ongoing(hba);
+ ufshcd_shutdown_clkscaling(hba);
+ /**
+ * (1) Acquire the lock to stop any more requests
+ * (2) Wait for all issued requests to complete
*/
+ ufshcd_get_write_lock(hba);
+ ufshcd_scsi_block_requests(hba);
+ ret = ufshcd_wait_for_doorbell_clr(hba, U64_MAX);
+ if (ret)
+ dev_err(hba->dev, "%s: waiting for DB clear: failed: %d\n",
+ __func__, ret);
+ /* Requests may have errored out above, let it be handled */
+ flush_work(&hba->eh_work);
+ /* reqs issued from contexts other than shutdown will fail from now */
+ ufshcd_scsi_unblock_requests(hba);
+ ufshcd_release_all(hba);
+ ret = ufshcd_suspend(hba, UFS_SHUTDOWN_PM);
+out:
+ if (ret)
+ dev_err(hba->dev, "%s failed, err %d\n", __func__, ret);
+ /* allow force shutdown even in case of errors */
return 0;
}
EXPORT_SYMBOL(ufshcd_shutdown);
@@ -8886,6 +9367,32 @@
if (scale_up) {
memcpy(&new_pwr_info, &hba->clk_scaling.saved_pwr_info.info,
sizeof(struct ufs_pa_layer_attr));
+ /*
+ * Some UFS devices may stop responding after switching from
+ * HS-G1 to HS-G3. Also, it is found that these devices work
+ * fine if we do 2 steps switch: HS-G1 to HS-G2 followed by
+ * HS-G2 to HS-G3. If UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH
+ * quirk is enabled for such devices, this 2 steps gear switch
+ * workaround will be applied.
+ */
+ if ((hba->dev_info.quirks &
+ UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH)
+ && (hba->pwr_info.gear_tx == UFS_HS_G1)
+ && (new_pwr_info.gear_tx == UFS_HS_G3)) {
+ /* scale up to G2 first */
+ new_pwr_info.gear_tx = UFS_HS_G2;
+ new_pwr_info.gear_rx = UFS_HS_G2;
+ ret = ufshcd_change_power_mode(hba, &new_pwr_info);
+ if (ret)
+ goto out;
+
+ /* scale up to G3 now */
+ new_pwr_info.gear_tx = UFS_HS_G3;
+ new_pwr_info.gear_rx = UFS_HS_G3;
+ ret = ufshcd_change_power_mode(hba, &new_pwr_info);
+ if (ret)
+ goto out;
+ }
} else {
memcpy(&new_pwr_info, &hba->pwr_info,
sizeof(struct ufs_pa_layer_attr));
@@ -8905,10 +9412,10 @@
new_pwr_info.pwr_rx = FASTAUTO_MODE;
}
}
+ ret = ufshcd_change_power_mode(hba, &new_pwr_info);
}
- ret = ufshcd_change_power_mode(hba, &new_pwr_info);
-
+out:
if (ret)
dev_err(hba->dev, "%s: failed err %d, old gear: (tx %d rx %d), new gear: (tx %d rx %d), scale_up = %d",
__func__, ret,
@@ -8928,10 +9435,10 @@
* clock scaling is in progress
*/
ufshcd_scsi_block_requests(hba);
- down_write(&hba->clk_scaling_lock);
+ down_write(&hba->lock);
if (ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US)) {
ret = -EBUSY;
- up_write(&hba->clk_scaling_lock);
+ up_write(&hba->lock);
ufshcd_scsi_unblock_requests(hba);
}
@@ -8940,7 +9447,7 @@
static void ufshcd_clock_scaling_unprepare(struct ufs_hba *hba)
{
- up_write(&hba->clk_scaling_lock);
+ up_write(&hba->lock);
ufshcd_scsi_unblock_requests(hba);
}
@@ -8971,10 +9478,29 @@
goto clk_scaling_unprepare;
}
+ /*
+ * If auto hibern8 is supported then put the link in
+ * hibern8 manually, this is to avoid auto hibern8
+ * racing during clock frequency scaling sequence.
+ */
+ if (ufshcd_is_auto_hibern8_supported(hba)) {
+ ret = ufshcd_uic_hibern8_enter(hba);
+ if (ret)
+ /* link will be bad state so no need to scale_up_gear */
+ return ret;
+ }
+
ret = ufshcd_scale_clks(hba, scale_up);
if (ret)
goto scale_up_gear;
+ if (ufshcd_is_auto_hibern8_supported(hba)) {
+ ret = ufshcd_uic_hibern8_exit(hba);
+ if (ret)
+ /* link will be bad state so no need to scale_up_gear */
+ return ret;
+ }
+
/* scale up the gear after scaling up clocks */
if (scale_up) {
ret = ufshcd_scale_gear(hba, true);
@@ -9220,23 +9746,6 @@
return 0;
}
-#if IS_ENABLED(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND)
-static struct devfreq_simple_ondemand_data ufshcd_ondemand_data = {
- .upthreshold = 35,
- .downdifferential = 30,
- .simple_scaling = 1,
-};
-
-static void *gov_data = &ufshcd_ondemand_data;
-#else
-static void *gov_data;
-#endif
-
-static struct devfreq_dev_profile ufs_devfreq_profile = {
- .polling_ms = 40,
- .target = ufshcd_devfreq_target,
- .get_dev_status = ufshcd_devfreq_get_dev_status,
-};
static void ufshcd_clkscaling_init_sysfs(struct ufs_hba *hba)
{
hba->clk_scaling.enable_attr.show = ufshcd_clkscale_enable_show;
@@ -9352,7 +9861,7 @@
/* Initialize mutex for device management commands */
mutex_init(&hba->dev_cmd.lock);
- init_rwsem(&hba->clk_scaling_lock);
+ init_rwsem(&hba->lock);
/* Initialize device management tag acquire wait queue */
init_waitqueue_head(&hba->dev_cmd.tag_wq);
@@ -9389,6 +9898,15 @@
goto exit_gating;
}
+ /* Reset controller to power on reset (POR) state */
+ ufshcd_vops_full_reset(hba);
+
+ /* reset connected UFS device */
+ err = ufshcd_reset_device(hba);
+ if (err)
+ dev_warn(hba->dev, "%s: device reset failed. err %d\n",
+ __func__, err);
+
/* Host controller enable */
err = ufshcd_hba_enable(hba);
if (err) {
@@ -9401,16 +9919,6 @@
if (ufshcd_is_clkscaling_supported(hba)) {
char wq_name[sizeof("ufs_clkscaling_00")];
- hba->devfreq = devfreq_add_device(dev, &ufs_devfreq_profile,
- "simple_ondemand", gov_data);
- if (IS_ERR(hba->devfreq)) {
- dev_err(hba->dev, "Unable to register with devfreq %ld\n",
- PTR_ERR(hba->devfreq));
- err = PTR_ERR(hba->devfreq);
- goto out_remove_scsi_host;
- }
- hba->clk_scaling.is_suspended = false;
-
INIT_WORK(&hba->clk_scaling.suspend_work,
ufshcd_clk_scaling_suspend_work);
INIT_WORK(&hba->clk_scaling.resume_work,
@@ -9420,8 +9928,6 @@
host->host_no);
hba->clk_scaling.workq = create_singlethread_workqueue(wq_name);
- /* Suspend devfreq until the UFS device is detected */
- ufshcd_suspend_clkscaling(hba);
ufshcd_clkscaling_init_sysfs(hba);
}
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 709801f..b70606b 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -3,7 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.h
* Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -39,6 +39,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -55,6 +56,7 @@
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
#include "unipro.h"
#include <asm/irq.h>
@@ -309,6 +311,7 @@
* @update_sec_cfg: called to restore host controller secure configuration
* @get_scale_down_gear: called to get the minimum supported gear to
* scale down
+ * @set_bus_vote: called to vote for the required bus bandwidth
* @add_debugfs: used to add debugfs entries
* @remove_debugfs: used to remove debugfs entries
*/
@@ -332,9 +335,10 @@
int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
int (*full_reset)(struct ufs_hba *);
- void (*dbg_register_dump)(struct ufs_hba *hba);
+ void (*dbg_register_dump)(struct ufs_hba *hba, bool no_sleep);
int (*update_sec_cfg)(struct ufs_hba *hba, bool restore_sec_cfg);
u32 (*get_scale_down_gear)(struct ufs_hba *);
+ int (*set_bus_vote)(struct ufs_hba *, bool);
#ifdef CONFIG_DEBUG_FS
void (*add_debugfs)(struct ufs_hba *hba, struct dentry *root);
void (*remove_debugfs)(struct ufs_hba *hba);
@@ -393,8 +397,9 @@
/**
* struct ufs_clk_gating - UFS clock gating related info
- * @gate_work: worker to turn off clocks after some delay as specified in
- * delay_ms
+ * @gate_hrtimer: hrtimer to invoke @gate_work after some delay as
+ * specified in @delay_ms
+ * @gate_work: worker to turn off clocks
* @ungate_work: worker to turn on clocks that will be used in case of
* interrupt context
* @state: the current clocks state
@@ -412,7 +417,8 @@
* completion before gating clocks.
*/
struct ufs_clk_gating {
- struct delayed_work gate_work;
+ struct hrtimer gate_hrtimer;
+ struct work_struct gate_work;
struct work_struct ungate_work;
enum clk_gating_state state;
unsigned long delay_ms;
@@ -425,6 +431,7 @@
struct device_attribute enable_attr;
bool is_enabled;
int active_reqs;
+ struct workqueue_struct *ungating_workq;
};
/* Hibern8 state */
@@ -801,6 +808,7 @@
u32 saved_uic_err;
u32 saved_ce_err;
bool silence_err_logs;
+ bool force_host_reset;
/* Device management request data */
struct ufs_dev_cmd dev_cmd;
@@ -882,17 +890,33 @@
enum bkops_status urgent_bkops_lvl;
bool is_urgent_bkops_lvl_checked;
- struct rw_semaphore clk_scaling_lock;
+ /* sync b/w diff contexts */
+ struct rw_semaphore lock;
+ unsigned long shutdown_in_prog;
+ struct reset_control *core_reset;
/* If set, don't gate device ref_clk during clock gating */
bool no_ref_clk_gating;
int scsi_block_reqs_cnt;
+ bool full_init_linereset;
+ struct pinctrl *pctrl;
+
int latency_hist_enabled;
struct io_latency_state io_lat_s;
};
+static inline void ufshcd_mark_shutdown_ongoing(struct ufs_hba *hba)
+{
+ set_bit(0, &hba->shutdown_in_prog);
+}
+
+static inline bool ufshcd_is_shutdown_ongoing(struct ufs_hba *hba)
+{
+ return !!(test_bit(0, &hba->shutdown_in_prog));
+}
+
/* Returns true if clocks can be gated. Otherwise false */
static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba)
{
@@ -1233,10 +1257,11 @@
}
-static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
+static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba,
+ bool no_sleep)
{
if (hba->var && hba->var->vops && hba->var->vops->dbg_register_dump)
- hba->var->vops->dbg_register_dump(hba);
+ hba->var->vops->dbg_register_dump(hba, no_sleep);
}
static inline int ufshcd_vops_update_sec_cfg(struct ufs_hba *hba,
@@ -1255,6 +1280,13 @@
return UFS_HS_G1;
}
+static inline int ufshcd_vops_set_bus_vote(struct ufs_hba *hba, bool on)
+{
+ if (hba->var && hba->var->vops && hba->var->vops->set_bus_vote)
+ return hba->var->vops->set_bus_vote(hba, on);
+ return 0;
+}
+
#ifdef CONFIG_DEBUG_FS
static inline void ufshcd_vops_add_debugfs(struct ufs_hba *hba,
struct dentry *root)
diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h
index d65dad0..c0e4650 100644
--- a/drivers/scsi/ufs/ufshci.h
+++ b/drivers/scsi/ufs/ufshci.h
@@ -190,6 +190,7 @@
/* UECPA - Host UIC Error Code PHY Adapter Layer 38h */
#define UIC_PHY_ADAPTER_LAYER_ERROR UFS_BIT(31)
+#define UIC_PHY_ADAPTER_LAYER_GENERIC_ERROR UFS_BIT(4)
#define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F
#define UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK 0xF
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index cf715e5..0f8d9b6 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -214,6 +214,15 @@
deadlocks. It does not run during the bootup process, so it will
not catch any early lockups.
+config QPNP_PBS
+ tristate "PBS trigger support for QPNP PMIC"
+ depends on SPMI
+ help
+ This driver supports configuring software PBS trigger event through PBS
+ RAM on Qualcomm Technologies, Inc. QPNP PMICs. This module provides
+ the APIs to the client drivers that wants to send the PBS trigger
+ event to the PBS RAM.
+
config QCOM_MEMORY_DUMP_V2
bool "QCOM Memory Dump V2 Support"
help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 45384668..00a1284 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -3,6 +3,7 @@
obj-$(CONFIG_QCOM_LLCC) += llcc-core.o llcc-slice.o
obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o
obj-$(CONFIG_QCOM_LLCC_AMON) += llcc-amon.o
+obj-$(CONFIG_QPNP_PBS) += qpnp-pbs.o
obj-$(CONFIG_QCOM_PM) += spm.o
obj-$(CONFIG_QCOM_SMD) += smd.o
obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
diff --git a/drivers/soc/qcom/avtimer.c b/drivers/soc/qcom/avtimer.c
index 04e351d..1819d46 100644
--- a/drivers/soc/qcom/avtimer.c
+++ b/drivers/soc/qcom/avtimer.c
@@ -64,6 +64,7 @@
void __iomem *p_avtimer_msw;
void __iomem *p_avtimer_lsw;
uint32_t clk_div;
+ uint32_t clk_mult;
atomic_t adsp_ready;
int num_retries;
};
@@ -292,7 +293,6 @@
int avcs_core_query_timer(uint64_t *avtimer_tick)
{
uint32_t avtimer_msw = 0, avtimer_lsw = 0;
- uint32_t res = 0;
uint64_t avtimer_tick_temp;
if (!atomic_read(&avtimer.adsp_ready)) {
@@ -302,13 +302,13 @@
avtimer_lsw = ioread32(avtimer.p_avtimer_lsw);
avtimer_msw = ioread32(avtimer.p_avtimer_msw);
- avtimer_tick_temp =
- (uint64_t)((uint64_t)avtimer_msw << 32)
- | avtimer_lsw;
- res = do_div(avtimer_tick_temp, avtimer.clk_div);
- *avtimer_tick = avtimer_tick_temp;
+ avtimer_tick_temp = (uint64_t)((uint64_t)avtimer_msw << 32)
+ | avtimer_lsw;
+ *avtimer_tick = mul_u64_u32_div(avtimer_tick_temp, avtimer.clk_mult,
+ avtimer.clk_div);
pr_debug_ratelimited("%s:Avtimer: msw: %u, lsw: %u, tick: %llu\n",
__func__,
+ avtimer_msw, avtimer_lsw, *avtimer_tick);
return 0;
}
EXPORT_SYMBOL(avcs_core_query_timer);
@@ -374,6 +374,7 @@
struct device *device_handle;
struct resource *reg_lsb = NULL, *reg_msb = NULL;
uint32_t clk_div_val;
+ uint32_t clk_mult_val;
if (!pdev) {
pr_err("%s: Invalid params\n", __func__);
@@ -462,7 +463,14 @@
else
avtimer.clk_div = clk_div_val;
- pr_debug("avtimer.clk_div = %d\n", avtimer.clk_div);
+ if (of_property_read_u32(pdev->dev.of_node,
+ "qcom,clk-mult", &clk_mult_val))
+ avtimer.clk_mult = 1;
+ else
+ avtimer.clk_mult = clk_mult_val;
+
+ pr_debug("%s: avtimer.clk_div = %d, avtimer.clk_mult = %d\n",
+ __func__, avtimer.clk_div, avtimer.clk_mult);
return 0;
class_destroy:
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 722127d..0b35caa 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -48,6 +48,11 @@
#include <soc/qcom/socinfo.h>
#include <soc/qcom/ramdump.h>
+#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC
+#include <net/cnss_prealloc.h>
+#endif
+
+
#include "wlan_firmware_service_v01.h"
#ifdef CONFIG_ICNSS_DEBUG
@@ -62,7 +67,7 @@
#define WLFW_CLIENT_ID 0x4b4e454c
#define MAX_PROP_SIZE 32
#define NUM_LOG_PAGES 10
-#define NUM_REG_LOG_PAGES 4
+#define NUM_LOG_LONG_PAGES 4
#define ICNSS_MAGIC 0x5abc5abc
#define ICNSS_SERVICE_LOCATION_CLIENT_NAME "ICNSS-WLAN"
@@ -77,14 +82,10 @@
ipc_log_string(icnss_ipc_log_context, _x); \
} while (0)
-#ifdef CONFIG_ICNSS_DEBUG
#define icnss_ipc_log_long_string(_x...) do { \
if (icnss_ipc_log_long_context) \
ipc_log_string(icnss_ipc_log_long_context, _x); \
} while (0)
-#else
-#define icnss_ipc_log_long_string(_x...)
-#endif
#define icnss_pr_err(_fmt, ...) do { \
pr_err(_fmt, ##__VA_ARGS__); \
@@ -110,28 +111,25 @@
##__VA_ARGS__); \
} while (0)
-#define icnss_reg_dbg(_fmt, ...) do { \
+#define icnss_pr_vdbg(_fmt, ...) do { \
pr_debug(_fmt, ##__VA_ARGS__); \
- icnss_ipc_log_long_string("REG: " pr_fmt(_fmt), \
+ icnss_ipc_log_long_string("DBG: " pr_fmt(_fmt), \
##__VA_ARGS__); \
} while (0)
#ifdef CONFIG_ICNSS_DEBUG
#define ICNSS_ASSERT(_condition) do { \
if (!(_condition)) { \
- icnss_pr_err("ASSERT at line %d\n", \
- __LINE__); \
+ icnss_pr_err("ASSERT at line %d\n", __LINE__); \
BUG_ON(1); \
} \
} while (0)
+
+bool ignore_qmi_timeout;
+#define ICNSS_QMI_ASSERT() ICNSS_ASSERT(ignore_qmi_timeout)
#else
-#define ICNSS_ASSERT(_condition) do { \
- if (!(_condition)) { \
- icnss_pr_err("ASSERT at line %d\n", \
- __LINE__); \
- WARN_ON(1); \
- } \
- } while (0)
+#define ICNSS_ASSERT(_condition) do { } while (0)
+#define ICNSS_QMI_ASSERT() do { } while (0)
#endif
enum icnss_debug_quirks {
@@ -156,10 +154,7 @@
module_param(dynamic_feature_mask, ullong, 0600);
void *icnss_ipc_log_context;
-
-#ifdef CONFIG_ICNSS_DEBUG
void *icnss_ipc_log_long_context;
-#endif
#define ICNSS_EVENT_PENDING 2989
@@ -181,6 +176,7 @@
struct icnss_event_pd_service_down_data {
bool crashed;
bool fw_rejuvenate;
+ bool wdog_bite;
};
struct icnss_driver_event {
@@ -205,6 +201,7 @@
ICNSS_PD_RESTART,
ICNSS_MSA0_ASSIGNED,
ICNSS_WLFW_EXISTS,
+ ICNSS_WDOG_BITE,
};
struct ce_irq_list {
@@ -212,6 +209,38 @@
irqreturn_t (*handler)(int, void *);
};
+struct icnss_vreg_info {
+ struct regulator *reg;
+ const char *name;
+ u32 min_v;
+ u32 max_v;
+ u32 load_ua;
+ unsigned long settle_delay;
+ bool required;
+};
+
+struct icnss_clk_info {
+ struct clk *handle;
+ const char *name;
+ u32 freq;
+ bool required;
+};
+
+static struct icnss_vreg_info icnss_vreg_info[] = {
+ {NULL, "vdd-0.8-cx-mx", 800000, 800000, 0, 0, false},
+ {NULL, "vdd-1.8-xo", 1800000, 1800000, 0, 0, false},
+ {NULL, "vdd-1.3-rfa", 1304000, 1304000, 0, 0, false},
+ {NULL, "vdd-3.3-ch0", 3312000, 3312000, 0, 0, false},
+};
+
+#define ICNSS_VREG_INFO_SIZE ARRAY_SIZE(icnss_vreg_info)
+
+static struct icnss_clk_info icnss_clk_info[] = {
+ {NULL, "cxo_ref_clk_pin", 0, false},
+};
+
+#define ICNSS_CLK_INFO_SIZE ARRAY_SIZE(icnss_clk_info)
+
struct icnss_stats {
struct {
uint32_t posted;
@@ -265,6 +294,7 @@
uint32_t rejuvenate_ack_req;
uint32_t rejuvenate_ack_resp;
uint32_t rejuvenate_ack_err;
+ uint32_t trigger_recovery;
};
#define MAX_NO_OF_MAC_ADDR 4
@@ -284,6 +314,8 @@
struct platform_device *pdev;
struct icnss_driver_ops *ops;
struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS];
+ struct icnss_vreg_info vreg_info[ICNSS_VREG_INFO_SIZE];
+ struct icnss_clk_info clk_info[ICNSS_CLK_INFO_SIZE];
u32 ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
phys_addr_t mem_base_pa;
void __iomem *mem_base_va;
@@ -310,8 +342,9 @@
u32 pwr_pin_result;
u32 phy_io_pin_result;
u32 rf_pin_result;
+ uint32_t nr_mem_region;
struct icnss_mem_region_info
- icnss_mem_region[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01];
+ mem_region[QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01];
struct dentry *root_dentry;
spinlock_t on_off_lock;
struct icnss_stats stats;
@@ -334,14 +367,24 @@
struct ramdump_device *msa0_dump_dev;
bool is_wlan_mac_set;
struct icnss_wlan_mac_addr wlan_mac_addr;
+ bool bypass_s1_smmu;
} *penv;
+#ifdef CONFIG_ICNSS_DEBUG
+static void icnss_ignore_qmi_timeout(bool ignore)
+{
+ ignore_qmi_timeout = ignore;
+}
+#else
+static void icnss_ignore_qmi_timeout(bool ignore) { }
+#endif
+
static void icnss_pm_stay_awake(struct icnss_priv *priv)
{
if (atomic_inc_return(&priv->pm_count) != 1)
return;
- icnss_pr_dbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
+ icnss_pr_vdbg("PM stay awake, state: 0x%lx, count: %d\n", priv->state,
atomic_read(&priv->pm_count));
pm_stay_awake(&priv->pdev->dev);
@@ -358,7 +401,7 @@
if (r != 0)
return;
- icnss_pr_dbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
+ icnss_pr_vdbg("PM relax, state: 0x%lx, count: %d\n", priv->state,
atomic_read(&priv->pm_count));
pm_relax(&priv->pdev->dev);
@@ -680,41 +723,220 @@
return ret;
}
+static int icnss_vreg_on(struct icnss_priv *priv)
+{
+ int ret = 0;
+ struct icnss_vreg_info *vreg_info;
+ int i;
+
+ for (i = 0; i < ICNSS_VREG_INFO_SIZE; i++) {
+ vreg_info = &priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ icnss_pr_vdbg("Regulator %s being enabled\n", vreg_info->name);
+
+ ret = regulator_set_voltage(vreg_info->reg, vreg_info->min_v,
+ vreg_info->max_v);
+ if (ret) {
+ icnss_pr_err("Regulator %s, can't set voltage: min_v: %u, max_v: %u, ret: %d\n",
+ vreg_info->name, vreg_info->min_v,
+ vreg_info->max_v, ret);
+ break;
+ }
+
+ if (vreg_info->load_ua) {
+ ret = regulator_set_load(vreg_info->reg,
+ vreg_info->load_ua);
+ if (ret < 0) {
+ icnss_pr_err("Regulator %s, can't set load: %u, ret: %d\n",
+ vreg_info->name,
+ vreg_info->load_ua, ret);
+ break;
+ }
+ }
+
+ ret = regulator_enable(vreg_info->reg);
+ if (ret) {
+ icnss_pr_err("Regulator %s, can't enable: %d\n",
+ vreg_info->name, ret);
+ break;
+ }
+
+ if (vreg_info->settle_delay)
+ udelay(vreg_info->settle_delay);
+ }
+
+ if (!ret)
+ return 0;
+
+ for (; i >= 0; i--) {
+ vreg_info = &priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ regulator_disable(vreg_info->reg);
+ regulator_set_load(vreg_info->reg, 0);
+ regulator_set_voltage(vreg_info->reg, 0, vreg_info->max_v);
+ }
+
+ return ret;
+}
+
+static int icnss_vreg_off(struct icnss_priv *priv)
+{
+ int ret = 0;
+ struct icnss_vreg_info *vreg_info;
+ int i;
+
+ for (i = ICNSS_VREG_INFO_SIZE - 1; i >= 0; i--) {
+ vreg_info = &priv->vreg_info[i];
+
+ if (!vreg_info->reg)
+ continue;
+
+ icnss_pr_vdbg("Regulator %s being disabled\n", vreg_info->name);
+
+ ret = regulator_disable(vreg_info->reg);
+ if (ret)
+ icnss_pr_err("Regulator %s, can't disable: %d\n",
+ vreg_info->name, ret);
+
+ ret = regulator_set_load(vreg_info->reg, 0);
+ if (ret < 0)
+ icnss_pr_err("Regulator %s, can't set load: %d\n",
+ vreg_info->name, ret);
+
+ ret = regulator_set_voltage(vreg_info->reg, 0,
+ vreg_info->max_v);
+ if (ret)
+ icnss_pr_err("Regulator %s, can't set voltage: %d\n",
+ vreg_info->name, ret);
+ }
+
+ return ret;
+}
+
+static int icnss_clk_init(struct icnss_priv *priv)
+{
+ struct icnss_clk_info *clk_info;
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+ clk_info = &priv->clk_info[i];
+
+ if (!clk_info->handle)
+ continue;
+
+ icnss_pr_vdbg("Clock %s being enabled\n", clk_info->name);
+
+ if (clk_info->freq) {
+ ret = clk_set_rate(clk_info->handle, clk_info->freq);
+
+ if (ret) {
+ icnss_pr_err("Clock %s, can't set frequency: %u, ret: %d\n",
+ clk_info->name, clk_info->freq,
+ ret);
+ break;
+ }
+ }
+
+ ret = clk_prepare_enable(clk_info->handle);
+ if (ret) {
+ icnss_pr_err("Clock %s, can't enable: %d\n",
+ clk_info->name, ret);
+ break;
+ }
+ }
+
+ if (ret == 0)
+ return 0;
+
+ for (; i >= 0; i--) {
+ clk_info = &priv->clk_info[i];
+
+ if (!clk_info->handle)
+ continue;
+
+ clk_disable_unprepare(clk_info->handle);
+ }
+
+ return ret;
+}
+
+static int icnss_clk_deinit(struct icnss_priv *priv)
+{
+ struct icnss_clk_info *clk_info;
+ int i;
+
+ for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+ clk_info = &priv->clk_info[i];
+
+ if (!clk_info->handle)
+ continue;
+
+ icnss_pr_vdbg("Clock %s being disabled\n", clk_info->name);
+
+ clk_disable_unprepare(clk_info->handle);
+ }
+
+ return 0;
+}
+
static int icnss_hw_power_on(struct icnss_priv *priv)
{
int ret = 0;
- unsigned long flags;
icnss_pr_dbg("HW Power on: state: 0x%lx\n", priv->state);
- spin_lock_irqsave(&priv->on_off_lock, flags);
+ spin_lock(&priv->on_off_lock);
if (test_bit(ICNSS_POWER_ON, &priv->state)) {
- spin_unlock_irqrestore(&priv->on_off_lock, flags);
+ spin_unlock(&priv->on_off_lock);
return ret;
}
set_bit(ICNSS_POWER_ON, &priv->state);
- spin_unlock_irqrestore(&priv->on_off_lock, flags);
+ spin_unlock(&priv->on_off_lock);
+ ret = icnss_vreg_on(priv);
+ if (ret)
+ goto out;
+
+ ret = icnss_clk_init(priv);
+ if (ret)
+ goto vreg_off;
+
+ return ret;
+
+vreg_off:
+ icnss_vreg_off(priv);
+out:
+ clear_bit(ICNSS_POWER_ON, &priv->state);
return ret;
}
static int icnss_hw_power_off(struct icnss_priv *priv)
{
int ret = 0;
- unsigned long flags;
if (test_bit(HW_ALWAYS_ON, &quirks))
return 0;
icnss_pr_dbg("HW Power off: 0x%lx\n", priv->state);
- spin_lock_irqsave(&priv->on_off_lock, flags);
+ spin_lock(&priv->on_off_lock);
if (!test_bit(ICNSS_POWER_ON, &priv->state)) {
- spin_unlock_irqrestore(&priv->on_off_lock, flags);
+ spin_unlock(&priv->on_off_lock);
return ret;
}
clear_bit(ICNSS_POWER_ON, &priv->state);
- spin_unlock_irqrestore(&priv->on_off_lock, flags);
+ spin_unlock(&priv->on_off_lock);
+
+ icnss_clk_deinit(priv);
+
+ ret = icnss_vreg_off(priv);
return ret;
}
@@ -760,7 +982,7 @@
}
EXPORT_SYMBOL(icnss_power_off);
-static int icnss_map_msa_permissions(struct icnss_priv *priv, u32 index)
+static int icnss_map_msa_permissions(struct icnss_mem_region_info *mem_region)
{
int ret = 0;
phys_addr_t addr;
@@ -773,10 +995,10 @@
int source_nelems = sizeof(source_vmlist)/sizeof(u32);
int dest_nelems = 0;
- addr = priv->icnss_mem_region[index].reg_addr;
- size = priv->icnss_mem_region[index].size;
+ addr = mem_region->reg_addr;
+ size = mem_region->size;
- if (!priv->icnss_mem_region[index].secure_flag) {
+ if (!mem_region->secure_flag) {
dest_vmids[2] = VMID_WLAN_CE;
dest_nelems = 3;
} else {
@@ -786,19 +1008,20 @@
ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems,
dest_vmids, dest_perms, dest_nelems);
if (ret) {
- icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n",
- index, &addr, size, ret);
+ icnss_pr_err("Hyperviser map failed for PA=%pa size=%u err=%d\n",
+ &addr, size, ret);
goto out;
}
- icnss_pr_dbg("Hypervisor map for region %u: source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n",
- index, source_vmlist[0], dest_nelems,
- dest_vmids[0], dest_vmids[1], dest_vmids[2]);
+
+ icnss_pr_dbg("Hypervisor map for source=%x, dest_nelems=%d, dest[0]=%x, dest[1]=%x, dest[2]=%x\n",
+ source_vmlist[0], dest_nelems, dest_vmids[0],
+ dest_vmids[1], dest_vmids[2]);
out:
return ret;
}
-static int icnss_unmap_msa_permissions(struct icnss_priv *priv, u32 index)
+static int icnss_unmap_msa_permissions(struct icnss_mem_region_info *mem_region)
{
int ret = 0;
phys_addr_t addr;
@@ -809,9 +1032,10 @@
int source_nelems = 0;
int dest_nelems = sizeof(dest_vmids)/sizeof(u32);
- addr = priv->icnss_mem_region[index].reg_addr;
- size = priv->icnss_mem_region[index].size;
- if (!priv->icnss_mem_region[index].secure_flag) {
+ addr = mem_region->reg_addr;
+ size = mem_region->size;
+
+ if (!mem_region->secure_flag) {
source_vmlist[2] = VMID_WLAN_CE;
source_nelems = 3;
} else {
@@ -822,14 +1046,13 @@
ret = hyp_assign_phys(addr, size, source_vmlist, source_nelems,
dest_vmids, dest_perms, dest_nelems);
if (ret) {
- icnss_pr_err("Region %u hyp_assign_phys failed IPA=%pa size=%u err=%d\n",
- index, &addr, size, ret);
+ icnss_pr_err("Hyperviser unmap failed for PA=%pa size=%u err=%d\n",
+ &addr, size, ret);
goto out;
}
- icnss_pr_dbg("hypervisor unmap for region %u, source_nelems=%d, source[0]=%x, source[1]=%x, source[2]=%x, dest=%x\n",
- index, source_nelems,
- source_vmlist[0], source_vmlist[1], source_vmlist[2],
- dest_vmids[0]);
+ icnss_pr_dbg("Hypervisor unmap for source_nelems=%d, source[0]=%x, source[1]=%x, source[2]=%x, dest=%x\n",
+ source_nelems, source_vmlist[0], source_vmlist[1],
+ source_vmlist[2], dest_vmids[0]);
out:
return ret;
}
@@ -837,34 +1060,37 @@
static int icnss_setup_msa_permissions(struct icnss_priv *priv)
{
int ret;
+ int i;
if (test_bit(ICNSS_MSA0_ASSIGNED, &priv->state))
return 0;
- ret = icnss_map_msa_permissions(priv, 0);
- if (ret)
- return ret;
+ for (i = 0; i < priv->nr_mem_region; i++) {
- ret = icnss_map_msa_permissions(priv, 1);
- if (ret)
- goto err_map_msa;
+ ret = icnss_map_msa_permissions(&priv->mem_region[i]);
+ if (ret)
+ goto err_unmap;
+ }
set_bit(ICNSS_MSA0_ASSIGNED, &priv->state);
- return ret;
+ return 0;
-err_map_msa:
- icnss_unmap_msa_permissions(priv, 0);
+err_unmap:
+ for (i--; i >= 0; i--)
+ icnss_unmap_msa_permissions(&priv->mem_region[i]);
return ret;
}
static void icnss_remove_msa_permissions(struct icnss_priv *priv)
{
+ int i;
+
if (!test_bit(ICNSS_MSA0_ASSIGNED, &priv->state))
return;
- icnss_unmap_msa_permissions(priv, 0);
- icnss_unmap_msa_permissions(priv, 1);
+ for (i = 0; i < priv->nr_mem_region; i++)
+ icnss_unmap_msa_permissions(&priv->mem_region[i]);
clear_bit(ICNSS_MSA0_ASSIGNED, &priv->state);
}
@@ -915,7 +1141,7 @@
icnss_pr_dbg("Receive mem_region_info_len: %d\n",
resp.mem_region_info_len);
- if (resp.mem_region_info_len > 2) {
+ if (resp.mem_region_info_len > QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01) {
icnss_pr_err("Invalid memory region length received: %d\n",
resp.mem_region_info_len);
ret = -EINVAL;
@@ -923,24 +1149,25 @@
}
penv->stats.msa_info_resp++;
+ penv->nr_mem_region = resp.mem_region_info_len;
for (i = 0; i < resp.mem_region_info_len; i++) {
- penv->icnss_mem_region[i].reg_addr =
+ penv->mem_region[i].reg_addr =
resp.mem_region_info[i].region_addr;
- penv->icnss_mem_region[i].size =
+ penv->mem_region[i].size =
resp.mem_region_info[i].size;
- penv->icnss_mem_region[i].secure_flag =
+ penv->mem_region[i].secure_flag =
resp.mem_region_info[i].secure_flag;
icnss_pr_dbg("Memory Region: %d Addr: 0x%llx Size: 0x%x Flag: 0x%08x\n",
- i, penv->icnss_mem_region[i].reg_addr,
- penv->icnss_mem_region[i].size,
- penv->icnss_mem_region[i].secure_flag);
+ i, penv->mem_region[i].reg_addr,
+ penv->mem_region[i].size,
+ penv->mem_region[i].secure_flag);
}
return 0;
out:
penv->stats.msa_info_err++;
- ICNSS_ASSERT(false);
+ ICNSS_QMI_ASSERT();
return ret;
}
@@ -988,7 +1215,7 @@
out:
penv->stats.msa_ready_err++;
- ICNSS_ASSERT(false);
+ ICNSS_QMI_ASSERT();
return ret;
}
@@ -1051,7 +1278,7 @@
out:
penv->stats.ind_register_err++;
- ICNSS_ASSERT(false);
+ ICNSS_QMI_ASSERT();
return ret;
}
@@ -1120,7 +1347,7 @@
out:
penv->stats.cap_err++;
- ICNSS_ASSERT(false);
+ ICNSS_QMI_ASSERT();
return ret;
}
@@ -1181,7 +1408,7 @@
out:
penv->stats.mode_req_err++;
- ICNSS_ASSERT(false);
+ ICNSS_QMI_ASSERT();
return ret;
}
@@ -1231,7 +1458,7 @@
out:
penv->stats.cfg_req_err++;
- ICNSS_ASSERT(false);
+ ICNSS_QMI_ASSERT();
return ret;
}
@@ -1284,7 +1511,7 @@
out:
penv->stats.ini_req_err++;
- ICNSS_ASSERT(false);
+ ICNSS_QMI_ASSERT();
return ret;
}
@@ -1339,7 +1566,7 @@
goto out;
}
- if (!resp->data_valid || resp->data_len <= data_len) {
+ if (!resp->data_valid || resp->data_len < data_len) {
icnss_pr_err("Athdiag read data is invalid, data_valid = %u, data_len = %u\n",
resp->data_valid, resp->data_len);
ret = -EINVAL;
@@ -1450,7 +1677,7 @@
out:
priv->stats.rejuvenate_ack_err++;
- ICNSS_ASSERT(false);
+ ICNSS_QMI_ASSERT();
return ret;
}
@@ -1524,7 +1751,7 @@
if (!penv || !penv->wlfw_clnt)
return;
- icnss_pr_dbg("Receiving Event in work queue context\n");
+ icnss_pr_vdbg("Receiving Event in work queue context\n");
do {
} while ((ret = qmi_recv_msg(penv->wlfw_clnt)) == 0);
@@ -1532,13 +1759,13 @@
if (ret != -ENOMSG)
icnss_pr_err("Error receiving message: %d\n", ret);
- icnss_pr_dbg("Receiving Event completed\n");
+ icnss_pr_vdbg("Receiving Event completed\n");
}
static void icnss_qmi_wlfw_clnt_notify(struct qmi_handle *handle,
enum qmi_event_type event, void *notify_priv)
{
- icnss_pr_dbg("QMI client notify: %d\n", event);
+ icnss_pr_vdbg("QMI client notify: %d\n", event);
if (!penv || !penv->wlfw_clnt)
return;
@@ -1553,11 +1780,29 @@
}
}
+static int icnss_call_driver_uevent(struct icnss_priv *priv,
+ enum icnss_uevent uevent, void *data)
+{
+ struct icnss_uevent_data uevent_data;
+
+ if (!priv->ops || !priv->ops->uevent)
+ return 0;
+
+ icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n",
+ priv->state, uevent);
+
+ uevent_data.uevent = uevent;
+ uevent_data.data = data;
+
+ return priv->ops->uevent(&priv->pdev->dev, &uevent_data);
+}
+
static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle,
unsigned int msg_id, void *msg,
unsigned int msg_len, void *ind_cb_priv)
{
struct icnss_event_pd_service_down_data *event_data;
+ struct icnss_uevent_fw_down_data fw_down_data;
if (!penv)
return;
@@ -1582,11 +1827,16 @@
case QMI_WLFW_REJUVENATE_IND_V01:
icnss_pr_dbg("Received Rejuvenate Indication msg_id 0x%x, state: 0x%lx\n",
msg_id, penv->state);
+
+ icnss_ignore_qmi_timeout(true);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
if (event_data == NULL)
return;
event_data->crashed = true;
event_data->fw_rejuvenate = true;
+ fw_down_data.crashed = true;
+ icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_DOWN,
+ &fw_down_data);
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
0, event_data);
break;
@@ -1707,6 +1957,9 @@
if (!priv->ops || !priv->ops->probe)
return 0;
+ if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
+ return -EINVAL;
+
icnss_pr_dbg("Calling driver probe state: 0x%lx\n", priv->state);
icnss_hw_power_on(priv);
@@ -1715,6 +1968,8 @@
if (ret < 0) {
icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
ret, priv->state);
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
goto out;
}
@@ -1727,17 +1982,39 @@
return ret;
}
+static int icnss_call_driver_shutdown(struct icnss_priv *priv)
+{
+ if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
+ goto out;
+
+ if (!priv->ops || !priv->ops->shutdown)
+ goto out;
+
+ icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state);
+
+ priv->ops->shutdown(&priv->pdev->dev);
+
+out:
+ return 0;
+}
+
static int icnss_pd_restart_complete(struct icnss_priv *priv)
{
int ret;
- clear_bit(ICNSS_PD_RESTART, &priv->state);
icnss_pm_relax(priv);
+ if (test_bit(ICNSS_WDOG_BITE, &priv->state)) {
+ icnss_call_driver_shutdown(priv);
+ clear_bit(ICNSS_WDOG_BITE, &priv->state);
+ }
+
+ clear_bit(ICNSS_PD_RESTART, &priv->state);
+
if (!priv->ops || !priv->ops->reinit)
goto out;
- if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
+ if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
goto call_probe;
icnss_pr_dbg("Calling driver reinit state: 0x%lx\n", priv->state);
@@ -1774,6 +2051,8 @@
set_bit(ICNSS_FW_READY, &penv->state);
+ icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_READY, NULL);
+
icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state);
icnss_hw_power_off(penv);
@@ -1820,6 +2099,8 @@
if (ret) {
icnss_pr_err("Driver probe failed: %d, state: 0x%lx\n",
ret, penv->state);
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
goto power_off;
}
@@ -1845,6 +2126,8 @@
penv->ops->remove(&penv->pdev->dev);
clear_bit(ICNSS_DRIVER_PROBED, &penv->state);
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
penv->ops = NULL;
@@ -1869,27 +2152,39 @@
penv->ops->remove(&priv->pdev->dev);
clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
+ wcnss_prealloc_check_memory_leak();
+ wcnss_pre_alloc_reset();
+
+ icnss_hw_power_off(penv);
return 0;
}
-static int icnss_call_driver_shutdown(struct icnss_priv *priv)
+static int icnss_fw_crashed(struct icnss_priv *priv,
+ struct icnss_event_pd_service_down_data *event_data)
{
- icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state);
+ icnss_pr_dbg("FW crashed, state: 0x%lx, wdog_bite: %d\n",
+ priv->state, event_data->wdog_bite);
set_bit(ICNSS_PD_RESTART, &priv->state);
clear_bit(ICNSS_FW_READY, &priv->state);
icnss_pm_stay_awake(priv);
- if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state))
- return 0;
+ if (test_bit(ICNSS_DRIVER_PROBED, &priv->state))
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL);
- if (!priv->ops || !priv->ops->shutdown)
- return 0;
+ if (event_data->wdog_bite) {
+ set_bit(ICNSS_WDOG_BITE, &priv->state);
+ goto out;
+ }
- priv->ops->shutdown(&priv->pdev->dev);
+ icnss_call_driver_shutdown(priv);
+ if (event_data->fw_rejuvenate)
+ wlfw_rejuvenate_ack_send_sync_msg(priv);
+
+out:
return 0;
}
@@ -1900,7 +2195,7 @@
struct icnss_event_pd_service_down_data *event_data = data;
if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state))
- return 0;
+ goto out;
if (test_bit(ICNSS_PD_RESTART, &priv->state)) {
icnss_pr_err("PD Down while recovery inprogress, crashed: %d, state: 0x%lx\n",
@@ -1910,18 +2205,15 @@
}
if (event_data->crashed)
- icnss_call_driver_shutdown(priv);
+ icnss_fw_crashed(priv, event_data);
else
icnss_call_driver_remove(priv);
- if (event_data->fw_rejuvenate)
- wlfw_rejuvenate_ack_send_sync_msg(priv);
-
out:
- ret = icnss_hw_power_off(priv);
-
kfree(data);
+ icnss_ignore_qmi_timeout(false);
+
return ret;
}
@@ -2046,8 +2338,9 @@
struct notif_data *notif = data;
struct icnss_priv *priv = container_of(nb, struct icnss_priv,
modem_ssr_nb);
+ struct icnss_uevent_fw_down_data fw_down_data;
- icnss_pr_dbg("Modem-Notify: event %lu\n", code);
+ icnss_pr_vdbg("Modem-Notify: event %lu\n", code);
if (code == SUBSYS_AFTER_SHUTDOWN &&
notif->crashed == CRASH_STATUS_ERR_FATAL) {
@@ -2063,7 +2356,10 @@
if (test_bit(ICNSS_PDR_ENABLED, &priv->state))
return NOTIFY_OK;
- icnss_pr_info("Modem went down, state: %lx\n", priv->state);
+ icnss_pr_info("Modem went down, state: 0x%lx, crashed: %d\n",
+ priv->state, notif->crashed);
+
+ icnss_ignore_qmi_timeout(true);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
@@ -2072,6 +2368,12 @@
event_data->crashed = notif->crashed;
+ if (notif->crashed == CRASH_STATUS_WDOG_BITE)
+ event_data->wdog_bite = true;
+
+ fw_down_data.crashed = !!notif->crashed;
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
+
icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
@@ -2135,31 +2437,47 @@
service_notifier_nb);
enum pd_subsys_state *state = data;
struct icnss_event_pd_service_down_data *event_data;
+ struct icnss_uevent_fw_down_data fw_down_data;
- switch (notification) {
- case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01:
- icnss_pr_info("Service down, data: 0x%p, state: 0x%lx\n", data,
- priv->state);
- event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
+ icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
+ notification, priv->state);
- if (event_data == NULL)
- return notifier_from_errno(-ENOMEM);
+ if (notification != SERVREG_NOTIF_SERVICE_STATE_DOWN_V01)
+ goto done;
- if (state == NULL || *state != ROOT_PD_SHUTDOWN)
- event_data->crashed = true;
+ event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
- icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
- ICNSS_EVENT_SYNC, event_data);
- break;
- case SERVREG_NOTIF_SERVICE_STATE_UP_V01:
- icnss_pr_dbg("Service up, state: 0x%lx\n", priv->state);
- break;
- default:
- icnss_pr_dbg("Service state Unknown, notification: 0x%lx, state: 0x%lx\n",
- notification, priv->state);
- return NOTIFY_DONE;
+ if (event_data == NULL)
+ return notifier_from_errno(-ENOMEM);
+
+ if (state == NULL) {
+ event_data->crashed = true;
+ goto event_post;
}
+ icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx\n",
+ *state, priv->state);
+
+ switch (*state) {
+ case ROOT_PD_WDOG_BITE:
+ event_data->crashed = true;
+ event_data->wdog_bite = true;
+ break;
+ case ROOT_PD_SHUTDOWN:
+ break;
+ default:
+ event_data->crashed = true;
+ break;
+ }
+
+event_post:
+ icnss_ignore_qmi_timeout(true);
+
+ fw_down_data.crashed = event_data->crashed;
+ icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN, &fw_down_data);
+ icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
+ ICNSS_EVENT_SYNC, event_data);
+done:
return NOTIFY_OK;
}
@@ -2265,7 +2583,7 @@
return 0;
out:
- icnss_pr_err("PD restart not enabled: %d\n", ret);
+ icnss_pr_err("Failed to enable PD restart: %d\n", ret);
return ret;
}
@@ -2375,7 +2693,7 @@
goto out;
}
- icnss_pr_dbg("CE request IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
+ icnss_pr_vdbg("CE request IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
icnss_pr_err("Invalid CE ID, ce_id: %d\n", ce_id);
@@ -2401,7 +2719,7 @@
irq_entry->irq = irq;
irq_entry->handler = handler;
- icnss_pr_dbg("IRQ requested: %d, ce_id: %d\n", irq, ce_id);
+ icnss_pr_vdbg("IRQ requested: %d, ce_id: %d\n", irq, ce_id);
penv->stats.ce_irqs[ce_id].request++;
out:
@@ -2420,7 +2738,7 @@
goto out;
}
- icnss_pr_dbg("CE free IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
+ icnss_pr_vdbg("CE free IRQ: %d, state: 0x%lx\n", ce_id, penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
icnss_pr_err("Invalid CE ID to free, ce_id: %d\n", ce_id);
@@ -2454,7 +2772,7 @@
return;
}
- icnss_pr_dbg("Enable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
+ icnss_pr_vdbg("Enable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
@@ -2478,7 +2796,7 @@
return;
}
- icnss_pr_dbg("Disable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
+ icnss_pr_vdbg("Disable IRQ: ce_id: %d, state: 0x%lx\n", ce_id,
penv->state);
if (ce_id >= ICNSS_MAX_IRQ_REGISTRATIONS) {
@@ -2878,12 +3196,25 @@
goto out;
}
- if (!priv->service_notifier[0].handle) {
- icnss_pr_err("Invalid handle during recovery\n");
+ if (!test_bit(ICNSS_PDR_ENABLED, &priv->state)) {
+ icnss_pr_err("PD restart not enabled to trigger recovery: state: 0x%lx\n",
+ priv->state);
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (!priv->service_notifier || !priv->service_notifier[0].handle) {
+ icnss_pr_err("Invalid handle during recovery, state: 0x%lx\n",
+ priv->state);
ret = -EINVAL;
goto out;
}
+ WARN_ON(1);
+ icnss_pr_warn("Initiate PD restart at WLAN FW, state: 0x%lx\n",
+ priv->state);
+ priv->stats.trigger_recovery++;
+
/*
* Initiate PDR, required only for the first instance
*/
@@ -2914,13 +3245,15 @@
goto map_fail;
}
- ret = iommu_domain_set_attr(mapping->domain,
- DOMAIN_ATTR_ATOMIC,
- &atomic_ctx);
- if (ret < 0) {
- icnss_pr_err("Set atomic_ctx attribute failed, err = %d\n",
- ret);
- goto set_attr_fail;
+ if (!priv->bypass_s1_smmu) {
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_ATOMIC,
+ &atomic_ctx);
+ if (ret < 0) {
+ icnss_pr_err("Set atomic_ctx attribute failed, err = %d\n",
+ ret);
+ goto set_attr_fail;
+ }
}
ret = iommu_domain_set_attr(mapping->domain,
@@ -2959,6 +3292,114 @@
priv->smmu_mapping = NULL;
}
+static int icnss_get_vreg_info(struct device *dev,
+ struct icnss_vreg_info *vreg_info)
+{
+ int ret = 0;
+ char prop_name[MAX_PROP_SIZE];
+ struct regulator *reg;
+ const __be32 *prop;
+ int len = 0;
+ int i;
+
+ reg = devm_regulator_get_optional(dev, vreg_info->name);
+ if (PTR_ERR(reg) == -EPROBE_DEFER) {
+ icnss_pr_err("EPROBE_DEFER for regulator: %s\n",
+ vreg_info->name);
+ ret = PTR_ERR(reg);
+ goto out;
+ }
+
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+
+ if (vreg_info->required) {
+ icnss_pr_err("Regulator %s doesn't exist: %d\n",
+ vreg_info->name, ret);
+ goto out;
+ } else {
+ icnss_pr_dbg("Optional regulator %s doesn't exist: %d\n",
+ vreg_info->name, ret);
+ goto done;
+ }
+ }
+
+ vreg_info->reg = reg;
+
+ snprintf(prop_name, MAX_PROP_SIZE,
+ "qcom,%s-config", vreg_info->name);
+
+ prop = of_get_property(dev->of_node, prop_name, &len);
+
+ icnss_pr_dbg("Got regulator config, prop: %s, len: %d\n",
+ prop_name, len);
+
+ if (!prop || len < (2 * sizeof(__be32))) {
+ icnss_pr_dbg("Property %s %s\n", prop_name,
+ prop ? "invalid format" : "doesn't exist");
+ goto done;
+ }
+
+ for (i = 0; (i * sizeof(__be32)) < len; i++) {
+ switch (i) {
+ case 0:
+ vreg_info->min_v = be32_to_cpup(&prop[0]);
+ break;
+ case 1:
+ vreg_info->max_v = be32_to_cpup(&prop[1]);
+ break;
+ case 2:
+ vreg_info->load_ua = be32_to_cpup(&prop[2]);
+ break;
+ case 3:
+ vreg_info->settle_delay = be32_to_cpup(&prop[3]);
+ break;
+ default:
+ icnss_pr_dbg("Property %s, ignoring value at %d\n",
+ prop_name, i);
+ break;
+ }
+ }
+
+done:
+ icnss_pr_dbg("Regulator: %s, min_v: %u, max_v: %u, load: %u, delay: %lu\n",
+ vreg_info->name, vreg_info->min_v, vreg_info->max_v,
+ vreg_info->load_ua, vreg_info->settle_delay);
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static int icnss_get_clk_info(struct device *dev,
+ struct icnss_clk_info *clk_info)
+{
+ struct clk *handle;
+ int ret = 0;
+
+ handle = devm_clk_get(dev, clk_info->name);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ if (clk_info->required) {
+ icnss_pr_err("Clock %s isn't available: %d\n",
+ clk_info->name, ret);
+ goto out;
+ } else {
+ icnss_pr_dbg("Ignoring clock %s: %d\n", clk_info->name,
+ ret);
+ ret = 0;
+ goto out;
+ }
+ }
+
+ icnss_pr_dbg("Clock: %s, freq: %u\n", clk_info->name, clk_info->freq);
+
+ clk_info->handle = handle;
+out:
+ return ret;
+}
+
static int icnss_fw_debug_show(struct seq_file *s, void *data)
{
struct icnss_priv *priv = s->private;
@@ -2969,6 +3410,7 @@
seq_puts(s, " VAL: 0 (Test mode disable)\n");
seq_puts(s, " VAL: 1 (WLAN FW test)\n");
seq_puts(s, " VAL: 2 (CCPM test)\n");
+ seq_puts(s, " VAL: 3 (Trigger Recovery)\n");
seq_puts(s, "\nCMD: dynamic_feature_mask\n");
seq_puts(s, " VAL: (64 bit feature mask)\n");
@@ -3223,6 +3665,9 @@
case ICNSS_WLFW_EXISTS:
seq_puts(s, "WLAN FW EXISTS");
continue;
+ case ICNSS_WDOG_BITE:
+ seq_puts(s, "MODEM WDOG BITE");
+ continue;
}
seq_printf(s, "UNKNOWN-%d", i);
@@ -3321,6 +3766,7 @@
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_req);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_resp);
ICNSS_STATS_DUMP(s, priv, rejuvenate_ack_err);
+ ICNSS_STATS_DUMP(s, priv, trigger_recovery);
seq_puts(s, "\n<------------------ PM stats ------------------->\n");
ICNSS_STATS_DUMP(s, priv, pm_suspend);
@@ -3666,6 +4112,26 @@
if (ret == -EPROBE_DEFER)
goto out;
+ memcpy(priv->vreg_info, icnss_vreg_info, sizeof(icnss_vreg_info));
+ for (i = 0; i < ICNSS_VREG_INFO_SIZE; i++) {
+ ret = icnss_get_vreg_info(dev, &priv->vreg_info[i]);
+
+ if (ret)
+ goto out;
+ }
+
+ memcpy(priv->clk_info, icnss_clk_info, sizeof(icnss_clk_info));
+ for (i = 0; i < ICNSS_CLK_INFO_SIZE; i++) {
+ ret = icnss_get_clk_info(dev, &priv->clk_info[i]);
+ if (ret)
+ goto out;
+ }
+
+ if (of_property_read_bool(pdev->dev.of_node, "qcom,smmu-s1-bypass"))
+ priv->bypass_s1_smmu = true;
+
+ icnss_pr_dbg("SMMU S1 BYPASS = %d\n", priv->bypass_s1_smmu);
+
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase");
if (!res) {
icnss_pr_err("Memory base not found in DT\n");
@@ -3830,7 +4296,7 @@
return -EINVAL;
}
- icnss_pr_dbg("PM Suspend, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM Suspend, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->pm_suspend ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -3859,7 +4325,7 @@
return -EINVAL;
}
- icnss_pr_dbg("PM resume, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM resume, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->pm_resume ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -3888,7 +4354,7 @@
return -EINVAL;
}
- icnss_pr_dbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->suspend_noirq ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -3917,7 +4383,7 @@
return -EINVAL;
}
- icnss_pr_dbg("PM resume_noirq, state: 0x%lx\n", priv->state);
+ icnss_pr_vdbg("PM resume_noirq, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->resume_noirq ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
@@ -3961,26 +4427,6 @@
},
};
-#ifdef CONFIG_ICNSS_DEBUG
-static void __init icnss_ipc_log_long_context_init(void)
-{
- icnss_ipc_log_long_context = ipc_log_context_create(NUM_REG_LOG_PAGES,
- "icnss_long", 0);
- if (!icnss_ipc_log_long_context)
- icnss_pr_err("Unable to create register log context\n");
-}
-
-static void __exit icnss_ipc_log_long_context_destroy(void)
-{
- ipc_log_context_destroy(icnss_ipc_log_long_context);
- icnss_ipc_log_long_context = NULL;
-}
-#else
-
-static void __init icnss_ipc_log_long_context_init(void) { }
-static void __exit icnss_ipc_log_long_context_destroy(void) { }
-#endif
-
static int __init icnss_initialize(void)
{
icnss_ipc_log_context = ipc_log_context_create(NUM_LOG_PAGES,
@@ -3988,7 +4434,10 @@
if (!icnss_ipc_log_context)
icnss_pr_err("Unable to create log context\n");
- icnss_ipc_log_long_context_init();
+ icnss_ipc_log_long_context = ipc_log_context_create(NUM_LOG_LONG_PAGES,
+ "icnss_long", 0);
+ if (!icnss_ipc_log_long_context)
+ icnss_pr_err("Unable to create log long context\n");
return platform_driver_register(&icnss_driver);
}
@@ -3998,8 +4447,8 @@
platform_driver_unregister(&icnss_driver);
ipc_log_context_destroy(icnss_ipc_log_context);
icnss_ipc_log_context = NULL;
-
- icnss_ipc_log_long_context_destroy();
+ ipc_log_context_destroy(icnss_ipc_log_long_context);
+ icnss_ipc_log_long_context = NULL;
}
diff --git a/drivers/soc/qcom/llcc-core.c b/drivers/soc/qcom/llcc-core.c
index fc88c71..3d6b002 100644
--- a/drivers/soc/qcom/llcc-core.c
+++ b/drivers/soc/qcom/llcc-core.c
@@ -33,42 +33,39 @@
#define SB_DB_TRP_INTERRUPT_ENABLE 0x3
#define TRP0_INTERRUPT_ENABLE 0x1
#define DRP0_INTERRUPT_ENABLE BIT(6)
-#define COMMON_INTERRUPT_0_AMON BIT(8)
#define SB_DB_DRP_INTERRUPT_ENABLE 0x3
-static void qcom_llcc_core_setup(struct regmap *llcc_regmap)
+static void qcom_llcc_core_setup(struct regmap *llcc_regmap, uint32_t b_off)
{
u32 sb_err_threshold;
/* Enable TRP in instance 2 of common interrupt enable register */
- regmap_update_bits(llcc_regmap, CMN_INTERRUPT_2_ENABLE,
+ regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE,
TRP0_INTERRUPT_ENABLE, TRP0_INTERRUPT_ENABLE);
/* Enable ECC interrupts on Tag Ram */
- regmap_update_bits(llcc_regmap, TRP_INTERRUPT_0_ENABLE,
+ regmap_update_bits(llcc_regmap, b_off + TRP_INTERRUPT_0_ENABLE,
SB_DB_TRP_INTERRUPT_ENABLE, SB_DB_TRP_INTERRUPT_ENABLE);
/* Enable SB error for Data RAM */
sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT);
- regmap_write(llcc_regmap, DRP_ECC_ERROR_CFG, sb_err_threshold);
+ regmap_write(llcc_regmap, b_off + DRP_ECC_ERROR_CFG, sb_err_threshold);
/* Enable DRP in instance 2 of common interrupt enable register */
- regmap_update_bits(llcc_regmap, CMN_INTERRUPT_2_ENABLE,
+ regmap_update_bits(llcc_regmap, b_off + CMN_INTERRUPT_2_ENABLE,
DRP0_INTERRUPT_ENABLE, DRP0_INTERRUPT_ENABLE);
/* Enable ECC interrupts on Data Ram */
- regmap_write(llcc_regmap, DRP_INTERRUPT_ENABLE,
+ regmap_write(llcc_regmap, b_off + DRP_INTERRUPT_ENABLE,
SB_DB_DRP_INTERRUPT_ENABLE);
-
- /* Enable AMON interrupt in the common interrupt register */
- regmap_update_bits(llcc_regmap, CMN_INTERRUPT_0_ENABLE,
- COMMON_INTERRUPT_0_AMON, COMMON_INTERRUPT_0_AMON);
}
static int qcom_llcc_core_probe(struct platform_device *pdev)
{
struct regmap *llcc_regmap;
struct device *dev = &pdev->dev;
+ u32 b_off = 0;
+ int ret = 0;
llcc_regmap = syscon_node_to_regmap(dev->of_node);
@@ -77,7 +74,14 @@
return PTR_ERR(llcc_regmap);
}
- qcom_llcc_core_setup(llcc_regmap);
+ ret = of_property_read_u32(dev->of_node,
+ "qcom,llcc-broadcast-off", &b_off);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to read broadcast-off\n");
+ return -EINVAL;
+ }
+
+ qcom_llcc_core_setup(llcc_regmap, b_off);
return 0;
}
diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c
index 77c2ae6..5ca0941 100644
--- a/drivers/soc/qcom/llcc-slice.c
+++ b/drivers/soc/qcom/llcc-slice.c
@@ -44,6 +44,7 @@
#define CACHE_LINE_SIZE_SHIFT 6
#define SIZE_PER_LLCC_SHIFT 2
+
#define MAX_CAP_TO_BYTES(n) (n * 1024)
#define LLCC_TRP_ACT_CTRLn(n) (n * 0x1000)
#define LLCC_TRP_STATUSn(n) (4 + n * 0x1000)
@@ -63,6 +64,7 @@
struct mutex slice_mutex;
u32 llcc_config_data_sz;
u32 max_slices;
+ u32 b_off;
unsigned long *llcc_slice_map;
};
@@ -172,8 +174,8 @@
u32 slice_status;
unsigned long timeout;
- act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
- status_reg = LLCC_TRP_STATUSn(sid);
+ act_ctrl_reg = drv->b_off + LLCC_TRP_ACT_CTRLn(sid);
+ status_reg = drv->b_off + LLCC_TRP_STATUSn(sid);
regmap_write(drv->llcc_map, act_ctrl_reg, act_ctrl_reg_val);
@@ -323,13 +325,14 @@
const struct llcc_slice_config *llcc_table;
struct llcc_drv_data *drv = platform_get_drvdata(pdev);
struct llcc_slice_desc desc;
+ u32 b_off = drv->b_off;
sz = drv->llcc_config_data_sz;
llcc_table = drv->slice_data;
for (i = 0; i < sz; i++) {
- attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
- attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
+ attr1_cfg = b_off + LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
+ attr0_cfg = b_off + LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
attr1_val = llcc_table[i].cache_mode;
attr1_val |= (llcc_table[i].probe_target_ways <<
@@ -386,7 +389,15 @@
rc = of_property_read_u32(pdev->dev.of_node, "max-slices",
&drv_data->max_slices);
if (rc) {
- dev_info(&pdev->dev, "Invalid max-slices dt entry\n");
+ dev_err(&pdev->dev, "Invalid max-slices dt entry\n");
+ devm_kfree(&pdev->dev, drv_data);
+ return rc;
+ }
+
+ rc = of_property_read_u32(pdev->dev.parent->of_node,
+ "qcom,llcc-broadcast-off", &drv_data->b_off);
+ if (rc) {
+ dev_err(&pdev->dev, "Invalid qcom,broadcast-off entry\n");
devm_kfree(&pdev->dev, drv_data);
return rc;
}
diff --git a/drivers/soc/qcom/msm-core.c b/drivers/soc/qcom/msm-core.c
index 5a0b261..de2a1ce 100644
--- a/drivers/soc/qcom/msm-core.c
+++ b/drivers/soc/qcom/msm-core.c
@@ -107,7 +107,6 @@
static struct cpu_activity_info activity[NR_CPUS];
DEFINE_PER_CPU(struct cpu_pstate_pwr *, ptable);
static struct cpu_pwr_stats cpu_stats[NR_CPUS];
-static uint32_t scaling_factor;
ALLOCATE_2D_ARRAY(uint32_t);
static int poll_ms;
@@ -402,9 +401,9 @@
return -EINVAL;
get_user(cluster, &argp->cluster);
- mpidr = (argp->cluster << (MAX_CORES_PER_CLUSTER *
+ mpidr = (cluster << (MAX_CORES_PER_CLUSTER *
MAX_NUM_OF_CLUSTERS));
- cpumask = argp->cpumask;
+ get_user(cpumask, &argp->cpumask);
switch (cmd) {
case EA_LEAKAGE:
@@ -603,54 +602,6 @@
return ret;
}
-static int msm_core_tsens_init(struct device_node *node, int cpu)
-{
- int ret = 0;
- char *key = NULL;
- struct device_node *phandle;
- const char *sensor_type = NULL;
- struct cpu_activity_info *cpu_node = &activity[cpu];
-
- if (!node)
- return -ENODEV;
-
- key = "sensor";
- phandle = of_parse_phandle(node, key, 0);
- if (!phandle) {
- pr_info("%s: No sensor mapping found for the core\n",
- __func__);
- /* Do not treat this as error as some targets might have
- * temperature notification only in userspace.
- * Use default temperature for the core. Userspace might
- * update the temperature once it is up.
- */
- cpu_node->sensor_id = -ENODEV;
- cpu_node->temp = DEFAULT_TEMP;
- return 0;
- }
-
- key = "qcom,sensor-name";
- ret = of_property_read_string(phandle, key,
- &sensor_type);
- if (ret) {
- pr_err("%s: Cannot read tsens id\n", __func__);
- return ret;
- }
-
- if (cpu_node->sensor_id < 0)
- return cpu_node->sensor_id;
-
- key = "qcom,scaling-factor";
- ret = of_property_read_u32(phandle, key,
- &scaling_factor);
- if (ret) {
- pr_info("%s: Cannot read tsens scaling factor\n", __func__);
- scaling_factor = DEFAULT_SCALING_FACTOR;
- }
-
- return ret;
-}
-
static int msm_core_mpidr_init(struct device_node *phandle)
{
int ret = 0;
@@ -779,8 +730,6 @@
int ret = 0;
unsigned long cpu = 0;
struct device_node *child_node = NULL;
- struct device_node *ea_node = NULL;
- char *key = NULL;
int mpidr;
for_each_possible_cpu(cpu) {
@@ -793,23 +742,8 @@
if (mpidr < 0)
return mpidr;
- if (cpu >= num_possible_cpus())
- continue;
-
activity[cpu].mpidr = mpidr;
- key = "qcom,ea";
- ea_node = of_parse_phandle(child_node, key, 0);
- if (!ea_node) {
- pr_err("%s Couldn't find the ea_node for cpu%lu\n",
- __func__, cpu);
- return -ENODEV;
- }
-
- ret = msm_core_tsens_init(ea_node, cpu);
- if (ret)
- return ret;
-
if (!activity[cpu].sp->table)
continue;
@@ -858,49 +792,6 @@
}
}
-static int uio_init(struct platform_device *pdev)
-{
- int ret = 0;
- struct uio_info *info = NULL;
- struct resource *clnt_res = NULL;
- u32 ea_mem_size = 0;
- phys_addr_t ea_mem_pyhsical = 0;
-
- clnt_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!clnt_res) {
- pr_err("resource not found\n");
- return -ENODEV;
- }
-
- info = devm_kzalloc(&pdev->dev, sizeof(struct uio_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
-
- ea_mem_size = resource_size(clnt_res);
- ea_mem_pyhsical = clnt_res->start;
-
- if (ea_mem_size == 0) {
- pr_err("msm-core: memory size is zero");
- return -EINVAL;
- }
-
- /* Setup device */
- info->name = clnt_res->name;
- info->version = "1.0";
- info->mem[0].addr = ea_mem_pyhsical;
- info->mem[0].size = ea_mem_size;
- info->mem[0].memtype = UIO_MEM_PHYS;
-
- ret = uio_register_device(&pdev->dev, info);
- if (ret) {
- pr_err("uio register failed ret=%d", ret);
- return ret;
- }
- dev_set_drvdata(&pdev->dev, info);
-
- return 0;
-}
-
static int msm_core_dev_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -934,10 +825,6 @@
key = "qcom,throttling-temp";
ret = of_property_read_u32(node, key, &max_throttling_temp);
- ret = uio_init(pdev);
- if (ret)
- return ret;
-
ret = msm_core_freq_init();
if (ret)
goto failed;
diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
index 1f5cfc0..beb5c2b 100644
--- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
+++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c
@@ -983,7 +983,6 @@
if (IS_ERR_OR_NULL(rscdev->mbox)) {
MSM_BUS_ERR("%s: Failed to get mbox:%s", __func__,
node_dev->node_info->name);
- return PTR_ERR(rscdev->mbox);
}
// Add way to count # of VCDs, initialize LL
@@ -1532,21 +1531,22 @@
goto exit_device_probe;
}
}
- if (pdata->info[i].node_info->is_bcm_dev)
+ if (pdata->info[i].node_info->is_bcm_dev) {
ret = msm_bus_bcm_init(node_dev, &pdata->info[i]);
if (ret) {
MSM_BUS_ERR("%s: Error intializing bcm %d",
__func__, pdata->info[i].node_info->id);
goto exit_device_probe;
}
- if (pdata->info[i].node_info->is_rsc_dev)
+ }
+ if (pdata->info[i].node_info->is_rsc_dev) {
ret = msm_bus_rsc_init(pdev, node_dev, &pdata->info[i]);
if (ret) {
MSM_BUS_ERR("%s: Error intializing rsc %d",
__func__, pdata->info[i].node_info->id);
goto exit_device_probe;
}
-
+ }
}
ret = bus_for_each_dev(&msm_bus_type, NULL, NULL,
diff --git a/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c b/drivers/soc/qcom/qdsp6v2/apr_tal_glink.c
index 40a539e..40aac6a 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,
@@ -254,6 +217,7 @@
*/
pr_debug("%s: remote queued an intent\n", __func__);
apr_ch->if_remote_intent_ready = true;
+ wake_up(&apr_ch->wait);
}
void apr_tal_notify_state(void *handle, const void *priv, unsigned int event)
@@ -456,8 +420,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 +435,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 +448,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/qdsp6v2/audio_notifier.c b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
index a2b0f0e..414c123 100644
--- a/drivers/soc/qcom/qdsp6v2/audio_notifier.c
+++ b/drivers/soc/qcom/qdsp6v2/audio_notifier.c
@@ -394,8 +394,8 @@
int ret;
list_for_each_safe(ptr, next, &client_list) {
- client_data = list_entry(ptr,
- struct client_data, list);
+ client_data = list_entry(ptr, struct client_data, list);
+
ret = audio_notifer_reg_client(client_data);
if (ret < 0)
pr_err("%s: audio_notifer_reg_client failed for client %s, ret %d\n",
@@ -518,9 +518,8 @@
goto done;
}
mutex_lock(¬ifier_mutex);
- list_for_each_safe(ptr, next, &client_data->list) {
- client_data = list_entry(ptr, struct client_data,
- list);
+ list_for_each_safe(ptr, next, &client_list) {
+ client_data = list_entry(ptr, struct client_data, list);
if (!strcmp(client_name, client_data->client_name)) {
ret2 = audio_notifer_dereg_client(client_data);
if (ret2 < 0) {
diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c
index 07e8991..f3b1b83 100644
--- a/drivers/soc/qcom/qdsp6v2/voice_svc.c
+++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c
@@ -42,6 +42,12 @@
struct list_head response_queue;
wait_queue_head_t response_wait;
spinlock_t response_lock;
+ /*
+ * This mutex ensures responses are processed in sequential order and
+ * that no two threads access and free the same response at the same
+ * time.
+ */
+ struct mutex response_mutex_lock;
};
struct apr_data {
@@ -361,6 +367,9 @@
struct voice_svc_prvt *prtd;
struct voice_svc_write_msg *data = NULL;
uint32_t cmd;
+ struct voice_svc_register *register_data = NULL;
+ struct voice_svc_cmd_request *request_data = NULL;
+ uint32_t request_payload_size;
pr_debug("%s\n", __func__);
@@ -409,12 +418,19 @@
*/
if (count == (sizeof(struct voice_svc_write_msg) +
sizeof(struct voice_svc_register))) {
- ret = process_reg_cmd(
- (struct voice_svc_register *)data->payload, prtd);
+ register_data =
+ (struct voice_svc_register *)data->payload;
+ if (register_data == NULL) {
+ pr_err("%s: register data is NULL", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = process_reg_cmd(register_data, prtd);
if (!ret)
ret = count;
} else {
- pr_err("%s: invalid payload size\n", __func__);
+ pr_err("%s: invalid data payload size for register command\n",
+ __func__);
ret = -EINVAL;
goto done;
}
@@ -423,19 +439,40 @@
/*
* Check that count reflects the expected size to ensure
* sufficient memory was allocated. Since voice_svc_cmd_request
- * has a variable size, check the minimum value count must be.
+ * has a variable size, check the minimum value count must be to
+ * parse the message request then check the minimum size to hold
+ * the payload of the message request.
*/
if (count >= (sizeof(struct voice_svc_write_msg) +
sizeof(struct voice_svc_cmd_request))) {
- ret = voice_svc_send_req(
- (struct voice_svc_cmd_request *)data->payload, prtd);
- if (!ret)
- ret = count;
- } else {
- pr_err("%s: invalid payload size\n", __func__);
- ret = -EINVAL;
- goto done;
- }
+ request_data =
+ (struct voice_svc_cmd_request *)data->payload;
+ if (request_data == NULL) {
+ pr_err("%s: request data is NULL", __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ request_payload_size = request_data->payload_size;
+
+ if (count >= (sizeof(struct voice_svc_write_msg) +
+ sizeof(struct voice_svc_cmd_request) +
+ request_payload_size)) {
+ ret = voice_svc_send_req(request_data, prtd);
+ if (!ret)
+ ret = count;
+ } else {
+ pr_err("%s: invalid request payload size\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
+ } else {
+ pr_err("%s: invalid data payload size for request command\n",
+ __func__);
+ ret = -EINVAL;
+ goto done;
+ }
break;
default:
pr_debug("%s: Invalid command: %u\n", __func__, cmd);
@@ -466,6 +503,7 @@
goto done;
}
+ mutex_lock(&prtd->response_mutex_lock);
spin_lock_irqsave(&prtd->response_lock, spin_flags);
if (list_empty(&prtd->response_queue)) {
@@ -479,7 +517,7 @@
pr_debug("%s: Read timeout\n", __func__);
ret = -ETIMEDOUT;
- goto done;
+ goto unlock;
} else if (ret > 0 && !list_empty(&prtd->response_queue)) {
pr_debug("%s: Interrupt received for response\n",
__func__);
@@ -487,7 +525,7 @@
pr_debug("%s: Interrupted by SIGNAL %d\n",
__func__, ret);
- goto done;
+ goto unlock;
}
spin_lock_irqsave(&prtd->response_lock, spin_flags);
@@ -506,7 +544,7 @@
__func__, count, size);
ret = -ENOMEM;
- goto done;
+ goto unlock;
}
if (!access_ok(VERIFY_WRITE, arg, size)) {
@@ -514,7 +552,7 @@
__func__);
ret = -EPERM;
- goto done;
+ goto unlock;
}
ret = copy_to_user(arg, &resp->resp,
@@ -524,7 +562,7 @@
pr_err("%s: copy_to_user failed %d\n", __func__, ret);
ret = -EPERM;
- goto done;
+ goto unlock;
}
spin_lock_irqsave(&prtd->response_lock, spin_flags);
@@ -538,6 +576,8 @@
ret = count;
+unlock:
+ mutex_unlock(&prtd->response_mutex_lock);
done:
return ret;
}
@@ -591,6 +631,7 @@
INIT_LIST_HEAD(&prtd->response_queue);
init_waitqueue_head(&prtd->response_wait);
spin_lock_init(&prtd->response_lock);
+ mutex_init(&prtd->response_mutex_lock);
file->private_data = (void *)prtd;
/* Current APR implementation doesn't support session based
@@ -641,6 +682,7 @@
pr_err("%s: Failed to dereg MVM %d\n", __func__, ret);
}
+ mutex_lock(&prtd->response_mutex_lock);
spin_lock_irqsave(&prtd->response_lock, spin_flags);
while (!list_empty(&prtd->response_queue)) {
@@ -654,6 +696,9 @@
}
spin_unlock_irqrestore(&prtd->response_lock, spin_flags);
+ mutex_unlock(&prtd->response_mutex_lock);
+
+ mutex_destroy(&prtd->response_mutex_lock);
kfree(file->private_data);
file->private_data = NULL;
diff --git a/drivers/soc/qcom/qpnp-pbs.c b/drivers/soc/qcom/qpnp-pbs.c
new file mode 100644
index 0000000..287c8a2
--- /dev/null
+++ b/drivers/soc/qcom/qpnp-pbs.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.
+ */
+
+#define pr_fmt(fmt) "PBS: %s: " fmt, __func__
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spmi.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/qpnp/qpnp-pbs.h>
+
+#define QPNP_PBS_DEV_NAME "qcom,qpnp-pbs"
+
+#define PBS_CLIENT_TRIG_CTL 0x42
+#define PBS_CLIENT_SW_TRIG_BIT BIT(7)
+#define PBS_CLIENT_SCRATCH1 0x50
+#define PBS_CLIENT_SCRATCH2 0x51
+
+static LIST_HEAD(pbs_dev_list);
+static DEFINE_MUTEX(pbs_list_lock);
+
+struct qpnp_pbs {
+ struct platform_device *pdev;
+ struct device *dev;
+ struct device_node *dev_node;
+ struct regmap *regmap;
+ struct mutex pbs_lock;
+ struct list_head link;
+
+ u32 base;
+};
+
+static int qpnp_pbs_read(struct qpnp_pbs *pbs, u32 address,
+ u8 *val, int count)
+{
+ int rc = 0;
+ struct platform_device *pdev = pbs->pdev;
+
+ rc = regmap_bulk_read(pbs->regmap, address, val, count);
+ if (rc)
+ pr_err("Failed to read address=0x%02x sid=0x%02x rc=%d\n",
+ address, to_spmi_device(pdev->dev.parent)->usid, rc);
+
+ return rc;
+}
+
+static int qpnp_pbs_write(struct qpnp_pbs *pbs, u16 address,
+ u8 *val, int count)
+{
+ int rc = 0;
+ struct platform_device *pdev = pbs->pdev;
+
+ rc = regmap_bulk_write(pbs->regmap, address, val, count);
+ if (rc < 0)
+ pr_err("Failed to write address =0x%02x sid=0x%02x rc=%d\n",
+ address, to_spmi_device(pdev->dev.parent)->usid, rc);
+ else
+ pr_debug("Wrote 0x%02X to addr 0x%04x\n", *val, address);
+
+ return rc;
+}
+
+static int qpnp_pbs_masked_write(struct qpnp_pbs *pbs, u16 address,
+ u8 mask, u8 val)
+{
+ int rc;
+
+ rc = regmap_update_bits(pbs->regmap, address, mask, val);
+ if (rc < 0)
+ pr_err("Failed to write address 0x%04X, rc = %d\n",
+ address, rc);
+ else
+ pr_debug("Wrote 0x%02X to addr 0x%04X\n",
+ val, address);
+
+ return rc;
+}
+
+static struct qpnp_pbs *get_pbs_client_node(struct device_node *dev_node)
+{
+ struct qpnp_pbs *pbs;
+
+ mutex_lock(&pbs_list_lock);
+ list_for_each_entry(pbs, &pbs_dev_list, link) {
+ if (dev_node == pbs->dev_node) {
+ mutex_unlock(&pbs_list_lock);
+ return pbs;
+ }
+ }
+
+ mutex_unlock(&pbs_list_lock);
+ return ERR_PTR(-EINVAL);
+}
+
+static int qpnp_pbs_wait_for_ack(struct qpnp_pbs *pbs, u8 bit_pos)
+{
+ int rc = 0;
+ u16 retries = 2000, dly = 1000;
+ u8 val;
+
+ while (retries--) {
+ rc = qpnp_pbs_read(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH2, &val, 1);
+ if (rc < 0) {
+ pr_err("Failed to read register %x rc = %d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ return rc;
+ }
+
+ if (val == 0xFF) {
+ /* PBS error - clear SCRATCH2 register */
+ rc = qpnp_pbs_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH2, 0, 1);
+ if (rc < 0) {
+ pr_err("Failed to clear register %x rc=%d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ return rc;
+ }
+
+ pr_err("NACK from PBS for bit %d\n", bit_pos);
+ return -EINVAL;
+ }
+
+ if (val & BIT(bit_pos)) {
+ pr_debug("PBS sequence for bit %d executed!\n",
+ bit_pos);
+ break;
+ }
+
+ usleep_range(dly, dly + 100);
+ }
+
+ if (!retries) {
+ pr_err("Timeout for PBS ACK/NACK for bit %d\n", bit_pos);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+/**
+ * qpnp_pbs_trigger_event - Trigger the PBS RAM sequence
+ *
+ * Returns = 0 If the PBS RAM sequence executed successfully.
+ *
+ * Returns < 0 for errors.
+ *
+ * This function is used to trigger the PBS RAM sequence to be
+ * executed by the client driver.
+ *
+ * The PBS trigger sequence involves
+ * 1. setting the PBS sequence bit in PBS_CLIENT_SCRATCH1
+ * 2. Initiating the SW PBS trigger
+ * 3. Checking the equivalent bit in PBS_CLIENT_SCRATCH2 for the
+ * completion of the sequence.
+ * 4. If PBS_CLIENT_SCRATCH2 == 0xFF, the PBS sequence failed to execute
+ */
+int qpnp_pbs_trigger_event(struct device_node *dev_node, u8 bitmap)
+{
+ struct qpnp_pbs *pbs;
+ int rc = 0;
+ u16 bit_pos = 0;
+ u8 val, mask = 0;
+
+ if (!dev_node)
+ return -EINVAL;
+
+ if (!bitmap) {
+ pr_err("Invalid bitmap passed by client\n");
+ return -EINVAL;
+ }
+
+ pbs = get_pbs_client_node(dev_node);
+ if (IS_ERR_OR_NULL(pbs)) {
+ pr_err("Unable to find the PBS dev_node\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&pbs->pbs_lock);
+ rc = qpnp_pbs_read(pbs, pbs->base + PBS_CLIENT_SCRATCH2, &val, 1);
+ if (rc < 0) {
+ pr_err("read register %x failed rc = %d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ goto out;
+ }
+
+ if (val == 0xFF) {
+ /* PBS error - clear SCRATCH2 register */
+ rc = qpnp_pbs_write(pbs, pbs->base + PBS_CLIENT_SCRATCH2, 0, 1);
+ if (rc < 0) {
+ pr_err("Failed to clear register %x rc=%d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ goto out;
+ }
+ }
+
+ for (bit_pos = 0; bit_pos < 8; bit_pos++) {
+ if (bitmap & BIT(bit_pos)) {
+ /*
+ * Clear the PBS sequence bit position in
+ * PBS_CLIENT_SCRATCH2 mask register.
+ */
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
+ if (rc < 0) {
+ pr_err("Failed to clear %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ goto error;
+ }
+
+ /*
+ * Set the PBS sequence bit position in
+ * PBS_CLIENT_SCRATCH1 register.
+ */
+ val = mask = BIT(bit_pos);
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH1, mask, val);
+ if (rc < 0) {
+ pr_err("Failed to set %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH1, rc);
+ goto error;
+ }
+
+ /* Initiate the SW trigger */
+ val = mask = PBS_CLIENT_SW_TRIG_BIT;
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_TRIG_CTL, mask, val);
+ if (rc < 0) {
+ pr_err("Failed to write register %x rc=%d\n",
+ PBS_CLIENT_TRIG_CTL, rc);
+ goto error;
+ }
+
+ rc = qpnp_pbs_wait_for_ack(pbs, bit_pos);
+ if (rc < 0) {
+ pr_err("Error during wait_for_ack\n");
+ goto error;
+ }
+
+ /*
+ * Clear the PBS sequence bit position in
+ * PBS_CLIENT_SCRATCH1 register.
+ */
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH1, BIT(bit_pos), 0);
+ if (rc < 0) {
+ pr_err("Failed to clear %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH1, rc);
+ goto error;
+ }
+
+ /*
+ * Clear the PBS sequence bit position in
+ * PBS_CLIENT_SCRATCH2 mask register.
+ */
+ rc = qpnp_pbs_masked_write(pbs, pbs->base +
+ PBS_CLIENT_SCRATCH2, BIT(bit_pos), 0);
+ if (rc < 0) {
+ pr_err("Failed to clear %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH2, rc);
+ goto error;
+ }
+
+ }
+ }
+
+error:
+ /* Clear all the requested bitmap */
+ rc = qpnp_pbs_masked_write(pbs, pbs->base + PBS_CLIENT_SCRATCH1,
+ bitmap, 0);
+ if (rc < 0)
+ pr_err("Failed to clear %x reg bit rc=%d\n",
+ PBS_CLIENT_SCRATCH1, rc);
+out:
+ mutex_unlock(&pbs->pbs_lock);
+
+ return rc;
+}
+EXPORT_SYMBOL(qpnp_pbs_trigger_event);
+
+static int qpnp_pbs_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ u32 val = 0;
+ struct qpnp_pbs *pbs;
+
+ pbs = devm_kzalloc(&pdev->dev, sizeof(*pbs), GFP_KERNEL);
+ if (!pbs)
+ return -ENOMEM;
+
+ pbs->pdev = pdev;
+ pbs->dev = &pdev->dev;
+ pbs->dev_node = pdev->dev.of_node;
+ pbs->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!pbs->regmap) {
+ dev_err(&pdev->dev, "Couldn't get parent's regmap\n");
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(pdev->dev.of_node, "reg", &val);
+ if (rc < 0) {
+ dev_err(&pdev->dev,
+ "Couldn't find reg in node = %s rc = %d\n",
+ pdev->dev.of_node->full_name, rc);
+ return rc;
+ }
+
+ pbs->base = val;
+ mutex_init(&pbs->pbs_lock);
+
+ dev_set_drvdata(&pdev->dev, pbs);
+
+ mutex_lock(&pbs_list_lock);
+ list_add(&pbs->link, &pbs_dev_list);
+ mutex_unlock(&pbs_list_lock);
+
+ return 0;
+}
+
+static const struct of_device_id qpnp_pbs_match_table[] = {
+ { .compatible = QPNP_PBS_DEV_NAME },
+ {}
+};
+
+static struct platform_driver qpnp_pbs_driver = {
+ .driver = {
+ .name = QPNP_PBS_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = qpnp_pbs_match_table,
+ },
+ .probe = qpnp_pbs_probe,
+};
+
+static int __init qpnp_pbs_init(void)
+{
+ return platform_driver_register(&qpnp_pbs_driver);
+}
+arch_initcall(qpnp_pbs_init);
+
+static void __exit qpnp_pbs_exit(void)
+{
+ return platform_driver_unregister(&qpnp_pbs_driver);
+}
+module_exit(qpnp_pbs_exit);
+
+MODULE_DESCRIPTION("QPNP PBS DRIVER");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" QPNP_PBS_DEV_NAME);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 996ce64..aeecf29 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -454,7 +454,7 @@
* @n: The array of count of elements in each batch, 0 terminated.
*
* Write a request to the mailbox controller without caching. If the request
- * state is ACTIVE_ONLY, then the requests are treated as completion requests
+ * state is ACTIVE or AWAKE, then the requests are treated as completion request
* and sent to the controller immediately. The function waits until all the
* commands are complete. If the request was to SLEEP or WAKE_ONLY, then the
* request is sent as fire-n-forget and no ack is expected.
@@ -468,7 +468,8 @@
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq);
atomic_t wait_count = ATOMIC_INIT(0); /* overwritten */
int count = 0;
- int ret, i = 0;
+ int ret, i, j, k;
+ bool complete_set;
if (rpmh_standalone)
return 0;
@@ -479,6 +480,27 @@
if (count >= RPMH_MAX_REQ_IN_BATCH)
return -EINVAL;
+ if (state == RPMH_ACTIVE_ONLY_STATE || state == RPMH_AWAKE_STATE) {
+ /*
+ * Ensure the 'complete' bit is set for atleast one command in
+ * each set for active/awake requests.
+ */
+ for (i = 0, k = 0; i < count; i++, k += n[i]) {
+ complete_set = false;
+ for (j = 0; j < n[i]; j++) {
+ if (cmd[k + j].complete) {
+ complete_set = true;
+ break;
+ }
+ }
+ if (!complete_set) {
+ dev_err(rc->dev, "No completion set for batch");
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* Create async request batches */
for (i = 0; i < count; i++) {
rpm_msg[i] = __get_rpmh_msg_async(rc, state, cmd, n[i], false);
if (IS_ERR_OR_NULL(rpm_msg[i]))
@@ -488,11 +510,11 @@
cmd += n[i];
}
- if (state == RPMH_ACTIVE_ONLY_STATE) {
+ /* Send if Active or Awake and wait for the whole set to complete */
+ if (state == RPMH_ACTIVE_ONLY_STATE || state == RPMH_AWAKE_STATE) {
might_sleep();
atomic_set(&wait_count, count);
for (i = 0; i < count; i++) {
- rpm_msg[i]->msg.is_complete = true;
/* Bypass caching and write to mailbox directly */
ret = mbox_send_message(rc->chan, &rpm_msg[i]->msg);
if (ret < 0)
@@ -501,6 +523,7 @@
return wait_event_interruptible(waitq,
atomic_read(&wait_count) == 0);
} else {
+ /* Send Sleep requests to the controller, expect no response */
for (i = 0; i < count; i++) {
ret = mbox_send_controller_data(rc->chan,
&rpm_msg[i]->msg);
diff --git a/drivers/soc/qcom/secure_buffer.c b/drivers/soc/qcom/secure_buffer.c
index b2627f2..f1e7347 100644
--- a/drivers/soc/qcom/secure_buffer.c
+++ b/drivers/soc/qcom/secure_buffer.c
@@ -365,28 +365,19 @@
int source_nelems, int *dest_vmids,
int *dest_perms, int dest_nelems)
{
- struct sg_table *table;
+ struct sg_table table;
int ret;
- table = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
- if (!table)
- return -ENOMEM;
- ret = sg_alloc_table(table, 1, GFP_KERNEL);
+ ret = sg_alloc_table(&table, 1, GFP_KERNEL);
if (ret)
- goto err1;
+ return ret;
- sg_set_page(table->sgl, phys_to_page(addr), size, 0);
+ sg_set_page(table.sgl, phys_to_page(addr), size, 0);
- ret = hyp_assign_table(table, source_vm_list, source_nelems, dest_vmids,
- dest_perms, dest_nelems);
- if (ret)
- goto err2;
+ ret = hyp_assign_table(&table, source_vm_list, source_nelems,
+ dest_vmids, dest_perms, dest_nelems);
- return ret;
-err2:
- sg_free_table(table);
-err1:
- kfree(table);
+ sg_free_table(&table);
return ret;
}
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/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index 4c86197..403c799 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -119,30 +119,30 @@
int div = 0;
int idx;
struct se_geni_rsc *rsc = &mas->spi_rsc;
- int ret = 0;
u32 clk_sel = geni_read_reg(mas->base, SE_GENI_CLK_SEL);
u32 m_clk_cfg = geni_read_reg(mas->base, GENI_SER_M_CLK_CFG);
+ int ret;
clk_sel &= ~CLK_SEL_MSK;
m_clk_cfg &= ~CLK_DIV_MSK;
idx = get_sclk(speed_hz, &sclk_freq);
- if (idx < 0) {
- ret = -EINVAL;
- goto spi_clk_cfg_exit;
- }
- div = (sclk_freq / (SPI_OVERSAMPLING / speed_hz));
+ if (idx < 0)
+ return -EINVAL;
+
+ div = ((sclk_freq / SPI_OVERSAMPLING) / speed_hz);
+ if (!div)
+ return -EINVAL;
clk_sel |= (idx & CLK_SEL_MSK);
m_clk_cfg |= ((div << CLK_DIV_SHFT) | SER_CLK_EN);
ret = clk_set_rate(rsc->se_clk, sclk_freq);
if (ret)
- goto spi_clk_cfg_exit;
+ return ret;
geni_write_reg(clk_sel, mas->base, SE_GENI_CLK_SEL);
geni_write_reg(m_clk_cfg, mas->base, GENI_SER_M_CLK_CFG);
-spi_clk_cfg_exit:
- return ret;
+ return 0;
}
static void spi_setup_word_len(struct spi_geni_master *mas, u32 mode,
@@ -195,7 +195,8 @@
ret = do_spi_clk_cfg(mas->cur_speed_hz, mas);
if (ret) {
- dev_err(&spi_mas->dev, "Err setting clks ret %d\n", ret);
+ dev_err(&spi_mas->dev, "Err setting clks ret(%d) for %d\n",
+ ret, mas->cur_speed_hz);
goto prepare_message_exit;
}
spi_setup_word_len(mas, spi_slv->mode, spi_slv->bits_per_word);
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2fda339..2db473a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -118,6 +118,16 @@
help
Enable this to let the user space manage the platform thermals.
+config THERMAL_GOV_LOW_LIMITS
+ bool "Low limits mitigation governor"
+ help
+ Enable this to manage platform limits using low limits
+ governor.
+
+ Enable this governor to monitor and trigger floor mitigation.
+ This governor will monitor the limits going below a
+ trip threshold to trigger a floor mitigation.
+
config THERMAL_GOV_POWER_ALLOCATOR
bool "Power allocator thermal governor"
help
@@ -454,6 +464,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..2faed7f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -14,6 +14,7 @@
thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG) += gov_bang_bang.o
thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o
+thermal_sys-$(CONFIG_THERMAL_GOV_LOW_LIMITS) += gov_low_limits.o
thermal_sys-$(CONFIG_THERMAL_GOV_POWER_ALLOCATOR) += power_allocator.o
# cpufreq cooling
@@ -57,3 +58,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..a6245d5 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,12 @@
* 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.
+ * @cpufreq_floor_state: integer value representing the frequency floor state
+ * of cpufreq cooling devices.
+ * @floor_freq: integer value representing the absolute value of the floor
+ * frequency.
+ * @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()
@@ -92,6 +99,8 @@
struct thermal_cooling_device *cool_dev;
unsigned int cpufreq_state;
unsigned int clipped_freq;
+ unsigned int cpufreq_floor_state;
+ unsigned int floor_freq;
unsigned int max_level;
unsigned int *freq_table; /* In descending order */
struct cpumask allowed_cpus;
@@ -103,6 +112,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 +172,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;
@@ -218,7 +228,7 @@
unsigned long event, void *data)
{
struct cpufreq_policy *policy = data;
- unsigned long clipped_freq;
+ unsigned long clipped_freq, floor_freq;
struct cpufreq_cooling_device *cpufreq_dev;
if (event != CPUFREQ_ADJUST)
@@ -239,11 +249,16 @@
*
* But, if clipped_freq is greater than policy->max, we don't
* need to do anything.
+ *
+ * Similarly, if policy minimum set by the user is less than
+ * the floor_frequency, then adjust the policy->min.
*/
clipped_freq = cpufreq_dev->clipped_freq;
+ floor_freq = cpufreq_dev->floor_freq;
- if (policy->max > clipped_freq)
- cpufreq_verify_within_limits(policy, 0, clipped_freq);
+ if (policy->max > clipped_freq || policy->min < floor_freq)
+ cpufreq_verify_within_limits(policy, floor_freq,
+ clipped_freq);
break;
}
mutex_unlock(&cooling_list_lock);
@@ -491,6 +506,58 @@
}
/**
+ * cpufreq_get_min_state - callback function to get the device floor state.
+ * @cdev: thermal cooling device pointer.
+ * @state: fill this variable with the cooling device floor.
+ *
+ * Callback for the thermal cooling device to return the cpufreq
+ * floor state.
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+static int cpufreq_get_min_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+
+ *state = cpufreq_device->cpufreq_floor_state;
+
+ return 0;
+}
+
+/**
+ * cpufreq_set_min_state - callback function to set the device floor state.
+ * @cdev: thermal cooling device pointer.
+ * @state: set this variable to the current cooling state.
+ *
+ * Callback for the thermal cooling device to change the cpufreq
+ * floor state.
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+static int cpufreq_set_min_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
+ unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus);
+ unsigned int floor_freq;
+
+ if (state > cpufreq_device->max_level)
+ state = cpufreq_device->max_level;
+
+ if (cpufreq_device->cpufreq_floor_state == state)
+ return 0;
+
+ floor_freq = cpufreq_device->freq_table[state];
+ cpufreq_device->cpufreq_floor_state = state;
+ cpufreq_device->floor_freq = floor_freq;
+
+ cpufreq_update_policy(cpu);
+
+ return 0;
+}
+
+/**
* cpufreq_get_cur_state - callback function to get the current cooling state.
* @cdev: thermal cooling device pointer.
* @state: fill this variable with the current cooling state.
@@ -535,11 +602,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;
}
@@ -745,6 +828,8 @@
.get_max_state = cpufreq_get_max_state,
.get_cur_state = cpufreq_get_cur_state,
.set_cur_state = cpufreq_set_cur_state,
+ .set_min_state = cpufreq_set_min_state,
+ .get_min_state = cpufreq_get_min_state,
};
static struct thermal_cooling_device_ops cpufreq_power_cooling_ops = {
@@ -783,6 +868,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 +883,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 +937,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 +965,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 +974,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;
@@ -901,6 +994,9 @@
goto remove_idr;
cpufreq_dev->clipped_freq = cpufreq_dev->freq_table[0];
+ cpufreq_dev->floor_freq =
+ cpufreq_dev->freq_table[cpufreq_dev->max_level];
+ cpufreq_dev->cpufreq_floor_state = cpufreq_dev->max_level;
cpufreq_dev->cool_dev = cool_dev;
mutex_lock(&cooling_cpufreq_lock);
@@ -949,7 +1045,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 +1069,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 +1099,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 +1159,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/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
index 81631b1..b2990c1 100644
--- a/drivers/thermal/devfreq_cooling.c
+++ b/drivers/thermal/devfreq_cooling.c
@@ -51,6 +51,7 @@
struct thermal_cooling_device *cdev;
struct devfreq *devfreq;
unsigned long cooling_state;
+ unsigned long cooling_min_state;
u32 *power_table;
u32 *freq_table;
size_t freq_table_size;
@@ -96,13 +97,15 @@
/**
* partition_enable_opps() - disable all opps above a given state
* @dfc: Pointer to devfreq we are operating on
- * @cdev_state: cooling device state we're setting
+ * @cdev_max_state: Max cooling device state we're setting
+ * @cdev_min_state: Min cooling device state we're setting
*
* Go through the OPPs of the device, enabling all OPPs until
* @cdev_state and disabling those frequencies above it.
*/
static int partition_enable_opps(struct devfreq_cooling_device *dfc,
- unsigned long cdev_state)
+ unsigned long cdev_max_state,
+ unsigned long cdev_min_state)
{
int i;
struct device *dev = dfc->devfreq->dev.parent;
@@ -111,7 +114,8 @@
struct dev_pm_opp *opp;
int ret = 0;
unsigned int freq = dfc->freq_table[i];
- bool want_enable = i >= cdev_state ? true : false;
+ bool want_enable = (i >= cdev_max_state) &&
+ (i <= cdev_min_state) ? true : false;
rcu_read_lock();
opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
@@ -144,6 +148,41 @@
return 0;
}
+static int devfreq_cooling_get_min_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct devfreq_cooling_device *dfc = cdev->devdata;
+
+ *state = dfc->cooling_min_state;
+
+ return 0;
+}
+
+static int devfreq_cooling_set_min_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct devfreq_cooling_device *dfc = cdev->devdata;
+ struct devfreq *df = dfc->devfreq;
+ struct device *dev = df->dev.parent;
+ int ret;
+
+ if (state == dfc->cooling_min_state)
+ return 0;
+
+ dev_dbg(dev, "Setting cooling min state %lu\n", state);
+
+ if (state >= dfc->freq_table_size)
+ state = dfc->freq_table_size - 1;
+
+ ret = partition_enable_opps(dfc, dfc->cooling_state, state);
+ if (ret)
+ return ret;
+
+ dfc->cooling_min_state = state;
+
+ return 0;
+}
+
static int devfreq_cooling_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
@@ -170,7 +209,7 @@
if (state >= dfc->freq_table_size)
return -EINVAL;
- ret = partition_enable_opps(dfc, state);
+ ret = partition_enable_opps(dfc, state, dfc->cooling_min_state);
if (ret)
return ret;
@@ -361,6 +400,8 @@
.get_max_state = devfreq_cooling_get_max_state,
.get_cur_state = devfreq_cooling_get_cur_state,
.set_cur_state = devfreq_cooling_set_cur_state,
+ .get_min_state = devfreq_cooling_get_min_state,
+ .set_min_state = devfreq_cooling_set_min_state,
};
/**
@@ -499,6 +540,7 @@
if (err)
goto free_tables;
+ dfc->cooling_min_state = dfc->freq_table_size - 1;
snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
cdev = thermal_of_cooling_device_register(np, dev_name, dfc,
diff --git a/drivers/thermal/gov_low_limits.c b/drivers/thermal/gov_low_limits.c
new file mode 100644
index 0000000..cf2dbc4
--- /dev/null
+++ b/drivers/thermal/gov_low_limits.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2012 Intel Corp
+ * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
+ * 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 as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * 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/thermal.h>
+#include <trace/events/thermal.h>
+
+#include "thermal_core.h"
+
+static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
+{
+ int trip_temp, trip_hyst;
+ enum thermal_trip_type trip_type;
+ struct thermal_instance *instance;
+ bool throttle;
+ int old_target;
+
+ tz->ops->get_trip_temp(tz, trip, &trip_temp);
+ tz->ops->get_trip_type(tz, trip, &trip_type);
+ if (tz->ops->get_trip_hyst) {
+ tz->ops->get_trip_hyst(tz, trip, &trip_hyst);
+ trip_hyst = trip_temp + trip_hyst;
+ } else {
+ trip_hyst = trip_temp;
+ }
+
+ mutex_lock(&tz->lock);
+
+ list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+ if (instance->trip != trip)
+ continue;
+
+ if ((tz->temperature <= trip_temp) ||
+ (instance->target != THERMAL_NO_TARGET
+ && tz->temperature <= trip_hyst))
+ throttle = true;
+ else
+ throttle = false;
+
+ dev_dbg(&tz->device,
+ "Trip%d[type=%d,temp=%d,hyst=%d],throttle=%d\n",
+ trip, trip_type, trip_temp, trip_hyst, throttle);
+
+ old_target = instance->target;
+ instance->target = (throttle) ? instance->upper
+ : THERMAL_NO_TARGET;
+ dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
+ old_target, (int)instance->target);
+
+ if (old_target == instance->target)
+ continue;
+
+ if (old_target == THERMAL_NO_TARGET &&
+ instance->target != THERMAL_NO_TARGET) {
+ trace_thermal_zone_trip(tz, trip, trip_type);
+ tz->passive += 1;
+ } else if (old_target != THERMAL_NO_TARGET &&
+ instance->target == THERMAL_NO_TARGET) {
+ tz->passive -= 1;
+ }
+
+ instance->cdev->updated = false; /* cdev needs update */
+ }
+
+ mutex_unlock(&tz->lock);
+}
+
+/**
+ * low_limits_throttle - throttles devices associated with the given zone
+ * @tz - thermal_zone_device
+ * @trip - the trip point
+ *
+ * Throttling Logic: If the sensor reading goes below a trip point, the
+ * pre-defined mitigation will be applied for the cooling device.
+ * If the sensor reading goes above the trip hysteresis, the
+ * mitigation will be removed.
+ */
+static int low_limits_throttle(struct thermal_zone_device *tz, int trip)
+{
+ struct thermal_instance *instance;
+
+ thermal_zone_trip_update(tz, trip);
+
+ mutex_lock(&tz->lock);
+
+ list_for_each_entry(instance, &tz->thermal_instances, tz_node)
+ thermal_cdev_update(instance->cdev);
+
+ mutex_unlock(&tz->lock);
+
+ return 0;
+}
+
+static struct thermal_governor thermal_gov_low_limits_floor = {
+ .name = "low_limits_floor",
+ .throttle = low_limits_throttle,
+ .min_state_throttle = 1,
+};
+
+static struct thermal_governor thermal_gov_low_limits_cap = {
+ .name = "low_limits_cap",
+ .throttle = low_limits_throttle,
+};
+
+int thermal_gov_low_limits_register(void)
+{
+ thermal_register_governor(&thermal_gov_low_limits_cap);
+ return thermal_register_governor(&thermal_gov_low_limits_floor);
+}
+
+void thermal_gov_low_limits_unregister(void)
+{
+ thermal_unregister_governor(&thermal_gov_low_limits_cap);
+ thermal_unregister_governor(&thermal_gov_low_limits_floor);
+}
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 226b0b4ac..7b45b9a 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -49,6 +49,8 @@
MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL v2");
+#define THERMAL_MAX_ACTIVE 16
+
static DEFINE_IDR(thermal_tz_idr);
static DEFINE_IDR(thermal_cdev_idr);
static DEFINE_MUTEX(thermal_idr_lock);
@@ -64,6 +66,8 @@
static struct thermal_governor *def_governor;
+static struct workqueue_struct *thermal_passive_wq;
+
static struct thermal_governor *__find_governor(const char *name)
{
struct thermal_governor *pos;
@@ -392,14 +396,15 @@
mutex_unlock(&thermal_list_lock);
}
-static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
+static void thermal_zone_device_set_polling(struct workqueue_struct *queue,
+ struct thermal_zone_device *tz,
int delay)
{
if (delay > 1000)
- mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+ mod_delayed_work(queue, &tz->poll_queue,
round_jiffies(msecs_to_jiffies(delay)));
else if (delay)
- mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+ mod_delayed_work(queue, &tz->poll_queue,
msecs_to_jiffies(delay));
else
cancel_delayed_work(&tz->poll_queue);
@@ -410,11 +415,13 @@
mutex_lock(&tz->lock);
if (tz->passive)
- thermal_zone_device_set_polling(tz, tz->passive_delay);
+ thermal_zone_device_set_polling(thermal_passive_wq,
+ tz, tz->passive_delay);
else if (tz->polling_delay)
- thermal_zone_device_set_polling(tz, tz->polling_delay);
+ thermal_zone_device_set_polling(system_freezable_wq,
+ tz, tz->polling_delay);
else
- thermal_zone_device_set_polling(tz, 0);
+ thermal_zone_device_set_polling(NULL, tz, 0);
mutex_unlock(&tz->lock);
}
@@ -450,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;
@@ -513,7 +520,6 @@
if (!ret && *temp < crit_temp)
*temp = tz->emul_temperature;
}
-
mutex_unlock(&tz->lock);
exit:
return ret;
@@ -1194,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)
{
@@ -1213,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;
@@ -1222,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;
}
@@ -1235,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,
@@ -1255,6 +1308,7 @@
&dev_attr_cdev_type.attr,
&dev_attr_max_state.attr,
&dev_attr_cur_state.attr,
+ &dev_attr_min_state.attr,
NULL,
};
@@ -1548,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) {
@@ -1682,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*/
@@ -1692,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);
@@ -2069,7 +2135,7 @@
mutex_unlock(&thermal_list_lock);
- thermal_zone_device_set_polling(tz, 0);
+ thermal_zone_device_set_polling(NULL, tz, 0);
if (tz->type[0])
device_remove_file(&tz->device, &dev_attr_type);
@@ -2172,6 +2238,8 @@
.n_mcgrps = ARRAY_SIZE(thermal_event_mcgrps),
};
+static int allow_netlink_events;
+
int thermal_generate_netlink_event(struct thermal_zone_device *tz,
enum events event)
{
@@ -2186,6 +2254,9 @@
if (!tz)
return -EINVAL;
+ if (!allow_netlink_events)
+ return -ENODEV;
+
/* allocate memory */
size = nla_total_size(sizeof(struct thermal_genl_event)) +
nla_total_size(0);
@@ -2237,7 +2308,13 @@
static int genetlink_init(void)
{
- return genl_register_family(&thermal_event_genl_family);
+ int ret;
+
+ ret = genl_register_family(&thermal_event_genl_family);
+ if (!ret)
+ allow_netlink_events = true;
+
+ return ret;
}
static void genetlink_exit(void)
@@ -2247,6 +2324,8 @@
#else /* !CONFIG_NET */
static inline int genetlink_init(void) { return 0; }
static inline void genetlink_exit(void) {}
+static inline int thermal_generate_netlink_event(struct thermal_zone_device *tz,
+ enum events event) { return -ENODEV; }
#endif /* !CONFIG_NET */
static int __init thermal_register_governors(void)
@@ -2269,6 +2348,10 @@
if (result)
return result;
+ result = thermal_gov_low_limits_register();
+ if (result)
+ return result;
+
return thermal_gov_power_allocator_register();
}
@@ -2278,6 +2361,7 @@
thermal_gov_fair_share_unregister();
thermal_gov_bang_bang_unregister();
thermal_gov_user_space_unregister();
+ thermal_gov_low_limits_unregister();
thermal_gov_power_allocator_unregister();
}
@@ -2316,21 +2400,26 @@
{
int result;
+ thermal_passive_wq = alloc_workqueue("thermal_passive_wq",
+ WQ_HIGHPRI | WQ_UNBOUND
+ | WQ_FREEZABLE,
+ THERMAL_MAX_ACTIVE);
+ if (!thermal_passive_wq) {
+ result = -ENOMEM;
+ goto init_exit;
+ }
+
result = thermal_register_governors();
if (result)
- goto error;
+ goto destroy_wq;
result = class_register(&thermal_class);
if (result)
goto unregister_governors;
- result = genetlink_init();
- if (result)
- goto unregister_class;
-
result = of_parse_thermal_zones();
if (result)
- goto exit_netlink;
+ goto exit_zone_parse;
result = register_pm_notifier(&thermal_pm_nb);
if (result)
@@ -2339,13 +2428,13 @@
return 0;
-exit_netlink:
- genetlink_exit();
-unregister_class:
+exit_zone_parse:
class_unregister(&thermal_class);
unregister_governors:
thermal_unregister_governors();
-error:
+destroy_wq:
+ destroy_workqueue(thermal_passive_wq);
+init_exit:
idr_destroy(&thermal_tz_idr);
idr_destroy(&thermal_cdev_idr);
mutex_destroy(&thermal_idr_lock);
@@ -2358,6 +2447,7 @@
{
unregister_pm_notifier(&thermal_pm_nb);
of_thermal_destroy_zones();
+ destroy_workqueue(thermal_passive_wq);
genetlink_exit();
class_unregister(&thermal_class);
thermal_unregister_governors();
@@ -2368,5 +2458,19 @@
mutex_destroy(&thermal_governor_lock);
}
-fs_initcall(thermal_init);
+static int __init thermal_netlink_init(void)
+{
+ int ret = 0;
+
+ ret = genetlink_init();
+ if (!ret)
+ goto exit_netlink;
+
+ thermal_exit();
+exit_netlink:
+ return ret;
+}
+
+subsys_initcall(thermal_init);
+fs_initcall(thermal_netlink_init);
module_exit(thermal_exit);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 749d41a..eca8c3c 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);
@@ -97,6 +98,14 @@
static inline void thermal_gov_power_allocator_unregister(void) {}
#endif /* CONFIG_THERMAL_GOV_POWER_ALLOCATOR */
+#ifdef CONFIG_THERMAL_GOV_LOW_LIMITS
+int thermal_gov_low_limits_register(void);
+void thermal_gov_low_limits_unregister(void);
+#else
+static inline int thermal_gov_low_limits_register(void) { return 0; }
+static inline void thermal_gov_low_limits_unregister(void) {}
+#endif /* CONFIG_THERMAL_GOV_LOW_LIMITS */
+
/* device tree support */
#ifdef CONFIG_THERMAL_OF
int of_parse_thermal_zones(void);
@@ -105,6 +114,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 +135,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/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index a9ded51..bac9975 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1079,6 +1079,12 @@
hardware.
The driver supports console and High speed UART functions.
+config SERIAL_MSM_GENI_CONSOLE
+ tristate "MSM on-chip GENI HW based console support"
+ depends on SERIAL_MSM_GENI=y
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+
config SERIAL_MSM_CONSOLE
bool "MSM serial console support"
depends on SERIAL_MSM=y
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index a115f58..7c4654c 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -313,6 +313,7 @@
}
#endif
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
static void msm_geni_serial_wr_char(struct uart_port *uport, int ch)
{
geni_write_reg(ch, uport->membase, SE_GENI_TX_FIFOn);
@@ -384,6 +385,53 @@
spin_unlock(&uport->lock);
}
+static int handle_rx_console(struct uart_port *uport,
+ unsigned int rx_fifo_wc,
+ unsigned int rx_last_byte_valid,
+ unsigned int rx_last)
+{
+ int i, c;
+ unsigned char *rx_char;
+ struct tty_port *tport;
+ struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+
+ tport = &uport->state->port;
+
+ for (i = 0; i < rx_fifo_wc; i++) {
+ int bytes = 4;
+
+ *(msm_port->rx_fifo) =
+ geni_read_reg(uport->membase, SE_GENI_RX_FIFOn);
+ rx_char = (unsigned char *)msm_port->rx_fifo;
+
+ if (i == (rx_fifo_wc - 1)) {
+ if (rx_last && rx_last_byte_valid)
+ bytes = rx_last_byte_valid;
+ }
+ for (c = 0; c < bytes; c++) {
+ char flag = TTY_NORMAL;
+ int sysrq;
+
+ uport->icount.rx++;
+ sysrq = uart_handle_sysrq_char(uport, rx_char[c]);
+ if (!sysrq)
+ tty_insert_flip_char(tport, rx_char[c], flag);
+ }
+ }
+ tty_flip_buffer_push(tport);
+ return 0;
+}
+#else
+static int handle_rx_console(struct uart_port *uport,
+ unsigned int rx_fifo_wc,
+ unsigned int rx_last_byte_valid,
+ unsigned int rx_last)
+{
+ return -EPERM;
+}
+
+#endif /* (CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)) */
+
static void msm_geni_serial_start_tx(struct uart_port *uport)
{
unsigned int geni_m_irq_en;
@@ -476,43 +524,6 @@
WARN_ON(1);
}
-static int handle_rx_console(struct uart_port *uport,
- unsigned int rx_fifo_wc,
- unsigned int rx_last_byte_valid,
- unsigned int rx_last)
-{
- int i, c;
- unsigned char *rx_char;
- struct tty_port *tport;
- struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
-
- tport = &uport->state->port;
-
- for (i = 0; i < rx_fifo_wc; i++) {
- int bytes = 4;
-
- *(msm_port->rx_fifo) =
- geni_read_reg(uport->membase, SE_GENI_RX_FIFOn);
- rx_char = (unsigned char *)msm_port->rx_fifo;
-
- if (i == (rx_fifo_wc - 1)) {
- if (rx_last && rx_last_byte_valid)
- bytes = rx_last_byte_valid;
- }
- for (c = 0; c < bytes; c++) {
- char flag = TTY_NORMAL;
- int sysrq;
-
- uport->icount.rx++;
- sysrq = uart_handle_sysrq_char(uport, rx_char[c]);
- if (!sysrq)
- tty_insert_flip_char(tport, rx_char[c], flag);
- }
- }
- tty_flip_buffer_push(tport);
- return 0;
-}
-
static int handle_rx_hs(struct uart_port *uport,
unsigned int rx_fifo_wc,
unsigned int rx_last_byte_valid,
@@ -848,7 +859,7 @@
unsigned int stop_bit_len;
unsigned int rxstale;
unsigned int clk_div;
- unsigned long ser_clk_cfg;
+ unsigned long ser_clk_cfg = 0;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
unsigned long clk_rate;
@@ -943,6 +954,7 @@
return is_tx_empty;
}
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
static int __init msm_geni_console_setup(struct console *co, char *options)
{
struct uart_port *uport;
@@ -985,13 +997,100 @@
return uart_set_options(uport, co, baud, parity, bits, flow);
}
-static void msm_geni_serial_debug_init(struct uart_port *uport)
+static void
+msm_geni_serial_early_console_write(struct console *con, const char *s,
+ unsigned int n)
{
- struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+ struct earlycon_device *dev = con->data;
- msm_port->dbg = debugfs_create_dir(dev_name(uport->dev), NULL);
- if (IS_ERR_OR_NULL(msm_port->dbg))
- dev_err(uport->dev, "Failed to create dbg dir\n");
+ __msm_geni_serial_console_write(&dev->port, s, n);
+}
+
+static int __init
+msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
+ const char *opt)
+{
+ struct uart_port *uport = &dev->port;
+ int ret = 0;
+ struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+ u32 tx_trans_cfg = 0;
+ u32 tx_parity_cfg = 0;
+ u32 rx_trans_cfg = 0;
+ u32 rx_parity_cfg = 0;
+ u32 stop_bit = 0;
+ u32 rx_stale = 0;
+ u32 bits_per_char = 0;
+ u32 s_clk_cfg = 0;
+ u32 baud = 115200;
+ u32 clk_div;
+ unsigned long clk_rate;
+
+ if (!uport->membase) {
+ ret = -ENOMEM;
+ goto exit_geni_serial_earlyconsetup;
+ }
+
+ if (get_se_proto(uport->membase) != UART) {
+ ret = -ENXIO;
+ goto exit_geni_serial_earlyconsetup;
+ }
+
+ msm_port->xfer_mode = FIFO_MODE;
+ set_rfr_wm(msm_port);
+ msm_port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
+ msm_port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
+ msm_port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
+ geni_se_init(uport->membase, msm_port->xfer_mode, msm_port->rx_wm,
+ msm_port->rx_rfr);
+ /*
+ * Ignore Flow control.
+ * Disable Tx Parity.
+ * Don't check Parity during Rx.
+ * Disable Rx Parity.
+ * n = 8.
+ * Stop bit = 0.
+ * Stale timeout in bit-time (3 chars worth).
+ */
+ tx_trans_cfg |= UART_CTS_MASK;
+ tx_parity_cfg = 0;
+ rx_trans_cfg = 0;
+ rx_parity_cfg = 0;
+ bits_per_char = 0x8;
+ stop_bit = 0;
+ rx_stale = 0x18;
+ clk_div = get_clk_div_rate(baud, &clk_rate);
+ if (clk_div <= 0) {
+ ret = -EINVAL;
+ goto exit_geni_serial_earlyconsetup;
+ }
+
+ s_clk_cfg |= SER_CLK_EN;
+ s_clk_cfg |= (clk_div << CLK_DIV_SHFT);
+
+ geni_serial_write_term_regs(uport, 0, tx_trans_cfg,
+ tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
+ stop_bit, rx_stale, s_clk_cfg);
+
+ dev->con->write = msm_geni_serial_early_console_write;
+ dev->con->setup = NULL;
+ /*
+ * Ensure that the early console setup completes before
+ * returning.
+ */
+ mb();
+exit_geni_serial_earlyconsetup:
+ return ret;
+}
+OF_EARLYCON_DECLARE(msm_geni_serial, "qcom,msm-geni-uart",
+ msm_geni_serial_earlycon_setup);
+
+static int console_register(struct uart_driver *drv)
+{
+ return uart_register_driver(drv);
+}
+static void console_unregister(struct uart_driver *drv)
+{
+ uart_unregister_driver(drv);
}
static struct console cons_ops = {
@@ -1004,6 +1103,33 @@
.data = &msm_geni_console_driver,
};
+static struct uart_driver msm_geni_console_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "msm_geni_console",
+ .dev_name = "ttyMSM",
+ .nr = GENI_UART_NR_PORTS,
+ .cons = &cons_ops,
+};
+#else
+static int console_register(struct uart_driver *drv)
+{
+ return 0;
+}
+
+static void console_unregister(struct uart_driver *drv)
+{
+}
+#endif /* defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL) */
+
+static void msm_geni_serial_debug_init(struct uart_port *uport)
+{
+ struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
+
+ msm_port->dbg = debugfs_create_dir(dev_name(uport->dev), NULL);
+ if (IS_ERR_OR_NULL(msm_port->dbg))
+ dev_err(uport->dev, "Failed to create dbg dir\n");
+}
+
static const struct uart_ops msm_geni_serial_pops = {
.tx_empty = msm_geni_serial_tx_empty,
.stop_tx = msm_geni_serial_stop_tx,
@@ -1022,8 +1148,10 @@
};
static const struct of_device_id msm_geni_device_tbl[] = {
+#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(CONFIG_CONSOLE_POLL)
{ .compatible = "qcom,msm-geni-console",
.data = (void *)&msm_geni_console_driver},
+#endif
{ .compatible = "qcom,msm-geni-serial-hs",
.data = (void *)&msm_geni_serial_hs_driver},
{},
@@ -1189,92 +1317,6 @@
return 0;
}
-static void
-msm_geni_serial_early_console_write(struct console *con, const char *s,
- unsigned int n)
-{
- struct earlycon_device *dev = con->data;
-
- __msm_geni_serial_console_write(&dev->port, s, n);
-}
-
-static int __init
-msm_geni_serial_earlycon_setup(struct earlycon_device *dev,
- const char *opt)
-{
- struct uart_port *uport = &dev->port;
- int ret = 0;
- struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
- u32 tx_trans_cfg = 0;
- u32 tx_parity_cfg = 0;
- u32 rx_trans_cfg = 0;
- u32 rx_parity_cfg = 0;
- u32 stop_bit = 0;
- u32 rx_stale = 0;
- u32 bits_per_char = 0;
- u32 s_clk_cfg = 0;
- u32 baud = 115200;
- u32 clk_div;
- unsigned long clk_rate;
-
- if (!uport->membase) {
- ret = -ENOMEM;
- goto exit_geni_serial_earlyconsetup;
- }
-
- if (get_se_proto(uport->membase) != UART) {
- ret = -ENXIO;
- goto exit_geni_serial_earlyconsetup;
- }
-
- msm_port->xfer_mode = FIFO_MODE;
- set_rfr_wm(msm_port);
- msm_port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
- msm_port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS;
- msm_port->tx_fifo_width = DEF_FIFO_WIDTH_BITS;
- geni_se_init(uport->membase, msm_port->xfer_mode, msm_port->rx_wm,
- msm_port->rx_rfr);
- /*
- * Ignore Flow control.
- * Disable Tx Parity.
- * Don't check Parity during Rx.
- * Disable Rx Parity.
- * n = 8.
- * Stop bit = 0.
- * Stale timeout in bit-time (3 chars worth).
- */
- tx_trans_cfg |= UART_CTS_MASK;
- tx_parity_cfg = 0;
- rx_trans_cfg = 0;
- rx_parity_cfg = 0;
- bits_per_char = 0x8;
- stop_bit = 0;
- rx_stale = 0x18;
- clk_div = get_clk_div_rate(baud, &clk_rate);
- if (clk_div <= 0) {
- ret = -EINVAL;
- goto exit_geni_serial_earlyconsetup;
- }
-
- s_clk_cfg |= SER_CLK_EN;
- s_clk_cfg |= (clk_div << CLK_DIV_SHFT);
-
- geni_serial_write_term_regs(uport, 0, tx_trans_cfg,
- tx_parity_cfg, rx_trans_cfg, rx_parity_cfg, bits_per_char,
- stop_bit, rx_stale, s_clk_cfg);
-
- dev->con->write = msm_geni_serial_early_console_write;
- dev->con->setup = NULL;
- /*
- * Ensure that the early console setup completes before
- * returning.
- */
- mb();
-exit_geni_serial_earlyconsetup:
- return ret;
-}
-OF_EARLYCON_DECLARE(msm_geni_serial, "qcom,msm-geni-uart",
- msm_geni_serial_earlycon_setup);
#ifdef CONFIG_PM
static int msm_geni_serial_runtime_suspend(struct device *dev)
@@ -1366,13 +1408,6 @@
},
};
-static struct uart_driver msm_geni_console_driver = {
- .owner = THIS_MODULE,
- .driver_name = "msm_geni_console",
- .dev_name = "ttyMSM",
- .nr = GENI_UART_NR_PORTS,
- .cons = &cons_ops,
-};
static struct uart_driver msm_geni_serial_hs_driver = {
.owner = THIS_MODULE,
@@ -1393,7 +1428,7 @@
msm_geni_serial_ports[i].uport.line = i;
}
- ret = uart_register_driver(&msm_geni_console_driver);
+ ret = console_register(&msm_geni_console_driver);
if (ret)
return ret;
@@ -1405,7 +1440,7 @@
ret = platform_driver_register(&msm_geni_serial_platform_driver);
if (ret) {
- uart_unregister_driver(&msm_geni_console_driver);
+ console_unregister(&msm_geni_console_driver);
uart_unregister_driver(&msm_geni_serial_hs_driver);
return ret;
}
@@ -1419,7 +1454,7 @@
{
platform_driver_unregister(&msm_geni_serial_platform_driver);
uart_unregister_driver(&msm_geni_serial_hs_driver);
- uart_unregister_driver(&msm_geni_console_driver);
+ console_unregister(&msm_geni_console_driver);
}
module_exit(msm_geni_serial_exit);
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..cf25708 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1433,7 +1433,7 @@
{
if (IS_ENABLED(CONFIG_HAS_DMA) &&
(urb->transfer_flags & URB_SETUP_MAP_SINGLE))
- dma_unmap_single(hcd->self.controller,
+ dma_unmap_single(hcd->self.sysdev,
urb->setup_dma,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
@@ -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/dwc3/core.c b/drivers/usb/dwc3/core.c
index 94f65e4..33e3d9f 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -740,6 +740,16 @@
}
}
+ /*
+ * Workaround for STAR 9000961433 which affects only version
+ * 3.00a of the DWC_usb3 core. This prevents the controller
+ * interrupt from being masked while handling events. IMOD
+ * allows us to work around this issue. Enable it for the
+ * affected version.
+ */
+ if (!dwc->imod_interval && (dwc->revision == DWC3_REVISION_300A))
+ dwc->imod_interval = 1;
+
/* issue device SoftReset too */
ret = dwc3_core_reset(dwc);
if (ret)
@@ -1109,6 +1119,15 @@
#define DWC3_ALIGN_MASK (16 - 1)
+/* check whether the core supports IMOD */
+bool dwc3_has_imod(struct dwc3 *dwc)
+{
+ return ((dwc3_is_usb3(dwc) &&
+ dwc->revision >= DWC3_REVISION_300A) ||
+ (dwc3_is_usb31(dwc) &&
+ dwc->revision >= DWC3_USB31_REVISION_120A));
+}
+
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1154,8 +1173,8 @@
/* will be enabled in dwc3_msm_resume() */
irq_set_status_flags(irq, IRQ_NOAUTOEN);
- ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt,
- IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
+ ret = devm_request_irq(dev, irq, dwc3_interrupt, IRQF_SHARED, "dwc3",
+ dwc);
if (ret) {
dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
irq, ret);
@@ -1295,6 +1314,14 @@
spin_lock_init(&dwc->lock);
+ dwc->dwc_wq = alloc_ordered_workqueue("dwc_wq", WQ_HIGHPRI);
+ if (!dwc->dwc_wq) {
+ pr_err("%s: Unable to create workqueue dwc_wq\n", __func__);
+ return -ENOMEM;
+ }
+
+ INIT_WORK(&dwc->bh_work, dwc3_bh_work);
+
pm_runtime_no_callbacks(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
@@ -1366,6 +1393,7 @@
* memory region the next time probe is called.
*/
res->start -= DWC3_GLOBALS_REGS_START;
+ destroy_workqueue(dwc->dwc_wq);
return ret;
}
@@ -1389,6 +1417,8 @@
dwc3_core_exit(dwc);
dwc3_ulpi_exit(dwc);
+ destroy_workqueue(dwc->dwc_wq);
+
pm_runtime_put_sync(&pdev->dev);
pm_runtime_allow(&pdev->dev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 7968901..009193c 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -68,6 +68,7 @@
#define DWC3_DEVICE_EVENT_OVERFLOW 11
#define DWC3_GEVNTCOUNT_MASK 0xfffc
+#define DWC3_GEVNTCOUNT_EHB (1 << 31)
#define DWC3_GSNPSID_MASK 0xffff0000
#define DWC3_GSNPSREV_MASK 0xffff
@@ -150,6 +151,8 @@
#define DWC3_DEPCMDPAR0 0x08
#define DWC3_DEPCMD 0x0c
+#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4))
+
/* OTG Registers */
#define DWC3_OCFG 0xcc00
#define DWC3_OCTL 0xcc04
@@ -485,6 +488,11 @@
#define DWC3_DEPCMD_TYPE_BULK 2
#define DWC3_DEPCMD_TYPE_INTR 3
+#define DWC3_DEV_IMOD_COUNT_SHIFT 16
+#define DWC3_DEV_IMOD_COUNT_MASK (0xffff << 16)
+#define DWC3_DEV_IMOD_INTERVAL_SHIFT 0
+#define DWC3_DEV_IMOD_INTERVAL_MASK (0xffff << 0)
+
#define DWC_CTRL_COUNT 10
#define NUM_LOG_PAGES 12
@@ -939,6 +947,8 @@
* @vbus_draw: current to be drawn from USB
* @index: dwc3 instance's number
* @dwc_ipc_log_ctxt: dwc3 ipc log context
+ * @imod_interval: set the interrupt moderation interval in 250ns
+ * increments or 0 to disable.
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
@@ -1027,6 +1037,7 @@
*/
#define DWC3_REVISION_IS_DWC31 0x80000000
#define DWC3_USB31_REVISION_110A (0x3131302a | DWC3_REVISION_IS_DWC31)
+#define DWC3_USB31_REVISION_120A (0x3132302a | DWC3_REVISION_IS_DWC31)
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@@ -1108,6 +1119,11 @@
bool b_suspend;
unsigned int vbus_draw;
+ u16 imod_interval;
+
+ struct workqueue_struct *dwc_wq;
+ struct work_struct bh_work;
+
/* IRQ timing statistics */
int irq;
unsigned long ep_cmd_timeout_cnt;
@@ -1283,12 +1299,20 @@
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
+/* check whether we are on the DWC_usb3 core */
+static inline bool dwc3_is_usb3(struct dwc3 *dwc)
+{
+ return !(dwc->revision & DWC3_REVISION_IS_DWC31);
+}
+
/* check whether we are on the DWC_usb31 core */
static inline bool dwc3_is_usb31(struct dwc3 *dwc)
{
return !!(dwc->revision & DWC3_REVISION_IS_DWC31);
}
+bool dwc3_has_imod(struct dwc3 *dwc);
+
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 8d2b429..96684f4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -215,6 +215,8 @@
unsigned int irq_to_affin;
struct notifier_block dwc3_cpu_notifier;
+ struct notifier_block usbdev_nb;
+ bool hc_died;
struct extcon_dev *extcon_vbus;
struct extcon_dev *extcon_id;
@@ -1506,6 +1508,33 @@
flush_delayed_work(&mdwc->sm_work);
}
+static int msm_dwc3_usbdev_notify(struct notifier_block *self,
+ unsigned long action, void *priv)
+{
+ struct dwc3_msm *mdwc = container_of(self, struct dwc3_msm, usbdev_nb);
+ struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
+ struct usb_bus *bus = priv;
+
+ /* Interested only in recovery when HC dies */
+ if (action != USB_BUS_DIED)
+ return 0;
+
+ dev_dbg(mdwc->dev, "%s initiate recovery from hc_died\n", __func__);
+ /* Recovery already under process */
+ if (mdwc->hc_died)
+ return 0;
+
+ if (bus->controller != &dwc->xhci->dev) {
+ dev_dbg(mdwc->dev, "%s event for diff HCD\n", __func__);
+ return 0;
+ }
+
+ mdwc->hc_died = true;
+ schedule_delayed_work(&mdwc->sm_work, 0);
+ return 0;
+}
+
+
/*
* Check whether the DWC3 requires resetting the ep
* after going to Low Power Mode (lpm)
@@ -2045,6 +2074,9 @@
if (dwc->irq)
disable_irq(dwc->irq);
+ if (work_busy(&dwc->bh_work))
+ dbg_event(0xFF, "pend evt", 0);
+
/* disable power event irq, hs and ss phy irq is used as wake up src */
disable_irq(mdwc->pwr_event_irq);
@@ -2095,8 +2127,10 @@
dwc3_msm_config_gdsc(mdwc, 0);
clk_disable_unprepare(mdwc->sleep_clk);
- if (mdwc->iommu_map)
+ if (mdwc->iommu_map) {
arm_iommu_detach_device(mdwc->dev);
+ dev_dbg(mdwc->dev, "IOMMU detached\n");
+ }
}
/* Remove bus voting */
@@ -2230,6 +2264,16 @@
if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) {
u32 tmp;
+ if (mdwc->iommu_map) {
+ ret = arm_iommu_attach_device(mdwc->dev,
+ mdwc->iommu_map);
+ if (ret)
+ dev_err(mdwc->dev, "IOMMU attach failed (%d)\n",
+ ret);
+ else
+ dev_dbg(mdwc->dev, "attached to IOMMU\n");
+ }
+
dev_dbg(mdwc->dev, "%s: exit power collapse\n", __func__);
dwc3_msm_power_collapse_por(mdwc);
@@ -2242,16 +2286,6 @@
PWR_EVNT_POWERDOWN_IN_P3_MASK, 1);
mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE;
-
- if (mdwc->iommu_map) {
- ret = arm_iommu_attach_device(mdwc->dev,
- mdwc->iommu_map);
- if (ret)
- dev_err(mdwc->dev, "IOMMU attach failed (%d)\n",
- ret);
- else
- dev_dbg(mdwc->dev, "attached to IOMMU\n");
- }
}
atomic_set(&dwc->in_lpm, 0);
@@ -2788,7 +2822,7 @@
static int dwc3_msm_init_iommu(struct dwc3_msm *mdwc)
{
struct device_node *node = mdwc->dev->of_node;
- int atomic_ctx = 1;
+ int atomic_ctx = 1, s1_bypass;
int ret;
if (!of_property_read_bool(node, "iommus"))
@@ -2809,12 +2843,31 @@
if (ret) {
dev_err(mdwc->dev, "IOMMU set atomic attribute failed (%d)\n",
ret);
- arm_iommu_release_mapping(mdwc->iommu_map);
- mdwc->iommu_map = NULL;
- return ret;
+ goto release_mapping;
}
+ s1_bypass = of_property_read_bool(node, "qcom,smmu-s1-bypass");
+ ret = iommu_domain_set_attr(mdwc->iommu_map->domain,
+ DOMAIN_ATTR_S1_BYPASS, &s1_bypass);
+ if (ret) {
+ dev_err(mdwc->dev, "IOMMU set s1 bypass (%d) failed (%d)\n",
+ s1_bypass, ret);
+ goto release_mapping;
+ }
+
+ ret = arm_iommu_attach_device(mdwc->dev, mdwc->iommu_map);
+ if (ret) {
+ dev_err(mdwc->dev, "IOMMU attach failed (%d)\n", ret);
+ goto release_mapping;
+ }
+ dev_dbg(mdwc->dev, "attached to IOMMU\n");
+
return 0;
+
+release_mapping:
+ arm_iommu_release_mapping(mdwc->iommu_map);
+ mdwc->iommu_map = NULL;
+ return ret;
}
static ssize_t mode_show(struct device *dev, struct device_attribute *attr,
@@ -3184,6 +3237,10 @@
ret = of_property_read_u32(node, "qcom,num-gsi-evt-buffs",
&mdwc->num_gsi_event_buffers);
+ /* IOMMU will be reattached upon each resume/connect */
+ if (mdwc->iommu_map)
+ arm_iommu_detach_device(mdwc->dev);
+
/*
* Clocks and regulators will not be turned on until the first time
* runtime PM resume is called. This is to allow for booting up with
@@ -3250,8 +3307,10 @@
if (mdwc->bus_perf_client)
msm_bus_scale_unregister_client(mdwc->bus_perf_client);
uninit_iommu:
- if (mdwc->iommu_map)
+ if (mdwc->iommu_map) {
+ arm_iommu_detach_device(mdwc->dev);
arm_iommu_release_mapping(mdwc->iommu_map);
+ }
err:
return ret;
}
@@ -3509,6 +3568,8 @@
mdwc->host_nb.notifier_call = dwc3_msm_host_notifier;
usb_register_notify(&mdwc->host_nb);
+ mdwc->usbdev_nb.notifier_call = msm_dwc3_usbdev_notify;
+ usb_register_atomic_notify(&mdwc->usbdev_nb);
/*
* FIXME If micro A cable is disconnected during system suspend,
* xhci platform device will be removed before runtime pm is
@@ -3562,6 +3623,7 @@
} else {
dev_dbg(mdwc->dev, "%s: turn off host\n", __func__);
+ usb_unregister_atomic_notify(&mdwc->usbdev_nb);
if (!IS_ERR(mdwc->vbus_reg))
ret = regulator_disable(mdwc->vbus_reg);
if (ret) {
@@ -3884,11 +3946,12 @@
break;
case OTG_STATE_A_HOST:
- if (test_bit(ID, &mdwc->inputs)) {
- dev_dbg(mdwc->dev, "id\n");
+ if (test_bit(ID, &mdwc->inputs) || mdwc->hc_died) {
+ dev_dbg(mdwc->dev, "id || hc_died\n");
dwc3_otg_start_host(mdwc, 0);
mdwc->otg_state = OTG_STATE_B_IDLE;
mdwc->vbus_retry_count = 0;
+ mdwc->hc_died = false;
work = 1;
} else {
dev_dbg(mdwc->dev, "still in a_host state. Resuming root hub.\n");
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 264d9af..a5d3209f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -2099,6 +2099,18 @@
u32 reg;
dbg_event(0xFF, "__Gadgetstart", 0);
+
+ /*
+ * Use IMOD if enabled via dwc->imod_interval. Otherwise, if
+ * the core supports IMOD, disable it.
+ */
+ if (dwc->imod_interval) {
+ dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
+ } else if (dwc3_has_imod(dwc)) {
+ dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
+ }
+
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
@@ -3473,8 +3485,6 @@
*/
evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
left -= 4;
-
- dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), 4);
}
dwc->bh_handled_evt_cnt[dwc->bh_dbg_index] += (evt->count / 4);
@@ -3487,9 +3497,22 @@
reg &= ~DWC3_GEVNTSIZ_INTMASK;
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
+ if (dwc->imod_interval)
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0),
+ DWC3_GEVNTCOUNT_EHB);
+
return ret;
}
+void dwc3_bh_work(struct work_struct *w)
+{
+ struct dwc3 *dwc = container_of(w, struct dwc3, bh_work);
+
+ pm_runtime_get_sync(dwc->dev);
+ dwc3_thread_interrupt(dwc->irq, dwc);
+ pm_runtime_put(dwc->dev);
+}
+
static irqreturn_t dwc3_thread_interrupt(int irq, void *_dwc)
{
struct dwc3 *dwc = _dwc;
@@ -3543,6 +3566,8 @@
reg |= DWC3_GEVNTSIZ_INTMASK;
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), reg);
+ dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
+
return IRQ_WAKE_THREAD;
}
@@ -3572,7 +3597,7 @@
dwc->irq_dbg_index = (dwc->irq_dbg_index + 1) % MAX_INTR_STATS;
if (ret == IRQ_WAKE_THREAD)
- dwc3_thread_interrupt(dwc->irq, dwc);
+ queue_work(dwc->dwc_wq, &dwc->bh_work);
return IRQ_HANDLED;
}
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 990f423..e973ad3 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -97,6 +97,7 @@
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol);
void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
irqreturn_t dwc3_interrupt(int irq, void *_dwc);
+void dwc3_bh_work(struct work_struct *w);
static inline dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
struct dwc3_trb *trb)
diff --git a/drivers/usb/gadget/function/f_accessory.c b/drivers/usb/gadget/function/f_accessory.c
index daca68b..46df732 100644
--- a/drivers/usb/gadget/function/f_accessory.c
+++ b/drivers/usb/gadget/function/f_accessory.c
@@ -611,8 +611,7 @@
{
struct acc_dev *dev = fp->private_data;
struct usb_request *req;
- ssize_t r = count;
- unsigned xfer;
+ ssize_t r = count, xfer, len;
int ret = 0;
pr_debug("acc_read(%zu)\n", count);
@@ -633,6 +632,8 @@
goto done;
}
+ len = ALIGN(count, dev->ep_out->maxpacket);
+
if (dev->rx_done) {
// last req cancelled. try to get it.
req = dev->rx_req[0];
@@ -642,7 +643,7 @@
requeue_req:
/* queue a request */
req = dev->rx_req[0];
- req->length = count;
+ req->length = len;
dev->rx_done = 0;
ret = usb_ep_queue(dev->ep_out, req, GFP_KERNEL);
if (ret < 0) {
@@ -941,6 +942,8 @@
memset(dev->serial, 0, sizeof(dev->serial));
dev->start_requested = 0;
dev->audio_mode = 0;
+ strlcpy(dev->manufacturer, "Android", ACC_STRING_SIZE);
+ strlcpy(dev->model, "Android", ACC_STRING_SIZE);
}
}
@@ -1251,13 +1254,13 @@
INIT_DELAYED_WORK(&dev->start_work, acc_start_work);
INIT_WORK(&dev->hid_work, acc_hid_work);
- /* _acc_dev must be set before calling usb_gadget_register_driver */
- _acc_dev = dev;
-
ret = misc_register(&acc_device);
if (ret)
goto err;
+ /* _acc_dev must be set before calling usb_gadget_register_driver */
+ _acc_dev = dev;
+
return 0;
err:
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_audio_source.c b/drivers/usb/gadget/function/f_audio_source.c
index db7903d..a2a9185 100644
--- a/drivers/usb/gadget/function/f_audio_source.c
+++ b/drivers/usb/gadget/function/f_audio_source.c
@@ -989,6 +989,7 @@
struct device *create_function_device(char *name);
+#define AUDIO_SOURCE_DEV_NAME_LENGTH 20
static struct usb_function_instance *audio_source_alloc_inst(void)
{
struct audio_source_instance *fi_audio;
@@ -997,6 +998,8 @@
struct device *dev;
void *err_ptr;
int err = 0;
+ char device_name[AUDIO_SOURCE_DEV_NAME_LENGTH];
+ static u8 count;
fi_audio = kzalloc(sizeof(*fi_audio), GFP_KERNEL);
if (!fi_audio)
@@ -1014,7 +1017,11 @@
config_group_init_type_name(&fi_audio->func_inst.group, "",
&audio_source_func_type);
- dev = create_function_device("f_audio_source");
+
+ snprintf(device_name, AUDIO_SOURCE_DEV_NAME_LENGTH,
+ "f_audio_source%d", count++);
+
+ dev = create_function_device(device_name);
if (IS_ERR(dev)) {
err_ptr = dev;
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index c807b12..12e94d5 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -1562,13 +1562,6 @@
event->bNotificationType, req->status);
/* FALLTHROUGH */
case 0:
- /*
- * handle multiple pending resp available
- * notifications by queuing same until we're done,
- * rest of the notification require queuing new
- * request.
- */
- gsi_ctrl_send_notification(gsi);
break;
}
}
@@ -1663,6 +1656,14 @@
gsi_ctrl_send_cpkt_tomodem(gsi, req->buf, 0);
}
+static void gsi_ctrl_send_response_complete(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct f_gsi *gsi = req->context;
+
+ gsi_ctrl_send_notification(gsi);
+}
+
static int
gsi_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
@@ -1749,6 +1750,8 @@
memcpy(req->buf, cpkt->buf, value);
gsi_ctrl_pkt_free(cpkt);
+ req->complete = gsi_ctrl_send_response_complete;
+ req->context = gsi;
log_event_dbg("copied encap_resp %d bytes",
value);
break;
@@ -3047,6 +3050,9 @@
{
struct gsi_opts *opts = container_of(f, struct gsi_opts, func_inst);
+ if (!opts->gsi)
+ return;
+
if (opts->gsi->c_port.ctrl_device.fops)
misc_deregister(&opts->gsi->c_port.ctrl_device);
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index a832d27..fbe6910 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -1284,7 +1284,7 @@
card = midi->card;
midi->card = NULL;
if (card)
- snd_card_free(card);
+ snd_card_free_when_closed(card);
usb_free_all_descriptors(f);
}
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/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 7558021..681b77a 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -407,11 +407,20 @@
return -ENOMEM;
}
- xhci_queue_stop_endpoint(xhci, command, slot_id, i,
- suspend);
+
+ ret = xhci_queue_stop_endpoint(xhci, command, slot_id,
+ i, suspend);
+ if (ret) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ goto err_cmd_queue;
+ }
}
}
- xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
+ ret = xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);
+ if (ret) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ goto err_cmd_queue;
+ }
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -422,6 +431,8 @@
xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");
ret = -ETIME;
}
+
+err_cmd_queue:
xhci_free_command(xhci, cmd);
return ret;
}
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index f33f972..6d5f01a 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -136,6 +136,59 @@
MODULE_DEVICE_TABLE(of, usb_xhci_of_match);
#endif
+static ssize_t config_imod_store(struct device *pdev,
+ struct device_attribute *attr, const char *buff, size_t size)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(pdev);
+ struct xhci_hcd *xhci;
+ u32 temp;
+ u32 imod;
+ unsigned long flags;
+
+ if (kstrtouint(buff, 10, &imod) != 1)
+ return 0;
+
+ imod &= ER_IRQ_INTERVAL_MASK;
+ xhci = hcd_to_xhci(hcd);
+
+ if (xhci->shared_hcd->state == HC_STATE_SUSPENDED
+ && hcd->state == HC_STATE_SUSPENDED)
+ return -EACCES;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ temp = readl_relaxed(&xhci->ir_set->irq_control);
+ temp &= ~ER_IRQ_INTERVAL_MASK;
+ temp |= imod;
+ writel_relaxed(temp, &xhci->ir_set->irq_control);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ return size;
+}
+
+static ssize_t config_imod_show(struct device *pdev,
+ struct device_attribute *attr, char *buff)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(pdev);
+ struct xhci_hcd *xhci;
+ u32 temp;
+ unsigned long flags;
+
+ xhci = hcd_to_xhci(hcd);
+
+ if (xhci->shared_hcd->state == HC_STATE_SUSPENDED
+ && hcd->state == HC_STATE_SUSPENDED)
+ return -EACCES;
+
+ spin_lock_irqsave(&xhci->lock, flags);
+ temp = readl_relaxed(&xhci->ir_set->irq_control) &
+ ER_IRQ_INTERVAL_MASK;
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
+ return snprintf(buff, PAGE_SIZE, "%08u\n", temp);
+}
+
+static DEVICE_ATTR(config_imod, 0644, config_imod_show, config_imod_store);
+
static int xhci_plat_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
@@ -267,17 +320,22 @@
goto put_usb3_hcd;
}
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (ret)
goto disable_usb_phy;
if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
xhci->shared_hcd->can_do_streams = 1;
- ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
if (ret)
goto dealloc_usb2_hcd;
+ ret = device_create_file(&pdev->dev, &dev_attr_config_imod);
+ if (ret)
+ dev_err(&pdev->dev, "%s: unable to create imod sysfs entry\n",
+ __func__);
+
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(&pdev->dev);
@@ -312,6 +370,7 @@
pm_runtime_disable(&dev->dev);
xhci->xhc_state |= XHCI_STATE_REMOVING;
+ device_remove_file(&dev->dev, &dev_attr_config_imod);
usb_remove_hcd(xhci->shared_hcd);
usb_phy_shutdown(hcd->usb_phy);
@@ -352,7 +411,7 @@
dev_dbg(dev, "xhci-plat runtime suspend\n");
- return xhci_suspend(xhci, true);
+ return 0;
}
static int xhci_plat_runtime_resume(struct device *dev)
@@ -366,7 +425,7 @@
dev_dbg(dev, "xhci-plat runtime resume\n");
- ret = xhci_resume(xhci, false);
+ ret = 0;
pm_runtime_mark_last_busy(dev);
return ret;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e7e9c07..5d434e0 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -675,7 +675,7 @@
void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct xhci_ring *ring,
struct xhci_td *td)
{
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
struct xhci_segment *seg = td->bounce_seg;
struct urb *urb = td->urb;
@@ -3153,7 +3153,7 @@
static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
u32 *trb_buff_len, struct xhci_segment *seg)
{
- struct device *dev = xhci_to_hcd(xhci)->self.controller;
+ struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
unsigned int unalign;
unsigned int max_pkt;
u32 new_buff_len;
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/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 288318a..16c8fcf 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -199,6 +199,11 @@
if (rc)
return rc;
+ bd->usr_brightness_req = brightness;
+ brightness = (brightness <= bd->thermal_brightness_limit) ?
+ bd->usr_brightness_req :
+ bd->thermal_brightness_limit;
+
rc = backlight_device_set_brightness(bd, brightness);
return rc ? rc : count;
@@ -310,6 +315,63 @@
}
EXPORT_SYMBOL(backlight_force_update);
+static int bd_cdev_get_max_brightness(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct backlight_device *bd = (struct backlight_device *)cdev->devdata;
+
+ *state = bd->props.max_brightness;
+
+ return 0;
+}
+
+static int bd_cdev_get_cur_brightness(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct backlight_device *bd = (struct backlight_device *)cdev->devdata;
+
+ *state = bd->props.max_brightness - bd->thermal_brightness_limit;
+
+ return 0;
+}
+
+static int bd_cdev_set_cur_brightness(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct backlight_device *bd = (struct backlight_device *)cdev->devdata;
+ int brightness_lvl;
+
+ brightness_lvl = bd->props.max_brightness - state;
+ if (brightness_lvl == bd->thermal_brightness_limit)
+ return 0;
+
+ bd->thermal_brightness_limit = brightness_lvl;
+ brightness_lvl = (bd->usr_brightness_req
+ <= bd->thermal_brightness_limit) ?
+ bd->usr_brightness_req :
+ bd->thermal_brightness_limit;
+ backlight_device_set_brightness(bd, brightness_lvl);
+
+ return 0;
+}
+
+static struct thermal_cooling_device_ops bd_cdev_ops = {
+ .get_max_state = bd_cdev_get_max_brightness,
+ .get_cur_state = bd_cdev_get_cur_brightness,
+ .set_cur_state = bd_cdev_set_cur_brightness,
+};
+
+static void backlight_cdev_register(struct device *parent,
+ struct backlight_device *bd)
+{
+ if (of_find_property(parent->of_node, "#cooling-cells", NULL)) {
+ bd->cdev = thermal_of_cooling_device_register(parent->of_node,
+ (char *)dev_name(&bd->dev), bd, &bd_cdev_ops);
+ if (!bd->cdev)
+ pr_err("Cooling device register failed\n");
+ }
+}
+
/**
* backlight_device_register - create and register a new object of
* backlight_device class.
@@ -353,6 +415,8 @@
WARN(1, "%s: invalid backlight type", name);
new_bd->props.type = BACKLIGHT_RAW;
}
+ new_bd->thermal_brightness_limit = props->max_brightness;
+ new_bd->usr_brightness_req = props->brightness;
} else {
new_bd->props.type = BACKLIGHT_RAW;
}
@@ -369,6 +433,7 @@
return ERR_PTR(rc);
}
+ backlight_cdev_register(parent, new_bd);
new_bd->ops = ops;
#ifdef CONFIG_PMAC_BACKLIGHT
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/dt-bindings/msm/msm-bus-ids.h b/include/dt-bindings/msm/msm-bus-ids.h
index 900f268..8135da9 100644
--- a/include/dt-bindings/msm/msm-bus-ids.h
+++ b/include/dt-bindings/msm/msm-bus-ids.h
@@ -42,6 +42,7 @@
#define MSM_BUS_FAB_DC_NOC 6150
#define MSM_BUS_FAB_MC_VIRT 6151
#define MSM_BUS_FAB_MEM_NOC 6152
+#define MSM_BUS_FAB_IPA_VIRT 6153
#define MSM_BUS_FAB_MC_VIRT_DISPLAY 26000
#define MSM_BUS_FAB_MEM_NOC_DISPLAY 26001
@@ -86,6 +87,7 @@
#define MSM_BUS_BCM_CN0 7036
#define MSM_BUS_BCM_ACV 7037
#define MSM_BUS_BCM_ALC 7038
+#define MSM_BUS_BCM_QUP0 7039
#define MSM_BUS_RSC_APPS 8000
#define MSM_BUS_RSC_DISP 8001
@@ -241,7 +243,8 @@
#define MSM_BUS_MASTER_ANOC_PCIE_SNOC 140
#define MSM_BUS_MASTER_PIMEM 141
#define MSM_BUS_MASTER_MEM_NOC_SNOC 142
-#define MSM_BUS_MASTER_MASTER_LAST 143
+#define MSM_BUS_MASTER_IPA_CORE 143
+#define MSM_BUS_MASTER_MASTER_LAST 144
#define MSM_BUS_MASTER_LLCC_DISPLAY 20000
#define MSM_BUS_MASTER_MNOC_HF_MEM_NOC_DISPLAY 20001
@@ -579,7 +582,8 @@
#define MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 774
#define MSM_BUS_SLAVE_SNOC_MEM_NOC_SF 775
#define MSM_BUS_SLAVE_MEM_NOC_SNOC 776
-#define MSM_BUS_SLAVE_LAST 777
+#define MSM_BUS_SLAVE_IPA 777
+#define MSM_BUS_SLAVE_LAST 778
#define MSM_BUS_SLAVE_EBI_CH0_DISPLAY 20512
#define MSM_BUS_SLAVE_LLCC_DISPLAY 20513
diff --git a/include/linux/backlight.h b/include/linux/backlight.h
index 5f2fd61..d5ff4c30 100644
--- a/include/linux/backlight.h
+++ b/include/linux/backlight.h
@@ -12,6 +12,7 @@
#include <linux/fb.h>
#include <linux/mutex.h>
#include <linux/notifier.h>
+#include <linux/thermal.h>
/* Notes on locking:
*
@@ -110,6 +111,12 @@
struct list_head entry;
struct device dev;
+ /* Backlight cooling device */
+ struct thermal_cooling_device *cdev;
+ /* Thermally limited max brightness */
+ int thermal_brightness_limit;
+ /* User brightness request */
+ int usr_brightness_req;
/* Multiple framebuffers may share one backlight device */
bool fb_bl_on[FB_MAX];
diff --git a/include/linux/bug.h b/include/linux/bug.h
index 292d6a1..6f3da08 100644
--- a/include/linux/bug.h
+++ b/include/linux/bug.h
@@ -121,4 +121,10 @@
}
#endif /* CONFIG_GENERIC_BUG */
+
+#ifdef CONFIG_PANIC_ON_DATA_CORRUPTION
+#define PANIC_CORRUPTION 1
+#else
+#define PANIC_CORRUPTION 0
+#endif /* CONFIG_PANIC_ON_DATA_CORRUPTION */
#endif /* _LINUX_BUG_H */
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/clk-provider.h b/include/linux/clk-provider.h
index 31a7f91..8fd5fba 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -36,6 +36,8 @@
#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
/* parents need enable during gate/ungate, set rate and re-parent */
#define CLK_OPS_PARENT_ENABLE BIT(12)
+ /* unused */
+#define CLK_IS_MEASURE BIT(14) /* measure clock */
struct clk;
struct clk_hw;
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/devfreq_cooling.h b/include/linux/devfreq_cooling.h
index 7adf6cc..374eb79 100644
--- a/include/linux/devfreq_cooling.h
+++ b/include/linux/devfreq_cooling.h
@@ -20,8 +20,6 @@
#include <linux/devfreq.h>
#include <linux/thermal.h>
-#ifdef CONFIG_DEVFREQ_THERMAL
-
/**
* struct devfreq_cooling_power - Devfreq cooling power ops
* @get_static_power: Take voltage, in mV, and return the static power
@@ -43,6 +41,8 @@
unsigned long dyn_power_coeff;
};
+#ifdef CONFIG_DEVFREQ_THERMAL
+
struct thermal_cooling_device *
of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
struct devfreq_cooling_power *dfc_power);
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/ipa.h b/include/linux/ipa.h
index 16d3d26..0668534 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -98,7 +98,7 @@
};
/**
- * enum hdr_total_len_or_pad_type - type vof value held by TOTAL_LEN_OR_PAD
+ * enum hdr_total_len_or_pad_type - type of value held by TOTAL_LEN_OR_PAD
* field in header configuration register.
* @IPA_HDR_PAD: field is used as padding length
* @IPA_HDR_TOTAL_LEN: field is used as total length
@@ -433,6 +433,55 @@
unsigned long data);
/**
+ * enum ipa_wdi_meter_evt_type - type of event client callback is
+ * for AP+STA mode metering
+ * @IPA_GET_WDI_SAP_STATS: get IPA_stats betwen SAP and STA -
+ * use ipa_get_wdi_sap_stats structure
+ * @IPA_SET_WIFI_QUOTA: set quota limit on STA -
+ * use ipa_set_wifi_quota structure
+ */
+enum ipa_wdi_meter_evt_type {
+ IPA_GET_WDI_SAP_STATS,
+ IPA_SET_WIFI_QUOTA,
+};
+
+struct ipa_get_wdi_sap_stats {
+ /* indicate to reset stats after query */
+ uint8_t reset_stats;
+ /* indicate valid stats from wlan-fw */
+ uint8_t stats_valid;
+ /* Tx: SAP->STA */
+ uint64_t ipv4_tx_packets;
+ uint64_t ipv4_tx_bytes;
+ /* Rx: STA->SAP */
+ uint64_t ipv4_rx_packets;
+ uint64_t ipv4_rx_bytes;
+ uint64_t ipv6_tx_packets;
+ uint64_t ipv6_tx_bytes;
+ uint64_t ipv6_rx_packets;
+ uint64_t ipv6_rx_bytes;
+};
+
+/**
+ * struct ipa_set_wifi_quota - structure used for
+ * IPA_SET_WIFI_QUOTA.
+ *
+ * @quota_bytes: Quota (in bytes) for the STA interface.
+ * @set_quota: Indicate whether to set the quota (use 1) or
+ * unset the quota.
+ *
+ */
+struct ipa_set_wifi_quota {
+ uint64_t quota_bytes;
+ uint8_t set_quota;
+ /* indicate valid quota set from wlan-fw */
+ uint8_t set_valid;
+};
+
+typedef void (*ipa_wdi_meter_notifier_cb)(enum ipa_wdi_meter_evt_type evt,
+ void *data);
+
+/**
* struct ipa_connect_params - low-level client connect input parameters. Either
* client allocates the data and desc FIFO and specifies that in data+desc OR
* specifies sizes and pipe_mem pref and IPA does the allocation.
@@ -1003,6 +1052,7 @@
* @ul_smmu: WDI_RX configuration info when WLAN uses SMMU
* @dl_smmu: WDI_TX configuration info when WLAN uses SMMU
* @smmu_enabled: true if WLAN uses SMMU
+ * @ipa_wdi_meter_notifier_cb: Get WDI stats and quato info
*/
struct ipa_wdi_in_params {
struct ipa_sys_connect_params sys;
@@ -1013,6 +1063,9 @@
struct ipa_wdi_dl_params_smmu dl_smmu;
} u;
bool smmu_enabled;
+#ifdef IPA_WAN_MSG_IPv6_ADDR_GW_LEN
+ ipa_wdi_meter_notifier_cb wdi_notify;
+#endif
};
enum ipa_upstream_type {
@@ -1273,6 +1326,9 @@
int ipa_suspend_wdi_pipe(u32 clnt_hdl);
int ipa_get_wdi_stats(struct IpaHwStatsWDIInfoData_t *stats);
u16 ipa_get_smem_restr_bytes(void);
+int ipa_broadcast_wdi_quota_reach_ind(uint32_t fid,
+ uint64_t num_bytes);
+
/*
* To retrieve doorbell physical address of
* wlan pipes
@@ -1853,6 +1909,12 @@
return -EPERM;
}
+static inline int ipa_broadcast_wdi_quota_reach_ind(uint32_t fid,
+ uint64_t num_bytes)
+{
+ return -EPERM;
+}
+
static inline int ipa_uc_wdi_get_dbpa(
struct ipa_wdi_db_params *out)
{
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..6dd1547 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -85,6 +85,12 @@
struct mmc_host_ops {
/*
+ * 'enable' is called when the host is claimed and 'disable' is called
+ * when the host is released. 'enable' and 'disable' are deprecated.
+ */
+ int (*enable)(struct mmc_host *host);
+ int (*disable)(struct mmc_host *host);
+ /*
* It is optional for the host to implement pre_req and post_req in
* order to support double buffering of requests (prepare one
* request while another request is active).
@@ -313,9 +319,22 @@
#define MMC_CAP2_HS400_ES (1 << 20) /* Host supports enhanced strobe */
#define MMC_CAP2_NO_SD (1 << 21) /* Do not send SD commands during initialization */
#define MMC_CAP2_NO_MMC (1 << 22) /* Do not send (e)MMC commands during initialization */
+#define MMC_CAP2_PACKED_WR_CONTROL (1 << 23) /* Allow write packing control */
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 +542,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/msm_gsi.h b/include/linux/msm_gsi.h
index 541b10e..f5d2f72 100644
--- a/include/linux/msm_gsi.h
+++ b/include/linux/msm_gsi.h
@@ -367,6 +367,7 @@
enum gsi_xfer_elem_type {
GSI_XFER_ELEM_DATA,
GSI_XFER_ELEM_IMME_CMD,
+ GSI_XFER_ELEM_NOP,
};
/**
@@ -409,6 +410,7 @@
*
* GSI_XFER_ELEM_DATA: for all data transfers
* GSI_XFER_ELEM_IMME_CMD: for IPA immediate commands
+ * GSI_XFER_ELEM_NOP: for event generation only
*
* @xfer_user_data: cookie used in xfer_cb
*
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index 8462da2..2251428 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -84,6 +84,12 @@
ARMPMU_NR_ATTR_GROUPS
};
+enum armpmu_pmu_states {
+ ARM_PMU_STATE_OFF,
+ ARM_PMU_STATE_RUNNING,
+ ARM_PMU_STATE_GOING_DOWN,
+};
+
struct arm_pmu {
struct pmu pmu;
cpumask_t active_irqs;
@@ -108,6 +114,8 @@
void (*free_irq)(struct arm_pmu *);
int (*map_event)(struct perf_event *event);
int num_events;
+ int pmu_state;
+ int percpu_irq;
atomic_t active_events;
struct mutex reserve_mutex;
u64 max_period;
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 531b8b1..3c80583 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -270,6 +270,8 @@
atomic_t exclusive_cnt; /* < 0: cpu; > 0: tsk */
int task_ctx_nr;
int hrtimer_interval_ms;
+ u32 events_across_hotplug:1,
+ reserved:31;
/* number of address filters this PMU can do */
unsigned int nr_addr_filters;
diff --git a/include/linux/phy/phy-qcom-ufs.h b/include/linux/phy/phy-qcom-ufs.h
index 7945fea..25e7a5f 100644
--- a/include/linux/phy/phy-qcom-ufs.h
+++ b/include/linux/phy/phy-qcom-ufs.h
@@ -58,5 +58,6 @@
u8 major, u16 minor, u16 step);
const char *ufs_qcom_phy_name(struct phy *phy);
int ufs_qcom_phy_configure_lpm(struct phy *generic_phy, bool enable);
+void ufs_qcom_phy_dbg_register_dump(struct phy *generic_phy);
#endif /* PHY_QCOM_UFS_H_ */
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/qdsp6v2/rtac.h b/include/linux/qdsp6v2/rtac.h
index 3e5433b..eeea0eb 100644
--- a/include/linux/qdsp6v2/rtac.h
+++ b/include/linux/qdsp6v2/rtac.h
@@ -1,4 +1,5 @@
-/* Copyright (c) 2011, 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011, 2013-2015, 2017, The Linux Foundation. All rights
+ * reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -95,4 +96,5 @@
bool rtac_make_afe_callback(uint32_t *payload, u32 payload_size);
void rtac_set_afe_handle(void *handle);
void get_rtac_adm_data(struct rtac_adm *adm_data);
+void rtac_update_afe_topology(u32 port_id);
#endif
diff --git a/include/linux/qpnp/qpnp-misc.h b/include/linux/qpnp/qpnp-misc.h
new file mode 100644
index 0000000..7d95bf2
--- /dev/null
+++ b/include/linux/qpnp/qpnp-misc.h
@@ -0,0 +1,56 @@
+/* Copyright (c) 2013-2014, 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QPNP_MISC_H
+#define __QPNP_MISC_H
+
+#include <linux/errno.h>
+
+#ifdef CONFIG_QPNP_MISC
+/**
+ * qpnp_misc_irqs_available - check if IRQs are available
+ *
+ * @consumer_dev: device struct
+ *
+ * This function returns true if the MISC interrupts are available
+ * based on a check in the MISC peripheral revision registers.
+ *
+ * Any consumer of this function needs to reference a MISC device phandle
+ * using the "qcom,misc-ref" property in their device tree node.
+ */
+
+int qpnp_misc_irqs_available(struct device *consumer_dev);
+
+/**
+ * qpnp_misc_read_reg - read register from misc device
+ *
+ * @node: device node pointer
+ * @address: address offset in misc peripheral to be read
+ * @val: data read from register
+ *
+ * This function returns zero if reading the MISC register succeeds.
+ *
+ */
+
+int qpnp_misc_read_reg(struct device_node *node, u16 addr, u8 *val);
+#else
+static inline int qpnp_misc_irqs_available(struct device *consumer_dev)
+{
+ return 0;
+}
+static inline int qpnp_misc_read_reg(struct device_node *node, u16 addr,
+ u8 *val)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/include/linux/qpnp/qpnp-pbs.h b/include/linux/qpnp/qpnp-pbs.h
new file mode 100644
index 0000000..39497ac
--- /dev/null
+++ b/include/linux/qpnp/qpnp-pbs.h
@@ -0,0 +1,25 @@
+/* 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 _QPNP_PBS_H
+#define _QPNP_PBS_H
+
+#ifdef CONFIG_QPNP_PBS
+int qpnp_pbs_trigger_event(struct device_node *dev_node, u8 bitmap);
+#else
+static inline int qpnp_pbs_trigger_event(struct device_node *dev_node,
+ u8 bitmap) {
+ return -ENODEV;
+}
+#endif
+
+#endif
diff --git a/include/linux/qpnp/qpnp-revid.h b/include/linux/qpnp/qpnp-revid.h
index 4023e3a..a0e2283 100644
--- a/include/linux/qpnp/qpnp-revid.h
+++ b/include/linux/qpnp/qpnp-revid.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2016, 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
@@ -181,6 +181,7 @@
#define PM660L_SUBTYPE 0x1A
#define PM660_SUBTYPE 0x1B
+/* PMI8998 REV_ID */
#define PMI8998_V1P0_REV1 0x00
#define PMI8998_V1P0_REV2 0x00
#define PMI8998_V1P0_REV3 0x00
@@ -196,6 +197,26 @@
#define PMI8998_V2P0_REV3 0x00
#define PMI8998_V2P0_REV4 0x02
+/* PM660 REV_ID */
+#define PM660_V1P0_REV1 0x00
+#define PM660_V1P0_REV2 0x00
+#define PM660_V1P0_REV3 0x00
+#define PM660_V1P0_REV4 0x01
+
+#define PM660_V1P1_REV1 0x00
+#define PM660_V1P1_REV2 0x00
+#define PM660_V1P1_REV3 0x01
+#define PM660_V1P1_REV4 0x01
+
+/* PMI8998 FAB_ID */
+#define PMI8998_FAB_ID_SMIC 0x11
+#define PMI8998_FAB_ID_GF 0x30
+
+/* PM660 FAB_ID */
+#define PM660_FAB_ID_GF 0x0
+#define PM660_FAB_ID_TSMC 0x2
+#define PM660_FAB_ID_MX 0x3
+
/* PM8005 */
#define PM8005_SUBTYPE 0x18
diff --git a/include/linux/regulator/qpnp-labibb-regulator.h b/include/linux/regulator/qpnp-labibb-regulator.h
new file mode 100644
index 0000000..2470695
--- /dev/null
+++ b/include/linux/regulator/qpnp-labibb-regulator.h
@@ -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.
+ */
+
+#ifndef _QPNP_LABIBB_REGULATOR_H
+#define _QPNP_LABIBB_REGULATOR_H
+
+enum labibb_notify_event {
+ LAB_VREG_OK = 1,
+};
+
+int qpnp_labibb_notifier_register(struct notifier_block *nb);
+int qpnp_labibb_notifier_unregister(struct notifier_block *nb);
+
+#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/net/cfg80211.h b/include/net/cfg80211.h
index 677a047..6d27dae 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4245,6 +4245,32 @@
struct ieee80211_regdomain *rd);
/**
+ * regulatory_hint_user - hint to the wireless core a regulatory domain
+ * which the driver has received from an application
+ * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain
+ * should be in. If @rd is set this should be NULL. Note that if you
+ * set this to NULL you should still set rd->alpha2 to some accepted
+ * alpha2.
+ * @user_reg_hint_type: the type of user regulatory hint.
+ *
+ * Wireless drivers can use this function to hint to the wireless core
+ * the current regulatory domain as specified by trusted applications,
+ * it is the driver's responsibilty to estbalish which applications it
+ * trusts.
+ *
+ * The wiphy should be registered to cfg80211 prior to this call.
+ * For cfg80211 drivers this means you must first use wiphy_register(),
+ * for mac80211 drivers you must first use ieee80211_register_hw().
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENOMEM or an -EINVAL.
+ *
+ * Return: 0 on success. -ENOMEM, -EINVAL.
+ */
+int regulatory_hint_user(const char *alpha2,
+ enum nl80211_user_reg_hint_type user_reg_hint_type);
+
+/**
* wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
* @wiphy: the wireless device we want to process the regulatory domain on
* @regd: the custom regulatory domain to use for this wiphy
diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h
index 6b567d7..7ef984a 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -17,6 +17,21 @@
#define ICNSS_MAX_IRQ_REGISTRATIONS 12
#define ICNSS_MAX_TIMESTAMP_LEN 32
+enum icnss_uevent {
+ ICNSS_UEVENT_FW_READY,
+ ICNSS_UEVENT_FW_CRASHED,
+ ICNSS_UEVENT_FW_DOWN,
+};
+
+struct icnss_uevent_fw_down_data {
+ bool crashed;
+};
+
+struct icnss_uevent_data {
+ enum icnss_uevent uevent;
+ void *data;
+};
+
struct icnss_driver_ops {
char *name;
int (*probe)(struct device *dev);
@@ -28,6 +43,7 @@
int (*pm_resume)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
+ int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent);
};
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 6de9dfa..7a09cb1 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
@@ -1619,11 +1815,14 @@
#define AFE_PORT_SAMPLE_RATE_16K 16000
#define AFE_PORT_SAMPLE_RATE_48K 48000
#define AFE_PORT_SAMPLE_RATE_96K 96000
+#define AFE_PORT_SAMPLE_RATE_176P4K 176400
#define AFE_PORT_SAMPLE_RATE_192K 192000
+#define AFE_PORT_SAMPLE_RATE_352P8K 352800
#define AFE_LINEAR_PCM_DATA 0x0
#define AFE_NON_LINEAR_DATA 0x1
#define AFE_LINEAR_PCM_DATA_PACKED_60958 0x2
#define AFE_NON_LINEAR_DATA_PACKED_60958 0x3
+#define AFE_GENERIC_COMPRESSED 0x8
/* This param id is used to configure I2S interface */
#define AFE_PARAM_ID_I2S_CONFIG 0x0001020D
@@ -2265,6 +2464,13 @@
*/
#define AFE_PARAM_ID_USB_AUDIO_DEV_PARAMS 0x000102A5
+
+/* ID of the parameter used to set the endianness value for the
+ * USB audio device. It should be used with
+ * AFE_MODULE_AUDIO_DEV_INTERFACE
+ */
+#define AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT 0x000102AA
+
/* Minor version used for tracking USB audio configuration */
#define AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG 0x1
@@ -2280,6 +2486,15 @@
u32 dev_token;
} __packed;
+struct afe_param_id_usb_audio_dev_lpcm_fmt {
+/* Minor version used for tracking USB audio device parameter.
+ * Supported values: AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG
+ */
+ u32 cfg_minor_version;
+/* Endianness of actual end USB audio device */
+ u32 endian;
+} __packed;
+
/* ID of the parameter used by AFE_PARAM_ID_USB_AUDIO_CONFIG to configure
* USB audio interface. It should be used with AFE_MODULE_AUDIO_DEV_INTERFACE
*/
@@ -2324,13 +2539,18 @@
u16 reserved;
/* device token of actual end USB aduio device */
u32 dev_token;
+/* endianness of this interface */
+ u32 endian;
} __packed;
struct afe_usb_audio_dev_param_command {
struct apr_hdr hdr;
struct afe_port_cmd_set_param_v2 param;
struct afe_port_param_data_v2 pdata;
- struct afe_param_id_usb_audio_dev_params usb_dev;
+ union {
+ struct afe_param_id_usb_audio_dev_params usb_dev;
+ struct afe_param_id_usb_audio_dev_lpcm_fmt lpcm_fmt;
+ };
} __packed;
/* This param id is used to configure Real Time Proxy interface. */
@@ -2528,7 +2748,9 @@
* - #AFE_PORT_SAMPLE_RATE_16K
* - #AFE_PORT_SAMPLE_RATE_24K
* - #AFE_PORT_SAMPLE_RATE_32K
- * - #AFE_PORT_SAMPLE_RATE_48K @tablebulletend
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_176P4K
+ * - #AFE_PORT_SAMPLE_RATE_352P8K @tablebulletend
*/
u32 bit_width;
@@ -2537,10 +2759,11 @@
*/
u16 data_format;
- /* < Data format: linear and compressed
+ /* < Data format: linear ,compressed, generic compresssed
* @values
* - #AFE_LINEAR_PCM_DATA
- * - #AFE_NON_LINEAR_DATA @tablebulletend
+ * - #AFE_NON_LINEAR_DATA
+ * - #AFE_GENERIC_COMPRESSED
*/
u16 sync_mode;
@@ -3419,7 +3642,7 @@
#define DEFAULT_COPP_TOPOLOGY 0x00010314
#define DEFAULT_POPP_TOPOLOGY 0x00010BE4
#define COMPRESSED_PASSTHROUGH_DEFAULT_TOPOLOGY 0x0001076B
-#define COMPRESS_PASSTHROUGH_NONE_TOPOLOGY 0x00010774
+#define COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY 0x00010774
#define VPM_TX_SM_ECNS_COPP_TOPOLOGY 0x00010F71
#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY 0x00010F72
#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY 0x00010F75
@@ -3725,6 +3948,8 @@
#define ASM_MEDIA_FMT_EVRCWB_FS 0x00010BF0
+#define ASM_MEDIA_FMT_GENERIC_COMPRESSED 0x00013212
+
#define ASM_MAX_EQ_BANDS 12
#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98
@@ -3734,6 +3959,40 @@
/* Media format block size in bytes.*/
} __packed;
+struct asm_generic_compressed_fmt_blk_t {
+ struct apr_hdr hdr;
+ struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
+
+ /*
+ * Channel mapping array of bitstream output.
+ * Channel[i] mapping describes channel i inside the buffer, where
+ * i < num_channels. All valid used channels must be
+ * present at the beginning of the array.
+ */
+ uint8_t channel_mapping[8];
+
+ /*
+ * Number of channels of the incoming bitstream.
+ * Supported values: 1,2,3,4,5,6,7,8
+ */
+ uint16_t num_channels;
+
+ /*
+ * Nominal bits per sample value of the incoming bitstream.
+ * Supported values: 16, 32
+ */
+ uint16_t bits_per_sample;
+
+ /*
+ * Nominal sampling rate of the incoming bitstream.
+ * Supported values: 8000, 11025, 16000, 22050, 24000, 32000,
+ * 44100, 48000, 88200, 96000, 176400, 192000,
+ * 352800, 384000
+ */
+ uint32_t sampling_rate;
+
+} __packed;
+
struct asm_multi_channel_pcm_fmt_blk_v2 {
struct apr_hdr hdr;
struct asm_data_cmd_media_fmt_update_v2 fmt_blk;
@@ -4128,6 +4387,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 +5045,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 +5055,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 +6077,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 +7164,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 +9061,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 +9113,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 +9126,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)
@@ -9616,6 +10047,108 @@
union afe_port_group_config data;
} __packed;
+/* ID of the parameter used by #AFE_MODULE_AUDIO_DEV_INTERFACE to specify
+ * the timing statistics of the corresponding device interface.
+ * Client can periodically query for the device time statistics to help adjust
+ * the PLL based on the drift value. The get param command must be sent to
+ * AFE port ID corresponding to device interface
+
+ * This parameter ID supports following get param commands:
+ * #AFE_PORT_CMD_GET_PARAM_V2 and
+ * #AFE_PORT_CMD_GET_PARAM_V3.
+ */
+#define AFE_PARAM_ID_DEV_TIMING_STATS 0x000102AD
+
+/* Version information used to handle future additions to AFE device
+ * interface timing statistics (for backward compatibility).
+ */
+#define AFE_API_VERSION_DEV_TIMING_STATS 0x1
+
+/* Enumeration for specifying a sink(Rx) device */
+#define AFE_SINK_DEVICE 0x0
+
+/* Enumeration for specifying a source(Tx) device */
+#define AFE_SOURCE_DEVICE 0x1
+
+/* Enumeration for specifying the drift reference is of type AV Timer */
+#define AFE_REF_TIMER_TYPE_AVTIMER 0x0
+
+/* Message payload structure for the
+ * AFE_PARAM_ID_DEV_TIMING_STATS parameter.
+ */
+struct afe_param_id_dev_timing_stats {
+ /* Minor version used to track the version of device interface timing
+ * statistics. Currently, the supported version is 1.
+ * @values #AFE_API_VERSION_DEV_TIMING_STATS
+ */
+ u32 minor_version;
+
+ /* Indicates the device interface direction as either
+ * source (Tx) or sink (Rx).
+ * @values
+ * #AFE_SINK_DEVICE
+ * #AFE_SOURCE_DEVICE
+ */
+ u16 device_direction;
+
+ /* Reference timer for drift accumulation and time stamp information.
+ * @values
+ * #AFE_REF_TIMER_TYPE_AVTIMER @tablebulletend
+ */
+ u16 reference_timer;
+
+ /*
+ * Flag to indicate if resync is required on the client side for
+ * drift correction. Flag is set to TRUE for the first get_param
+ * response after device interface starts. This flag value can be
+ * used by client to identify if device interface restart has
+ * happened and if any re-sync is required at their end for drift
+ * correction.
+ * @values
+ * 0: FALSE (Resync not required)
+ * 1: TRUE (Resync required) @tablebulletend
+ */
+ u32 resync_flag;
+
+ /* Accumulated drift value in microseconds. This value is updated
+ * every 100th ms.
+ * Positive drift value indicates AV timer is running faster than device
+ * Negative drift value indicates AV timer is running slower than device
+ * @values Any valid int32 number
+ */
+ s32 acc_drift_value;
+
+ /* Lower 32 bits of the 64-bit absolute timestamp of reference
+ * timer in microseconds.
+
+ * This timestamp corresponds to the time when the drift values
+ * are accumlated for every 100th ms.
+ * @values Any valid uint32 number
+ */
+ u32 ref_timer_abs_ts_lsw;
+
+ /* Upper 32 bits of the 64-bit absolute timestamp of reference
+ * timer in microseconds.
+ * This timestamp corresponds to the time when the drift values
+ * are accumlated for every 100th ms.
+ * @values Any valid uint32 number
+ */
+ u32 ref_timer_abs_ts_msw;
+} __packed;
+
+struct afe_av_dev_drift_get_param {
+ struct apr_hdr hdr;
+ struct afe_port_cmd_get_param_v2 get_param;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_dev_timing_stats timing_stats;
+} __packed;
+
+struct afe_av_dev_drift_get_param_resp {
+ uint32_t status;
+ struct afe_port_param_data_v2 pdata;
+ struct afe_param_id_dev_timing_stats timing_stats;
+} __packed;
+
/* Command for Matrix or Stream Router */
#define ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2 0x00010DCE
/* Module for AVSYNC */
@@ -9701,12 +10234,108 @@
*/
};
+/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC which allows the
+ * audio client choose the rendering decision that the audio DSP should use.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD 0x00012F0D
+
+/* Indicates that rendering decision will be based on default rate
+ * (session clock based rendering, device driven).
+ * 1. The default session clock based rendering is inherently driven
+ * by the timing of the device.
+ * 2. After the initial decision is made (first buffer after a run
+ * command), subsequent data rendering decisions are made with
+ * respect to the rate at which the device is rendering, thus deriving
+ * its timing from the device.
+ * 3. While this decision making is simple, it has some inherent limitations
+ * (mentioned in the next section).
+ * 4. If this API is not set, the session clock based rendering will be assumed
+ * and this will ensure that the DSP is backward compatible.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT 0
+
+/* Indicates that rendering decision will be based on local clock rate.
+ * 1. In the DSP loopback/client loopback use cases (frame based
+ * inputs), the incoming data into audio DSP is time-stamped at the
+ * local clock rate (STC).
+ * 2. This TS rate may match the incoming data rate or maybe different
+ * from the incoming data rate.
+ * 3. Regardless, the data will be time-stamped with local STC and
+ * therefore, the client is recommended to set this mode for these
+ * use cases. This method is inherently more robust to sequencing
+ * (AFE Start/Stop) and device switches, among other benefits.
+ * 4. This API will inform the DSP to compare every incoming buffer TS
+ * against local STC.
+ * 5. DSP will continue to honor render windows APIs, as before.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC 1
+
+/* Structure for rendering decision parameter */
+struct asm_session_mtmx_strtr_param_render_mode_t {
+ /* Specifies the type of rendering decision the audio DSP should use.
+ *
+ * @values
+ * - #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT
+ * - #ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC
+ */
+ u32 flags;
+} __packed;
+
+/* Parameter used by #ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC which allows the
+ * audio client to specify the clock recovery mechanism that the audio DSP
+ * should use.
+ */
+
+#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD 0x00012F0E
+
+/* Indicates that default clock recovery will be used (no clock recovery).
+ * If the client wishes that no clock recovery be done, the client can
+ * choose this. This means that no attempt will made by the DSP to try and
+ * match the rates of the input and output audio.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE 0
+
+/* Indicates that independent clock recovery needs to be used.
+ * 1. In the DSP loopback/client loopback use cases (frame based inputs),
+ * the client should choose the independent clock recovery option.
+ * 2. This basically de-couples the audio and video from knowing each others
+ * clock sources and lets the audio DSP independently rate match the input
+ * and output rates.
+ * 3. After drift detection, the drift correction is achieved by either pulling
+ * the PLLs (if applicable) or by stream to device rate matching
+ * (for PCM use cases) by comparing drift with respect to STC.
+ * 4. For passthrough use cases, since the PLL pulling is the only option,
+ * a best effort will be made.
+ * If PLL pulling is not possible / available, the rendering will be
+ * done without rate matching.
+ */
+#define ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO 1
+
+/* Payload of the #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC parameter.
+ */
+struct asm_session_mtmx_strtr_param_clk_rec_t {
+ /* Specifies the type of clock recovery that the audio DSP should
+ * use for rate matching.
+ */
+
+ /* @values
+ * #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_DEFAULT
+ * #ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_INDEPENDENT
+ */
+ u32 flags;
+} __packed;
+
+union asm_session_mtmx_strtr_param_config {
+ struct asm_session_mtmx_strtr_param_window_v2_t window_param;
+ struct asm_session_mtmx_strtr_param_render_mode_t render_param;
+ struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
+} __packed;
+
struct asm_mtmx_strtr_params {
struct apr_hdr hdr;
struct asm_session_cmd_set_mtmx_strstr_params_v2 param;
struct asm_stream_param_data_v2 data;
- u32 window_lsw;
- u32 window_msw;
+ union asm_session_mtmx_strtr_param_config config;
} __packed;
#define ASM_SESSION_CMD_GET_MTMX_STRTR_PARAMS_V2 0x00010DCF
@@ -9826,6 +10455,8 @@
COMPRESSED_PASSTHROUGH,
COMPRESSED_PASSTHROUGH_CONVERT,
COMPRESSED_PASSTHROUGH_DSD,
+ LISTEN,
+ COMPRESSED_PASSTHROUGH_GEN,
};
#define AUDPROC_MODULE_ID_COMPRESSED_MUTE 0x00010770
@@ -9897,4 +10528,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..42d048f 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
@@ -58,9 +58,9 @@
struct route_payload {
unsigned int copp_idx[MAX_COPPS_PER_PORT];
unsigned int port_id[MAX_COPPS_PER_PORT];
- int app_type;
- int acdb_dev_id;
- int sample_rate;
+ int app_type[MAX_COPPS_PER_PORT];
+ int acdb_dev_id[MAX_COPPS_PER_PORT];
+ int sample_rate[MAX_COPPS_PER_PORT];
unsigned short num_copps;
unsigned int session_id;
};
@@ -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..8361175 100644
--- a/include/sound/q6afe-v2.h
+++ b/include/sound/q6afe-v2.h
@@ -42,6 +42,8 @@
#define AFE_CLK_VERSION_V1 1
#define AFE_CLK_VERSION_V2 2
+typedef int (*routing_cb)(int port);
+
enum {
/* IDX 0->4 */
IDX_PRIMARY_I2S_RX,
@@ -265,7 +267,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);
@@ -362,5 +364,8 @@
struct afe_param_id_custom_tdm_header_cfg *custom_tdm_header_cfg,
u16 port_id);
int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
- u32 rate);
+ u32 rate, u16 num_groups);
+void afe_set_routing_callback(routing_cb cb);
+int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
+ u16 port);
#endif /* __Q6AFE_V2_H__ */
diff --git a/include/sound/q6asm-v2.h b/include/sound/q6asm-v2.h
index 7321481..6bc93f5 100644
--- a/include/sound/q6asm-v2.h
+++ b/include/sound/q6asm-v2.h
@@ -53,6 +53,8 @@
#define FORMAT_G711_MLAW_FS 0x001b
#define FORMAT_DTS 0x001c
#define FORMAT_DSD 0x001d
+#define FORMAT_APTX 0x001e
+#define FORMAT_GEN_COMPR 0x001f
#define ENCDEC_SBCBITRATE 0x0001
#define ENCDEC_IMMEDIATE_DECODE 0x0002
@@ -270,7 +272,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*/);
@@ -499,6 +501,11 @@
uint32_t rate, uint32_t channels,
bool use_default_chmap, char *channel_map,
uint16_t bits_per_sample);
+int q6asm_media_format_block_gen_compr(
+ struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample);
int q6asm_media_format_block_multi_ch_pcm_v3(struct audio_client *ac,
uint32_t rate, uint32_t channels,
@@ -552,6 +559,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 +584,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);
@@ -627,6 +641,14 @@
struct asm_session_mtmx_strtr_param_window_v2_t *window_param,
uint32_t param_id);
+/* Configure DSP render mode */
+int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
+ uint32_t render_mode);
+
+/* Configure DSP clock recovery mode */
+int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
+ uint32_t clk_rec_mode);
+
/* Retrieve the current DSP path delay */
int q6asm_get_path_delay(struct audio_client *ac);
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/drm/msm_drm.h b/include/uapi/drm/msm_drm.h
index fb882f5..fda50e9 100644
--- a/include/uapi/drm/msm_drm.h
+++ b/include/uapi/drm/msm_drm.h
@@ -268,6 +268,39 @@
__u32 blackness_level;
};
+/**
+ * struct drm_msm_event_req - Payload to event enable/disable ioctls.
+ * @object_id: DRM object id. e.g.: for crtc pass crtc id.
+ * @object_type: DRM object type. e.g.: for crtc set it to DRM_MODE_OBJECT_CRTC.
+ * @event: Event for which notification is being enabled/disabled.
+ * e.g.: for Histogram set - DRM_EVENT_HISTOGRAM.
+ * @client_context: Opaque pointer that will be returned during event response
+ * notification.
+ * @index: Object index(e.g.: crtc index), optional for user-space to set.
+ * Driver will override value based on object_id and object_type.
+ */
+struct drm_msm_event_req {
+ __u32 object_id;
+ __u32 object_type;
+ __u32 event;
+ __u64 client_context;
+ __u32 index;
+};
+
+/**
+ * struct drm_msm_event_resp - payload returned when read is called for
+ * custom notifications.
+ * @base: Event type and length of complete notification payload.
+ * @info: Contains information about DRM that which raised this event.
+ * @data: Custom payload that driver returns for event type.
+ * size of data = base.length - (sizeof(base) + sizeof(info))
+ */
+struct drm_msm_event_resp {
+ struct drm_event base;
+ struct drm_msm_event_req info;
+ __u8 data[];
+};
+
#define DRM_MSM_GET_PARAM 0x00
/* placeholder:
#define DRM_MSM_SET_PARAM 0x01
@@ -284,6 +317,10 @@
#define DRM_MSM_REGISTER_EVENT 0x41
#define DRM_MSM_DEREGISTER_EVENT 0x42
+/* sde custom events */
+#define DRM_EVENT_HISTOGRAM 0x80000000
+#define DRM_EVENT_AD_BACKLIGHT 0x80000001
+
#define DRM_IOCTL_MSM_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GET_PARAM, struct drm_msm_param)
#define DRM_IOCTL_MSM_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_NEW, struct drm_msm_gem_new)
#define DRM_IOCTL_MSM_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_INFO, struct drm_msm_gem_info)
@@ -294,6 +331,10 @@
#define DRM_IOCTL_MSM_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_MSM_GEM_MADVISE, struct drm_msm_gem_madvise)
#define DRM_IOCTL_SDE_WB_CONFIG \
DRM_IOW((DRM_COMMAND_BASE + DRM_SDE_WB_CONFIG), struct sde_drm_wb_cfg)
+#define DRM_IOCTL_MSM_REGISTER_EVENT DRM_IOW((DRM_COMMAND_BASE + \
+ DRM_MSM_REGISTER_EVENT), struct drm_msm_event_req)
+#define DRM_IOCTL_MSM_DEREGISTER_EVENT DRM_IOW((DRM_COMMAND_BASE + \
+ DRM_MSM_DEREGISTER_EVENT), struct drm_msm_event_req)
#if defined(__cplusplus)
}
diff --git a/include/uapi/linux/esoc_ctrl.h b/include/uapi/linux/esoc_ctrl.h
index 1b17e1c..4201c95 100644
--- a/include/uapi/linux/esoc_ctrl.h
+++ b/include/uapi/linux/esoc_ctrl.h
@@ -5,11 +5,11 @@
#define ESOC_CODE 0xCC
-#define ESOC_CMD_EXE _IOW(ESOC_CODE, 1, __u32)
-#define ESOC_WAIT_FOR_REQ _IOR(ESOC_CODE, 2, __u32)
-#define ESOC_NOTIFY _IOW(ESOC_CODE, 3, __u32)
-#define ESOC_GET_STATUS _IOR(ESOC_CODE, 4, __u32)
-#define ESOC_WAIT_FOR_CRASH _IOR(ESOC_CODE, 6, __u32)
+#define ESOC_CMD_EXE _IOW(ESOC_CODE, 1, unsigned int)
+#define ESOC_WAIT_FOR_REQ _IOR(ESOC_CODE, 2, unsigned int)
+#define ESOC_NOTIFY _IOW(ESOC_CODE, 3, unsigned int)
+#define ESOC_GET_STATUS _IOR(ESOC_CODE, 4, unsigned int)
+#define ESOC_WAIT_FOR_CRASH _IOR(ESOC_CODE, 6, unsigned int)
#define ESOC_REG_REQ_ENG _IO(ESOC_CODE, 7)
#define ESOC_REG_CMD_ENG _IO(ESOC_CODE, 8)
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/linux/msm_kgsl.h b/include/uapi/linux/msm_kgsl.h
index 941a816..c190446 100644
--- a/include/uapi/linux/msm_kgsl.h
+++ b/include/uapi/linux/msm_kgsl.h
@@ -327,6 +327,7 @@
#define KGSL_PROP_DEVICE_QDSS_STM 0x19
#define KGSL_PROP_MIN_ACCESS_LENGTH 0x1A
#define KGSL_PROP_UBWC_MODE 0x1B
+#define KGSL_PROP_DEVICE_QTIMER 0x20
struct kgsl_shadowprop {
unsigned long gpuaddr;
@@ -339,6 +340,11 @@
uint64_t size;
};
+struct kgsl_qtimer_prop {
+ uint64_t gpuaddr;
+ uint64_t size;
+};
+
struct kgsl_version {
unsigned int drv_major;
unsigned int drv_minor;
diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild
index d138beb..5f375c4 100644
--- a/include/uapi/media/Kbuild
+++ b/include/uapi/media/Kbuild
@@ -1,8 +1,8 @@
-header-y += cam_req_mgr.h
header-y += cam_defs.h
header-y += cam_isp.h
header-y += cam_isp_vfe.h
header-y += cam_isp_ife.h
+header-y += cam_req_mgr.h
header-y += cam_sensor.h
header-y += cam_sync.h
header-y += msm_media_info.h
diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h
index 18bd04a..3e2b24c 100644
--- a/include/uapi/media/cam_req_mgr.h
+++ b/include/uapi/media/cam_req_mgr.h
@@ -9,16 +9,17 @@
#define CAM_REQ_MGR_VNODE_NAME "cam-req-mgr-devnode"
-#define CAM_DEVICE_TYPE_BASE (MEDIA_ENT_F_OLD_BASE)
-#define CAM_VNODE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE)
-#define CAM_SENSOR_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 1)
-#define CAM_IFE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 2)
-#define CAM_ICP_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 3)
-#define CAM_LRME_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 4)
-#define CAM_JPEG_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 5)
-#define CAM_FD_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 6)
-#define CAM_CPAS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 7)
-#define CAM_CSIPHY_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 8)
+#define CAM_DEVICE_TYPE_BASE (MEDIA_ENT_F_OLD_BASE)
+#define CAM_VNODE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE)
+#define CAM_SENSOR_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 1)
+#define CAM_IFE_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 2)
+#define CAM_ICP_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 3)
+#define CAM_LRME_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 4)
+#define CAM_JPEG_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 5)
+#define CAM_FD_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 6)
+#define CAM_CPAS_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 7)
+#define CAM_CSIPHY_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 8)
+#define CAM_ACTUATOR_DEVICE_TYPE (CAM_DEVICE_TYPE_BASE + 9)
/* cam_req_mgr hdl info */
#define CAM_REQ_MGR_HDL_IDX_POS 8
diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
index e04ccf0..3048105 100644
--- a/include/uapi/sound/compress_offload.h
+++ b/include/uapi/sound/compress_offload.h
@@ -70,7 +70,7 @@
__u32 pcm_frames;
__u32 pcm_io_frames;
__u32 sampling_rate;
- uint64_t timestamp;
+ __u64 timestamp;
} __attribute__((packed, aligned(4)));
/**
@@ -128,24 +128,46 @@
* @reserved: reserved for furture use
*/
struct snd_compr_audio_info {
- uint32_t frame_size;
- uint32_t reserved[15];
+ __u32 frame_size;
+ __u32 reserved[15];
} __attribute__((packed, aligned(4)));
+#define SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER 0
+#define SNDRV_COMPRESS_RENDER_MODE_STC_MASTER 1
+
+#define SNDRV_COMPRESS_CLK_REC_MODE_NONE 0
+#define SNDRV_COMPRESS_CLK_REC_MODE_AUTO 1
+
/**
* enum sndrv_compress_encoder
* @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the
* end of the track
* @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the
* beginning of the track
+ * @SNDRV_COMPRESS_PATH_DELAY: dsp path delay in microseconds
+ * @SNDRV_COMPRESS_RENDER_MODE: dsp render mode (audio master or stc)
+ * @SNDRV_COMPRESS_CLK_REC_MODE: clock recovery mode ( none or auto)
+ * @SNDRV_COMPRESS_RENDER_WINDOW: render window
+ * @SNDRV_COMPRESS_START_DELAY: start delay
*/
enum sndrv_compress_encoder {
SNDRV_COMPRESS_ENCODER_PADDING = 1,
SNDRV_COMPRESS_ENCODER_DELAY = 2,
SNDRV_COMPRESS_MIN_BLK_SIZE = 3,
SNDRV_COMPRESS_MAX_BLK_SIZE = 4,
+ SNDRV_COMPRESS_PATH_DELAY = 5,
+ SNDRV_COMPRESS_RENDER_MODE = 6,
+ SNDRV_COMPRESS_CLK_REC_MODE = 7,
+ SNDRV_COMPRESS_RENDER_WINDOW = 8,
+ SNDRV_COMPRESS_START_DELAY = 9,
};
+#define SNDRV_COMPRESS_PATH_DELAY SNDRV_COMPRESS_PATH_DELAY
+#define SNDRV_COMPRESS_RENDER_MODE SNDRV_COMPRESS_RENDER_MODE
+#define SNDRV_COMPRESS_CLK_REC_MODE SNDRV_COMPRESS_CLK_REC_MODE
+#define SNDRV_COMPRESS_RENDER_WINDOW SNDRV_COMPRESS_RENDER_WINDOW
+#define SNDRV_COMPRESS_START_DELAY SNDRV_COMPRESS_START_DELAY
+
/**
* struct snd_compr_metadata - compressed stream metadata
* @key: key id
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/events/core.c b/kernel/events/core.c
index 24f0d77..113d325 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -372,6 +372,7 @@
static DEFINE_PER_CPU(atomic_t, perf_cgroup_events);
static DEFINE_PER_CPU(int, perf_sched_cb_usages);
static DEFINE_PER_CPU(struct pmu_event_list, pmu_sb_events);
+static DEFINE_PER_CPU(bool, is_idle);
static atomic_t nr_mmap_events __read_mostly;
static atomic_t nr_comm_events __read_mostly;
@@ -3605,23 +3606,31 @@
static int perf_event_read(struct perf_event *event, bool group)
{
int event_cpu, ret = 0;
+ bool active_event_skip_read = false;
/*
* If event is enabled and currently active on a CPU, update the
* value in the event structure:
*/
+ event_cpu = READ_ONCE(event->oncpu);
+
+ if (event->state == PERF_EVENT_STATE_ACTIVE) {
+ if ((unsigned int)event_cpu >= nr_cpu_ids)
+ return 0;
+ if (cpu_isolated(event_cpu) ||
+ (event->attr.exclude_idle &&
+ per_cpu(is_idle, event_cpu)))
+ active_event_skip_read = true;
+ }
+
if (event->state == PERF_EVENT_STATE_ACTIVE &&
- !cpu_isolated(event->oncpu)) {
+ !active_event_skip_read) {
struct perf_read_data data = {
.event = event,
.group = group,
.ret = 0,
};
- event_cpu = READ_ONCE(event->oncpu);
- if ((unsigned)event_cpu >= nr_cpu_ids)
- return 0;
-
preempt_disable();
event_cpu = __perf_event_read_cpu(event, event_cpu);
@@ -3635,10 +3644,12 @@
* Therefore, either way, we'll have an up-to-date event count
* after this.
*/
- (void)smp_call_function_single(event_cpu, __perf_event_read, &data, 1);
+ (void)smp_call_function_single(event_cpu,
+ __perf_event_read, &data, 1);
preempt_enable();
ret = data.ret;
- } else if (event->state == PERF_EVENT_STATE_INACTIVE) {
+ } else if (event->state == PERF_EVENT_STATE_INACTIVE ||
+ active_event_skip_read) {
struct perf_event_context *ctx = event->ctx;
unsigned long flags;
@@ -3731,7 +3742,8 @@
if (!task) {
/* Must be root to operate on a CPU event: */
- if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
+ if (!is_kernel_event(event) && perf_paranoid_cpu() &&
+ !capable(CAP_SYS_ADMIN))
return ERR_PTR(-EACCES);
/*
@@ -7586,6 +7598,7 @@
.start = perf_swevent_start,
.stop = perf_swevent_stop,
.read = perf_swevent_read,
+ .events_across_hotplug = 1,
};
#ifdef CONFIG_EVENT_TRACING
@@ -7730,6 +7743,7 @@
.start = perf_swevent_start,
.stop = perf_swevent_stop,
.read = perf_swevent_read,
+ .events_across_hotplug = 1,
};
static inline void perf_tp_register(void)
@@ -8460,6 +8474,7 @@
.start = cpu_clock_event_start,
.stop = cpu_clock_event_stop,
.read = cpu_clock_event_read,
+ .events_across_hotplug = 1,
};
/*
@@ -8541,6 +8556,7 @@
.start = task_clock_event_start,
.stop = task_clock_event_stop,
.read = task_clock_event_read,
+ .events_across_hotplug = 1,
};
static void perf_pmu_nop_void(struct pmu *pmu)
@@ -10715,6 +10731,76 @@
}
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static void
+check_hotplug_start_event(struct perf_event *event)
+{
+ if (event->attr.type == PERF_TYPE_SOFTWARE) {
+ switch (event->attr.config) {
+ case PERF_COUNT_SW_CPU_CLOCK:
+ cpu_clock_event_start(event, 0);
+ break;
+ case PERF_COUNT_SW_TASK_CLOCK:
+ break;
+ default:
+ if (event->pmu->start)
+ event->pmu->start(event, 0);
+ break;
+ }
+ }
+}
+
+static int perf_event_start_swevents(unsigned int cpu)
+{
+ struct perf_event_context *ctx;
+ struct pmu *pmu;
+ struct perf_event *event;
+ int idx;
+
+ idx = srcu_read_lock(&pmus_srcu);
+ list_for_each_entry_rcu(pmu, &pmus, entry) {
+ ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx;
+ mutex_lock(&ctx->mutex);
+ raw_spin_lock(&ctx->lock);
+ list_for_each_entry(event, &ctx->event_list, event_entry)
+ check_hotplug_start_event(event);
+ raw_spin_unlock(&ctx->lock);
+ mutex_unlock(&ctx->mutex);
+ }
+ srcu_read_unlock(&pmus_srcu, idx);
+ return 0;
+}
+
+/*
+ * If keeping events across hotplugging is supported, do not
+ * remove the event list so event lives beyond CPU hotplug.
+ * The context is exited via an fd close path when userspace
+ * is done and the target CPU is online. If software clock
+ * event is active, then stop hrtimer associated with it.
+ * Start the timer when the CPU comes back online.
+ */
+static void
+check_hotplug_remove_from_context(struct perf_event *event,
+ struct perf_cpu_context *cpuctx,
+ struct perf_event_context *ctx)
+{
+ if (!event->pmu->events_across_hotplug) {
+ __perf_remove_from_context(event, cpuctx,
+ ctx, (void *)DETACH_GROUP);
+ } else if (event->attr.type == PERF_TYPE_SOFTWARE) {
+ switch (event->attr.config) {
+ case PERF_COUNT_SW_CPU_CLOCK:
+ cpu_clock_event_stop(event, 0);
+ break;
+ case PERF_COUNT_SW_TASK_CLOCK:
+ break;
+ default:
+ if (event->pmu->stop)
+ event->pmu->stop(event, 0);
+ break;
+ }
+ }
+}
+
static void __perf_event_exit_context(void *__info)
{
struct perf_event_context *ctx = __info;
@@ -10723,7 +10809,7 @@
raw_spin_lock(&ctx->lock);
list_for_each_entry(event, &ctx->event_list, event_entry)
- __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
+ check_hotplug_remove_from_context(event, cpuctx, ctx);
raw_spin_unlock(&ctx->lock);
}
@@ -10775,6 +10861,26 @@
.priority = INT_MIN,
};
+static int event_idle_notif(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ switch (action) {
+ case IDLE_START:
+ __this_cpu_write(is_idle, true);
+ break;
+ case IDLE_END:
+ __this_cpu_write(is_idle, false);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block perf_event_idle_nb = {
+ .notifier_call = event_idle_notif,
+};
+
+
void __init perf_event_init(void)
{
int ret;
@@ -10788,6 +10894,7 @@
perf_pmu_register(&perf_task_clock, NULL, -1);
perf_tp_register();
perf_event_init_cpu(smp_processor_id());
+ idle_notifier_register(&perf_event_idle_nb);
register_reboot_notifier(&perf_reboot_notifier);
ret = init_hw_breakpoint();
@@ -10842,6 +10949,21 @@
}
device_initcall(perf_event_sysfs_init);
+static int perf_cpu_hp_init(void)
+{
+ int ret;
+
+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE,
+ "PERF/CORE/AP_PERF_ONLINE",
+ perf_event_start_swevents,
+ perf_event_exit_cpu);
+ if (ret)
+ pr_err("CPU hotplug notifier for perf core could not be registered: %d\n",
+ ret);
+ return ret;
+}
+subsys_initcall(perf_cpu_hp_init);
+
#ifdef CONFIG_CGROUP_PERF
static struct cgroup_subsys_state *
perf_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
diff --git a/kernel/power/qos.c b/kernel/power/qos.c
index 22d67f0..0854263 100644
--- a/kernel/power/qos.c
+++ b/kernel/power/qos.c
@@ -703,12 +703,22 @@
/* silent return to keep pcm code cleaner */
if (!pm_qos_request_active(req)) {
- WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n");
+ WARN(1, "pm_qos_remove_request() called for unknown object\n");
return;
}
cancel_delayed_work_sync(&req->work);
+#ifdef CONFIG_SMP
+ if (req->type == PM_QOS_REQ_AFFINE_IRQ) {
+ int ret = 0;
+ /* Get the current affinity */
+ ret = irq_set_affinity_notifier(req->irq, NULL);
+ if (ret)
+ WARN(1, "IRQ affinity notify set failed\n");
+ }
+#endif
+
trace_pm_qos_remove_request(req->pm_qos_class, PM_QOS_DEFAULT_VALUE);
pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints,
req, PM_QOS_REMOVE_REQ,
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/kernel/trace/ipc_logging.c b/kernel/trace/ipc_logging.c
index fa7fd14..6d310ab 100644
--- a/kernel/trace/ipc_logging.c
+++ b/kernel/trace/ipc_logging.c
@@ -515,8 +515,8 @@
tsv_qtimer_write(&ectxt);
avail_size = (MAX_MSG_SIZE - (ectxt.offset + hdr_size));
va_start(arg_list, fmt);
- data_size = vsnprintf((ectxt.buff + ectxt.offset + hdr_size),
- avail_size, fmt, arg_list);
+ data_size = vscnprintf((ectxt.buff + ectxt.offset + hdr_size),
+ avail_size, fmt, arg_list);
va_end(arg_list);
tsv_write_header(&ectxt, TSV_TYPE_BYTE_ARRAY, data_size);
ectxt.offset += data_size;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 84c5076..7ae9b24 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -2116,6 +2116,7 @@
current->comm, preempt_count(), task_pid_nr(current),
worker->current_func);
debug_show_held_locks(current);
+ BUG_ON(PANIC_CORRUPTION);
dump_stack();
}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index fa9c7cd..64ec3fd 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -257,6 +257,17 @@
If unsure, say N.
+config PAGE_OWNER_ENABLE_DEFAULT
+ bool "Enable Track page owner by default"
+ depends on PAGE_OWNER
+ ---help---
+ This keeps track of what call chain is the owner of a page, may
+ help to find bare alloc_page(s) leaks. If you include this
+ feature on your build, it is enabled by default. You should pass
+ "page_owner=off" to boot parameter in order to disable it. Eats
+ a fair amount of memory if enabled. See tools/vm/page_owner_sort.c
+ for user-space helper.
+
config DEBUG_FS
bool "Debug Filesystem"
select SRCU
@@ -2029,6 +2040,19 @@
memtest=17, mean do 17 test patterns.
If you are unsure how to answer this question, answer N.
+config MEMTEST_ENABLE_DEFAULT
+ int "Enable Memtest pattern test by default? (0-17)"
+ range 0 17
+ default "0"
+ depends on MEMTEST
+ help
+ This option helps to select Memtest to be enabled through
+ kernel defconfig options. Alternatively it can be enabled
+ using memtest=<patterns> kernel command line.
+
+ Default value is kept as "0" so that it is kept as disabled.
+ To enable enter any value between 1-17 range.
+
config TEST_STATIC_KEYS
tristate "Test static keys"
default n
@@ -2038,6 +2062,13 @@
If unsure, say N.
+config PANIC_ON_DATA_CORRUPTION
+ bool "Cause a Kernel Panic When Data Corruption is detected"
+ help
+ Select this option to upgrade warnings for potentially
+ recoverable data corruption scenarios to system-halting panics,
+ for easier detection and debug.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 3859bf6..7a5c1c0 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -11,6 +11,7 @@
#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/rculist.h>
+#include <linux/bug.h>
/*
* Insert a new entry between two known consecutive entries.
@@ -34,6 +35,10 @@
WARN(new == prev || new == next,
"list_add double add: new=%p, prev=%p, next=%p.\n",
new, prev, next);
+
+ BUG_ON((prev->next != next || next->prev != prev ||
+ new == prev || new == next) && PANIC_CORRUPTION);
+
next->prev = new;
new->next = next;
new->prev = prev;
@@ -58,9 +63,11 @@
"list_del corruption. prev->next should be %p, "
"but was %p\n", entry, prev->next) ||
WARN(next->prev != entry,
- "list_del corruption. next->prev should be %p, "
- "but was %p\n", entry, next->prev))
+ "list_del corruption. next->prev should be %p, but was %p\n",
+ entry, next->prev)) {
+ BUG_ON(PANIC_CORRUPTION);
return;
+ }
__list_del(prev, next);
}
diff --git a/mm/memtest.c b/mm/memtest.c
index 8eaa4c3..15a423e 100644
--- a/mm/memtest.c
+++ b/mm/memtest.c
@@ -80,8 +80,8 @@
}
/* default is disabled */
-static unsigned int memtest_pattern __initdata;
-
+static unsigned int memtest_pattern __initdata =
+ CONFIG_MEMTEST_ENABLE_DEFAULT;
static int __init parse_memtest(char *arg)
{
int ret = 0;
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 60634dc..d2db436 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -25,7 +25,8 @@
depot_stack_handle_t handle;
};
-static bool page_owner_disabled = true;
+static bool page_owner_disabled =
+ !IS_ENABLED(CONFIG_PAGE_OWNER_ENABLE_DEFAULT);
DEFINE_STATIC_KEY_FALSE(page_owner_inited);
static depot_stack_handle_t dummy_handle;
@@ -41,6 +42,9 @@
if (strcmp(buf, "on") == 0)
page_owner_disabled = false;
+ if (strcmp(buf, "off") == 0)
+ page_owner_disabled = true;
+
return 0;
}
early_param("page_owner", early_page_owner_param);
diff --git a/mm/page_poison.c b/mm/page_poison.c
index 2e647c6..0abd75e 100644
--- a/mm/page_poison.c
+++ b/mm/page_poison.c
@@ -106,7 +106,8 @@
return error && !(error & (error - 1));
}
-static void check_poison_mem(unsigned char *mem, size_t bytes)
+static void check_poison_mem(struct page *page,
+ unsigned char *mem, size_t bytes)
{
static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 10);
unsigned char *start;
@@ -127,12 +128,15 @@
if (!__ratelimit(&ratelimit))
return;
else if (start == end && single_bit_flip(*start, PAGE_POISON))
- pr_err("pagealloc: single bit error\n");
+ pr_err("pagealloc: single bit error on page with phys start 0x%lx\n",
+ (unsigned long)page_to_phys(page));
else
- pr_err("pagealloc: memory corruption\n");
+ pr_err("pagealloc: memory corruption on page with phys start 0x%lx\n",
+ (unsigned long)page_to_phys(page));
print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 16, 1, start,
end - start + 1, 1);
+ BUG_ON(PANIC_CORRUPTION);
dump_stack();
}
@@ -144,7 +148,7 @@
return;
addr = kmap_atomic(page);
- check_poison_mem(addr, PAGE_SIZE);
+ check_poison_mem(page, addr, PAGE_SIZE);
clear_page_poison(page);
kunmap_atomic(addr);
}
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/wireless/reg.c b/net/wireless/reg.c
index eeb23d2..bc0ebd4 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2340,6 +2340,7 @@
return 0;
}
+EXPORT_SYMBOL(regulatory_hint_user);
int regulatory_hint_indoor(bool is_indoor, u32 portid)
{
diff --git a/net/wireless/reg.h b/net/wireless/reg.h
index f6ced31..822ac90 100644
--- a/net/wireless/reg.h
+++ b/net/wireless/reg.h
@@ -28,9 +28,6 @@
bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region);
enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy);
-int regulatory_hint_user(const char *alpha2,
- enum nl80211_user_reg_hint_type user_reg_hint_type);
-
/**
* regulatory_hint_indoor - hint operation in indoor env. or not
* @is_indoor: if true indicates that user space thinks that the
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..fe135b4 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
@@ -1159,11 +1159,12 @@
config SND_SOC_MSM_HDMI_CODEC_RX
bool "HDMI Audio Playback"
- depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSM8998)
+ depends on FB_MSM_MDSS_HDMI_PANEL && (SND_SOC_APQ8084 || SND_SOC_MSM8994 || SND_SOC_MSM8996 || SND_SOC_MSM8998 || SND_SOC_SDM660_COMMON)
help
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..46cfe7d 100644
--- a/sound/soc/codecs/msm_hdmi_codec_rx.c
+++ b/sound/soc/codecs/msm_hdmi_codec_rx.c
@@ -20,10 +20,17 @@
#include <linux/msm_ext_display.h>
#define MSM_EXT_DISP_PCM_RATES SNDRV_PCM_RATE_48000
+#define AUD_EXT_DISP_ACK_DISCONNECT (AUDIO_ACK_CONNECT ^ AUDIO_ACK_CONNECT)
+#define AUD_EXT_DISP_ACK_CONNECT (AUDIO_ACK_CONNECT)
+#define AUD_EXT_DISP_ACK_ENABLE (AUDIO_ACK_SET_ENABLE | AUDIO_ACK_ENABLE)
static const char *const ext_disp_audio_type_text[] = {"None", "HDMI", "DP"};
+static const char *const ext_disp_audio_ack_text[] = {"Disconnect", "Connect",
+ "Ack_Enable"};
static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_type, ext_disp_audio_type_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_audio_ack_state,
+ ext_disp_audio_ack_text);
struct msm_ext_disp_audio_codec_rx_data {
struct platform_device *ext_disp_core_pdev;
@@ -84,6 +91,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);
@@ -166,6 +182,55 @@
return rc;
}
+static int msm_ext_disp_audio_ack_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct msm_ext_disp_audio_codec_rx_data *codec_data;
+ u32 ack_state = 0;
+ int rc;
+
+ codec_data = snd_soc_codec_get_drvdata(codec);
+ if (!codec_data ||
+ !codec_data->ext_disp_ops.acknowledge) {
+ dev_err(codec->dev,
+ "%s: codec_data or ops acknowledge() is NULL\n",
+ __func__);
+ rc = -EINVAL;
+ goto done;
+ }
+
+ switch (ucontrol->value.enumerated.item[0]) {
+ case 0:
+ ack_state = AUD_EXT_DISP_ACK_DISCONNECT;
+ break;
+ case 1:
+ ack_state = AUD_EXT_DISP_ACK_CONNECT;
+ break;
+ case 2:
+ ack_state = AUD_EXT_DISP_ACK_ENABLE;
+ break;
+ default:
+ rc = -EINVAL;
+ dev_err(codec->dev,
+ "%s: invalid value %d for mixer ctl\n",
+ __func__, ucontrol->value.enumerated.item[0]);
+ goto done;
+ }
+ dev_dbg(codec->dev, "%s: control %d, ack set value 0x%x\n",
+ __func__, ucontrol->value.enumerated.item[0], ack_state);
+
+ rc = codec_data->ext_disp_ops.acknowledge(
+ codec_data->ext_disp_core_pdev, ack_state);
+ if (rc < 0) {
+ dev_err(codec->dev, "%s: error from acknowledge(), err:%d\n",
+ __func__, rc);
+ }
+
+done:
+ return rc;
+}
+
static const struct snd_kcontrol_new msm_ext_disp_codec_rx_controls[] = {
{
.access = SNDRV_CTL_ELEM_ACCESS_READ |
@@ -185,6 +250,8 @@
},
SOC_ENUM_EXT("External Display Type", ext_disp_audio_type,
msm_ext_disp_audio_type_get, NULL),
+ SOC_ENUM_EXT("External Display Audio Ack", ext_disp_audio_ack_state,
+ NULL, msm_ext_disp_audio_ack_set),
};
static int msm_ext_disp_audio_codec_rx_dai_startup(
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..502aa4f
--- /dev/null
+++ b/sound/soc/codecs/msm_sdw/msm_sdw_cdc.c
@@ -0,0 +1,1991 @@
+/* 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
+
+/*
+ * 200 Milliseconds sufficient for DSP bring up in the modem
+ * after Sub System Restart
+ */
+#define ADSP_STATE_READY_TIMEOUT_MS 200
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static struct snd_soc_dai_driver msm_sdw_dai[];
+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, 0x04);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX10_SPKR_PROT_PATH_CTL, 0x0F, 0x04);
+ 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,
+ 0x04);
+ snd_soc_update_bits(codec,
+ MSM_SDW_TX12_SPKR_PROT_PATH_CTL, 0x0F,
+ 0x04);
+ 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;
+
+ /*
+ * Add sleep as SWR slave access read takes time.
+ * Allow for RD_DONE to complete for previous register if any.
+ */
+ usleep_range(50, 55);
+
+ /* 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 clk_fs_rate, 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:
+ clk_fs_rate = 0x00;
+ fs_rate = 0x00;
+ break;
+ case 16000:
+ clk_fs_rate = 0x01;
+ fs_rate = 0x01;
+ break;
+ case 32000:
+ clk_fs_rate = 0x02;
+ fs_rate = 0x03;
+ break;
+ case 48000:
+ clk_fs_rate = 0x03;
+ fs_rate = 0x04;
+ break;
+ case 96000:
+ clk_fs_rate = 0x04;
+ fs_rate = 0x05;
+ break;
+ case 192000:
+ clk_fs_rate = 0x05;
+ fs_rate = 0x06;
+ break;
+ default:
+ dev_err(dai->codec->dev,
+ "%s: Invalid sampling rate %d\n", __func__,
+ params_rate(params));
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_TOP_TX_I2S_CTL, 0x1C,
+ (clk_fs_rate << 2));
+ } else {
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_TOP_RX_I2S_CTL, 0x1C,
+ (clk_fs_rate << 2));
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_RX7_RX_PATH_CTL, 0x0F,
+ fs_rate);
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_RX8_RX_PATH_CTL, 0x0F,
+ fs_rate);
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_TOP_TX_I2S_CTL, 0x20, 0x20);
+ else
+ 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:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ snd_soc_update_bits(dai->codec,
+ MSM_SDW_TOP_TX_I2S_CTL, 0x20, 0x00);
+ else
+ 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;
+ }
+
+ 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 = 4,
+ },
+ .ops = &msm_sdw_dai_ops,
+ },
+ {
+ .name = "msm_sdw_vifeedback",
+ .id = AIF1_SDW_VIFEED,
+ .capture = {
+ .stream_name = "VIfeed_SDW",
+ .rates = MSM_SDW_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rate_max = 48000,
+ .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);
+ bool adsp_ready = false;
+ unsigned long timeout;
+
+ 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 (!q6core_is_adsp_ready()) {
+ dev_dbg(msm_sdw->dev, "ADSP isn't ready\n");
+ timeout = jiffies +
+ msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
+ while (!time_after(jiffies, timeout)) {
+ if (!q6core_is_adsp_ready()) {
+ dev_dbg(msm_sdw->dev,
+ "ADSP isn't ready\n");
+ } else {
+ dev_dbg(msm_sdw->dev,
+ "ADSP is ready\n");
+ adsp_ready = true;
+ goto powerup;
+ }
+ }
+ } else {
+ adsp_ready = true;
+ dev_dbg(msm_sdw->dev, "%s: DSP is ready\n", __func__);
+ }
+powerup:
+ if (adsp_ready) {
+ 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;
+
+ 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..52e6815
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.c
@@ -0,0 +1,4607 @@
+/* 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 lpass
+ * after Sub System Restart
+ */
+#define ADSP_STATE_READY_TIMEOUT_MS 50
+
+#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 {
+ BOOST_SWITCH = 0,
+ BOOST_ALWAYS,
+ BYPASS_ALWAYS,
+ BOOST_ON_FOREVER,
+};
+
+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 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_priv *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_mbhc,
+ nblock);
+
+ return blocking_notifier_chain_unregister(&sdm660_cdc->notifier_mbhc,
+ 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_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+
+ 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_mbhc, 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);
+ }
+ 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 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_priv *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_priv *sdm660_cdc = handle;
+
+ 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_AIF_IN("PDM_IN_RX1", "PDM Playback",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PDM_IN_RX2", "PDM Playback",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("PDM_IN_RX3", "PDM Playback",
+ 0, SND_SOC_NOPM, 0, 0),
+
+ 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_AIF_OUT("ADC1_OUT", "PDM Capture",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("ADC2_OUT", "PDM Capture",
+ 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("ADC3_OUT", "PDM Capture",
+ 0, SND_SOC_NOPM, 0, 0),
+};
+
+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_priv *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);
+
+ 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);
+
+ 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:
+ 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_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+ 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;
+
+ 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;
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ int ret;
+
+ sdm660_cdc = dev_get_drvdata(codec->dev);
+ sdm660_cdc->codec = codec;
+
+ /* codec resmgr module init */
+ sdm660_cdc->spkdrv_reg =
+ msm_anlg_cdc_find_regulator(sdm660_cdc,
+ MSM89XX_VDD_SPKDRV_NAME);
+ sdm660_cdc->pmic_rev =
+ snd_soc_read(codec,
+ MSM89XX_PMIC_DIGITAL_REVISION1);
+ sdm660_cdc->codec_version =
+ snd_soc_read(codec,
+ MSM89XX_PMIC_DIGITAL_PERPH_SUBTYPE);
+ sdm660_cdc->analog_major_rev =
+ snd_soc_read(codec,
+ MSM89XX_PMIC_ANALOG_REVISION4);
+
+ if (sdm660_cdc->codec_version == CONGA) {
+ dev_dbg(codec->dev, "%s :Conga REV: %d\n", __func__,
+ sdm660_cdc->codec_version);
+ sdm660_cdc->ext_spk_boost_set = true;
+ } else {
+ dev_dbg(codec->dev, "%s :PMIC REV: %d\n", __func__,
+ sdm660_cdc->pmic_rev);
+ if (sdm660_cdc->pmic_rev == TOMBAK_1_0 &&
+ sdm660_cdc->codec_version == CAJON_2_0) {
+ if (sdm660_cdc->analog_major_rev == 0x02) {
+ sdm660_cdc->codec_version = DRAX_CDC;
+ dev_dbg(codec->dev,
+ "%s : Drax codec detected\n", __func__);
+ } else {
+ sdm660_cdc->codec_version = DIANGU;
+ dev_dbg(codec->dev, "%s : Diangu detected\n",
+ __func__);
+ }
+ } else if (sdm660_cdc->pmic_rev == TOMBAK_1_0 &&
+ (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
+ & 0x80)) {
+ sdm660_cdc->codec_version = CAJON;
+ dev_dbg(codec->dev, "%s : Cajon detected\n", __func__);
+ } else if (sdm660_cdc->pmic_rev == TOMBAK_2_0 &&
+ (snd_soc_read(codec, MSM89XX_PMIC_ANALOG_NCP_FBCTRL)
+ & 0x80)) {
+ sdm660_cdc->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->boost_option = BOOST_SWITCH;
+ sdm660_cdc->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->on_demand_list[ON_DEMAND_MICBIAS].supply =
+ msm_anlg_cdc_find_regulator(
+ sdm660_cdc,
+ on_demand_supply_name[ON_DEMAND_MICBIAS]);
+ atomic_set(&sdm660_cdc->on_demand_list[ON_DEMAND_MICBIAS].ref,
+ 0);
+
+ sdm660_cdc->fw_data = devm_kzalloc(codec->dev,
+ sizeof(*(sdm660_cdc->fw_data)),
+ GFP_KERNEL);
+ if (!sdm660_cdc->fw_data)
+ return -ENOMEM;
+
+ set_bit(WCD9XXX_MBHC_CAL, sdm660_cdc->fw_data->cal_bit);
+ ret = wcd_cal_create_hwdep(sdm660_cdc->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->mbhc, codec, &mbhc_cb, &intr_ids,
+ wcd_mbhc_registers, true);
+
+ sdm660_cdc->int_mclk0_enabled = false;
+ /*Update speaker boost configuration*/
+ sdm660_cdc->spk_boost_set = spkr_boost_en;
+ pr_debug("%s: speaker boost configured = %d\n",
+ __func__, sdm660_cdc->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);
+
+ snd_soc_dapm_ignore_suspend(dapm, "PDM Playback");
+ snd_soc_dapm_ignore_suspend(dapm, "PDM Capture");
+
+ return 0;
+}
+
+static int msm_anlg_cdc_soc_remove(struct snd_soc_codec *codec)
+{
+ struct sdm660_cdc_priv *sdm660_cdc_priv =
+ dev_get_drvdata(codec->dev);
+
+ 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_priv *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_priv *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 sdm660_cdc_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+ struct sdm660_cdc_pdata *sdm660_cdc_pdata =
+ sdm660_cdc->dev->platform_data;
+
+ 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_priv *sdm660_cdc = snd_soc_codec_get_drvdata(codec);
+ 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_priv *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_priv *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_priv *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_priv *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_priv,
+ 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_priv *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_priv),
+ 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);
+
+ 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__);
+ }
+ dev_set_drvdata(&pdev->dev, sdm660_cdc);
+
+ 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;
+ }
+ BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier);
+ BLOCKING_INIT_NOTIFIER_HEAD(&sdm660_cdc->notifier_mbhc);
+
+ 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_priv *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..0c9e9a6
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-analog-cdc.h
@@ -0,0 +1,237 @@
+/* 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_priv {
+ 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;
+ 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;
+ /* 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;
+};
+
+struct sdm660_cdc_pdata {
+ struct wcd_micbias_setting micbias;
+ struct sdm660_cdc_regulator regulator[MAX_REGULATOR];
+};
+
+
+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..f140b19
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.c
@@ -0,0 +1,2143 @@
+/* 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);
+
+ mutex_lock(&pdata->cdc_int_mclk0_mutex);
+ 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_INT0_MI2S_RX,
+ &pdata->digital_cdc_core_clk);
+ if (ret < 0) {
+ pr_err("%s:failed to enable the MCLK\n",
+ __func__);
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ return ret;
+ }
+ pr_debug("enabled digital codec core clk\n");
+ atomic_set(&pdata->int_mclk0_enabled, true);
+ schedule_delayed_work(&pdata->disable_int_mclk0_work,
+ 50);
+ }
+ } else {
+ dev_dbg(registered_digcodec->dev,
+ "disable MCLK, workq to disable set already\n");
+ }
+ mutex_unlock(&pdata->cdc_int_mclk0_mutex);
+ 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_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
+
+ 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_priv *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 = hpf_work->dig_cdc;
+ 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 *msm_dig_cdc = 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_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)
+ msm_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)
+ msm_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_priv *msm_dig_cdc = snd_soc_codec_get_drvdata(codec);
+ 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;
+ if (msm_dig->get_cdc_version)
+ msm_dig->version = msm_dig->get_cdc_version(msm_dig->handle);
+ else
+ msm_dig->version = DRAX_CDC;
+
+ 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 *msm_dig_cdc = dev_get_drvdata(codec->dev);
+ struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
+ int i, ret;
+
+ msm_dig_cdc->codec = codec;
+
+ 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 = msm_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++)
+ msm_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;
+ }
+ }
+ registered_digcodec = codec;
+
+ snd_soc_dapm_ignore_suspend(dapm, "AIF1 Playback");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF1 Capture");
+ snd_soc_dapm_ignore_suspend(dapm, "ADC1_IN");
+ snd_soc_dapm_ignore_suspend(dapm, "ADC2_IN");
+ snd_soc_dapm_ignore_suspend(dapm, "ADC3_IN");
+ snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX1");
+ snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX2");
+ snd_soc_dapm_ignore_suspend(dapm, "PDM_OUT_RX3");
+
+ return 0;
+}
+
+static int msm_dig_cdc_soc_remove(struct snd_soc_codec *codec)
+{
+ struct msm_dig_priv *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_priv *msm_dig_cdc = dev_get_drvdata(dev);
+
+ return msm_dig_cdc->regmap;
+}
+
+static int msm_dig_cdc_suspend(struct snd_soc_codec *codec)
+{
+ struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+ msm_dig_cdc->dapm_bias_off = 1;
+ return 0;
+}
+
+static int msm_dig_cdc_resume(struct snd_soc_codec *codec)
+{
+ struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(codec->dev);
+
+ msm_dig_cdc->dapm_bias_off = 0;
+ return 0;
+}
+
+static struct snd_soc_codec_driver soc_msm_dig_codec = {
+ .probe = msm_dig_cdc_soc_probe,
+ .remove = msm_dig_cdc_soc_remove,
+ .suspend = msm_dig_cdc_suspend,
+ .resume = msm_dig_cdc_resume,
+ .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_priv *msm_dig_cdc;
+ struct dig_ctrl_platform_data *pdata;
+
+ msm_dig_cdc = devm_kzalloc(&pdev->dev, sizeof(struct msm_dig_priv),
+ 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;
+ }
+
+ 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;
+
+ dev_set_drvdata(&pdev->dev, msm_dig_cdc);
+ 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;
+}
+
+#ifdef CONFIG_PM
+static int msm_dig_suspend(struct device *dev)
+{
+ struct msm_asoc_mach_data *pdata =
+ snd_soc_card_get_drvdata(registered_digcodec->component.card);
+ struct msm_dig_priv *msm_dig_cdc = dev_get_drvdata(dev);
+
+ if (msm_dig_cdc->dapm_bias_off) {
+ 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);
+ }
+ }
+
+ return 0;
+}
+
+static int msm_dig_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops msm_dig_pm_ops = {
+ .suspend = msm_dig_suspend,
+ .resume = msm_dig_resume,
+};
+#endif
+
+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,
+#ifdef CONFIG_PM
+ .pm = &msm_dig_pm_ops,
+#endif
+ },
+ .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..f0e7a9c
--- /dev/null
+++ b/sound/soc/codecs/sdm660_cdc/msm-digital-cdc.h
@@ -0,0 +1,91 @@
+/* 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;
+ char __iomem *dig_base;
+ struct regmap *regmap;
+ struct notifier_block nblock;
+ u32 mute_mask;
+ int dapm_bias_off;
+ 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 f4c68ff..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);
@@ -570,6 +571,9 @@
static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
enum snd_jack_types jack_type)
{
+ struct snd_soc_codec *codec = mbhc->codec;
+ bool is_pa_on = false;
+
WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
pr_debug("%s: enter insertion %d hph_status %x\n",
@@ -595,14 +599,14 @@
if (mbhc->micbias_enable) {
if (mbhc->mbhc_cb->mbhc_micbias_control)
mbhc->mbhc_cb->mbhc_micbias_control(
- mbhc->codec, MIC_BIAS_2,
+ codec, MIC_BIAS_2,
MICB_DISABLE);
if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
- mbhc->codec,
+ codec,
MIC_BIAS_2, false);
if (mbhc->mbhc_cb->set_micbias_value) {
- mbhc->mbhc_cb->set_micbias_value(mbhc->codec);
+ mbhc->mbhc_cb->set_micbias_value(codec);
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
}
mbhc->micbias_enable = false;
@@ -632,15 +636,15 @@
if (mbhc->micbias_enable) {
if (mbhc->mbhc_cb->mbhc_micbias_control)
mbhc->mbhc_cb->mbhc_micbias_control(
- mbhc->codec, MIC_BIAS_2,
+ codec, MIC_BIAS_2,
MICB_DISABLE);
if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
- mbhc->codec,
+ codec,
MIC_BIAS_2, false);
if (mbhc->mbhc_cb->set_micbias_value) {
mbhc->mbhc_cb->set_micbias_value(
- mbhc->codec);
+ codec);
WCD_MBHC_REG_UPDATE_BITS(
WCD_MBHC_MICB_CTRL, 0);
}
@@ -691,9 +695,13 @@
} else if (jack_type == SND_JACK_ANC_HEADPHONE)
mbhc->current_plug = MBHC_PLUG_TYPE_ANC_HEADPHONE;
+ if (mbhc->mbhc_cb->hph_pa_on_status)
+ is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(codec);
+
if (mbhc->impedance_detect &&
mbhc->mbhc_cb->compute_impedance &&
- (mbhc->mbhc_cfg->linein_th != 0)) {
+ (mbhc->mbhc_cfg->linein_th != 0) &&
+ (!is_pa_on)) {
mbhc->mbhc_cb->compute_impedance(mbhc,
&mbhc->zl, &mbhc->zr);
if ((mbhc->zl > mbhc->mbhc_cfg->linein_th &&
@@ -1158,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__);
@@ -1175,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);
/*
@@ -1207,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))) {
@@ -1226,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)
@@ -1251,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)
@@ -1448,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);
@@ -1472,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);
@@ -1549,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) {
@@ -1566,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);
@@ -1603,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);
@@ -1754,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__);
@@ -1930,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) {
@@ -1952,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,
@@ -1983,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;
@@ -2128,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);
@@ -2136,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);
@@ -2300,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");
@@ -2325,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);
@@ -2354,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);
@@ -2372,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";
@@ -2392,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-dsd.c b/sound/soc/codecs/wcd934x/wcd934x-dsd.c
index 580591a..3e23e37 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-dsd.c
+++ b/sound/soc/codecs/wcd934x/wcd934x-dsd.c
@@ -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
@@ -97,6 +97,11 @@
{"DSD_FILTER_1", NULL, "DSD_R IF MUX"},
{"DSD_FILTER_1", NULL, "RX INT2 NATIVE SUPPLY"},
{"RX INT2 MIX3", "DSD HPHR Switch", "DSD_FILTER_1"},
+
+ {"DSD_FILTER_0", NULL, "RX INT3 NATIVE SUPPLY"},
+ {"RX INT3 MIX3", "DSD LO1 Switch", "DSD_FILTER_0"},
+ {"DSD_FILTER_1", NULL, "RX INT4 NATIVE SUPPLY"},
+ {"RX INT4 MIX3", "DSD LO2 Switch", "DSD_FILTER_1"},
};
static bool is_valid_dsd_interpolator(int interp_num)
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-mbhc.h b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
index d001fa2..d40546a 100644
--- a/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
+++ b/sound/soc/codecs/wcd934x/wcd934x-mbhc.h
@@ -35,6 +35,7 @@
bool is_hph_recover;
};
+#ifdef CONFIG_SND_SOC_WCD934X_MBHC
extern int tavil_mbhc_init(struct wcd934x_mbhc **mbhc,
struct snd_soc_codec *codec,
struct fw_info *fw_data);
@@ -46,4 +47,38 @@
struct snd_soc_codec *codec);
extern int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc,
uint32_t *zl, uint32_t *zr);
+#else
+static inline int tavil_mbhc_init(struct wcd934x_mbhc **mbhc,
+ struct snd_soc_codec *codec,
+ struct fw_info *fw_data)
+{
+ return 0;
+}
+static inline void tavil_mbhc_hs_detect_exit(struct snd_soc_codec *codec)
+{
+}
+static inline int tavil_mbhc_hs_detect(struct snd_soc_codec *codec,
+ struct wcd_mbhc_config *mbhc_cfg)
+{
+ return 0;
+}
+static inline void tavil_mbhc_deinit(struct snd_soc_codec *codec)
+{
+}
+static inline int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc,
+ struct snd_soc_codec *codec)
+{
+ return 0;
+}
+static inline int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc,
+ uint32_t *zl, uint32_t *zr)
+{
+ if (zl)
+ *zl = 0;
+ if (zr)
+ *zr = 0;
+ return -EINVAL;
+}
+#endif
+
#endif /* __WCD934X_MBHC_H__ */
diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h
index 8ca4c07..afd93b2 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
@@ -872,7 +872,8 @@
{"RX INT3 SEC MIX", NULL, "RX INT3_1 INTERP"},
{"RX INT3 MIX2", NULL, "RX INT3 SEC MIX"},
{"RX INT3 MIX2", NULL, "RX INT3 MIX2 INP"},
- {"RX INT3 DAC", NULL, "RX INT3 MIX2"},
+ {"RX INT3 MIX3", NULL, "RX INT3 MIX2"},
+ {"RX INT3 DAC", NULL, "RX INT3 MIX3"},
{"RX INT3 DAC", NULL, "RX_BIAS"},
{"LINEOUT1 PA", NULL, "RX INT3 DAC"},
{"LINEOUT1", NULL, "LINEOUT1 PA"},
@@ -882,7 +883,8 @@
{"RX INT4 SEC MIX", NULL, "RX INT4_1 MIX1"},
{"RX INT4 MIX2", NULL, "RX INT4 SEC MIX"},
{"RX INT4 MIX2", NULL, "RX INT4 MIX2 INP"},
- {"RX INT4 DAC", NULL, "RX INT4 MIX2"},
+ {"RX INT4 MIX3", NULL, "RX INT4 MIX2"},
+ {"RX INT4 DAC", NULL, "RX INT4 MIX3"},
{"RX INT4 DAC", NULL, "RX_BIAS"},
{"LINEOUT2 PA", NULL, "RX INT4 DAC"},
{"LINEOUT2", NULL, "LINEOUT2 PA"},
@@ -914,9 +916,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..4b6fcb0b 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,
@@ -2069,6 +2292,9 @@
{
struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0;
+ u16 dsd_mute_reg = 0, dsd_clk_reg = 0;
+ struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
+ struct tavil_dsd_config *dsd_conf = tavil->dsd_config;
dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
@@ -2076,9 +2302,13 @@
if (w->shift == 7) {
lineout_vol_reg = WCD934X_CDC_RX3_RX_PATH_CTL;
lineout_mix_vol_reg = WCD934X_CDC_RX3_RX_PATH_MIX_CTL;
+ dsd_mute_reg = WCD934X_CDC_DSD0_CFG2;
+ dsd_clk_reg = WCD934X_CDC_DSD0_PATH_CTL;
} else if (w->shift == 6) {
lineout_vol_reg = WCD934X_CDC_RX4_RX_PATH_CTL;
lineout_mix_vol_reg = WCD934X_CDC_RX4_RX_PATH_MIX_CTL;
+ dsd_mute_reg = WCD934X_CDC_DSD1_CFG2;
+ dsd_clk_reg = WCD934X_CDC_DSD1_PATH_CTL;
}
} else {
dev_err(codec->dev, "%s: Error enabling lineout PA\n",
@@ -2103,6 +2333,12 @@
snd_soc_update_bits(codec,
lineout_mix_vol_reg,
0x10, 0x00);
+ if (dsd_conf && (snd_soc_read(codec, dsd_clk_reg) & 0x01))
+ snd_soc_update_bits(codec, dsd_mute_reg, 0x04, 0x00);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if (dsd_conf && (snd_soc_read(codec, dsd_clk_reg) & 0x01))
+ snd_soc_update_bits(codec, dsd_mute_reg, 0x04, 0x04);
break;
case SND_SOC_DAPM_POST_PMD:
/*
@@ -2167,12 +2403,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 +2445,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 +2492,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 +2528,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 +2852,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 +2863,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 +3417,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 +3880,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 +3889,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 +5397,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 +5417,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 +5427,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 +6718,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);
@@ -6554,6 +6831,16 @@
tavil_dsd_mixer_get, tavil_dsd_mixer_put),
};
+static const struct snd_kcontrol_new lo1_mixer[] = {
+ SOC_SINGLE_EXT("DSD LO1 Switch", SND_SOC_NOPM, INTERP_LO1, 1, 0,
+ tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
+static const struct snd_kcontrol_new lo2_mixer[] = {
+ SOC_SINGLE_EXT("DSD LO2 Switch", SND_SOC_NOPM, INTERP_LO2, 1, 0,
+ tavil_dsd_mixer_get, tavil_dsd_mixer_put),
+};
+
static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
AIF1_PB, 0, tavil_codec_enable_slimrx,
@@ -6686,7 +6973,11 @@
SND_SOC_DAPM_MIXER("RX INT2 MIX3", SND_SOC_NOPM, 0, 0, hphr_mixer,
ARRAY_SIZE(hphr_mixer)),
SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT3 MIX3", SND_SOC_NOPM, 0, 0, lo1_mixer,
+ ARRAY_SIZE(lo1_mixer)),
SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT4 MIX3", SND_SOC_NOPM, 0, 0, lo2_mixer,
+ ARRAY_SIZE(lo2_mixer)),
SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_MIXER_E("RX INT7 CHAIN", SND_SOC_NOPM, 0, 0,
NULL, 0, tavil_codec_spk_boost_event,
@@ -7075,17 +7366,25 @@
SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD934X_ANA_LO_1_2, 7, 0, NULL, 0,
tavil_codec_enable_lineout_pa,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0,
tavil_codec_enable_lineout_pa,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0,
tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
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 +7394,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 +7404,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),
@@ -7787,13 +8095,8 @@
static void tavil_codec_power_gate_digital_core(struct tavil_priv *tavil)
{
- struct snd_soc_codec *codec = tavil->codec;
-
- if (!codec)
- return;
-
mutex_lock(&tavil->power_lock);
- dev_dbg(codec->dev, "%s: Entering power gating function, %d\n",
+ dev_dbg(tavil->dev, "%s: Entering power gating function, %d\n",
__func__, tavil->power_active_ref);
if (tavil->power_active_ref > 0)
@@ -7802,16 +8105,16 @@
wcd9xxx_set_power_state(tavil->wcd9xxx,
WCD_REGION_POWER_COLLAPSE_BEGIN,
WCD9XXX_DIG_CORE_REGION_1);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
- 0x04, 0x04);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
- 0x01, 0x00);
- snd_soc_update_bits(codec, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL,
- 0x02, 0x00);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x04, 0x04);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x01, 0x00);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x02, 0x00);
wcd9xxx_set_power_state(tavil->wcd9xxx, WCD_REGION_POWER_DOWN,
WCD9XXX_DIG_CORE_REGION_1);
exit:
- dev_dbg(codec->dev, "%s: Exiting power gating function, %d\n",
+ dev_dbg(tavil->dev, "%s: Exiting power gating function, %d\n",
__func__, tavil->power_active_ref);
mutex_unlock(&tavil->power_lock);
}
@@ -7820,34 +8123,32 @@
{
struct tavil_priv *tavil;
struct delayed_work *dwork;
- struct snd_soc_codec *codec;
dwork = to_delayed_work(work);
tavil = container_of(dwork, struct tavil_priv, power_gate_work);
- codec = tavil->codec;
-
- if (!codec)
- return;
tavil_codec_power_gate_digital_core(tavil);
}
/* called under power_lock acquisition */
-static int tavil_dig_core_remove_power_collapse(struct snd_soc_codec *codec)
+static int tavil_dig_core_remove_power_collapse(struct tavil_priv *tavil)
{
- struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec);
-
- 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);
+ regmap_write(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x05);
+ regmap_write(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x07);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x00);
+ regmap_update_bits(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_RST_CTL, 0x02, 0x02);
+ regmap_write(tavil->wcd9xxx->regmap,
+ WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x03);
wcd9xxx_set_power_state(tavil->wcd9xxx,
WCD_REGION_POWER_COLLAPSE_REMOVE,
WCD9XXX_DIG_CORE_REGION_1);
- regcache_mark_dirty(codec->component.regmap);
- regcache_sync_region(codec->component.regmap,
+ regcache_mark_dirty(tavil->wcd9xxx->regmap);
+ regcache_sync_region(tavil->wcd9xxx->regmap,
WCD934X_DIG_CORE_REG_MIN,
WCD934X_DIG_CORE_REG_MAX);
@@ -7857,7 +8158,6 @@
static int tavil_dig_core_power_collapse(struct tavil_priv *tavil,
int req_state)
{
- struct snd_soc_codec *codec;
int cur_state;
/* Exit if feature is disabled */
@@ -7878,10 +8178,6 @@
goto unlock_mutex;
}
- codec = tavil->codec;
- if (!codec)
- goto unlock_mutex;
-
if (req_state == POWER_COLLAPSE) {
if (tavil->power_active_ref == 0) {
schedule_delayed_work(&tavil->power_gate_work,
@@ -7899,7 +8195,7 @@
tavil->wcd9xxx,
WCD9XXX_DIG_CORE_REGION_1);
if (cur_state == WCD_REGION_POWER_DOWN) {
- tavil_dig_core_remove_power_collapse(codec);
+ tavil_dig_core_remove_power_collapse(tavil);
} else {
mutex_unlock(&tavil->power_lock);
cancel_delayed_work_sync(
@@ -8799,13 +9095,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 +9104,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 +9300,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);
@@ -9027,6 +9314,7 @@
snd_soc_dapm_ignore_suspend(dapm, "AIF3 Playback");
snd_soc_dapm_ignore_suspend(dapm, "AIF3 Capture");
snd_soc_dapm_ignore_suspend(dapm, "AIF4 Playback");
+ snd_soc_dapm_ignore_suspend(dapm, "AIF4 MAD TX");
snd_soc_dapm_ignore_suspend(dapm, "VIfeed");
snd_soc_dapm_sync(dapm);
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-temp-sensor.c b/sound/soc/codecs/wsa881x-temp-sensor.c
index 0079d0f..5ab0ecf 100644
--- a/sound/soc/codecs/wsa881x-temp-sensor.c
+++ b/sound/soc/codecs/wsa881x-temp-sensor.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 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
@@ -23,7 +23,7 @@
#define LOW_TEMP_THRESHOLD 5
#define HIGH_TEMP_THRESHOLD 45
#define TEMP_INVALID 0xFFFF
-
+#define WSA881X_TEMP_RETRY 3
/*
* wsa881x_get_temp - get wsa temperature
* @thermal: thermal zone device
@@ -44,6 +44,7 @@
int temp_val;
int t1 = T1_TEMP;
int t2 = T2_TEMP;
+ u8 retry = WSA881X_TEMP_RETRY;
if (!thermal)
return -EINVAL;
@@ -60,6 +61,7 @@
pr_err("%s: pdata is NULL\n", __func__);
return -EINVAL;
}
+temp_retry:
if (pdata->wsa_temp_reg_read) {
ret = pdata->wsa_temp_reg_read(codec, ®);
if (ret) {
@@ -101,6 +103,10 @@
printk_ratelimited("%s: T0: %d is out of range[%d, %d]\n",
__func__, temp_val, LOW_TEMP_THRESHOLD,
HIGH_TEMP_THRESHOLD);
+ if (retry--) {
+ msleep(20);
+ goto temp_retry;
+ }
}
if (temp)
*temp = temp_val;
diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c
index e689570..062bae2 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;
}
@@ -988,6 +986,7 @@
{
struct wsa881x_priv *wsa881x = snd_soc_codec_get_drvdata(codec);
struct swr_device *dev;
+ u8 retry = WSA881X_NUM_RETRY;
u8 devnum = 0;
if (!wsa881x) {
@@ -996,7 +995,12 @@
}
dev = wsa881x->swr_slave;
if (dev && (wsa881x->state == WSA881X_DEV_DOWN)) {
- if (swr_get_logical_dev_num(dev, dev->addr, &devnum)) {
+ while (swr_get_logical_dev_num(dev, dev->addr, &devnum) &&
+ retry--) {
+ /* Retry after 1 msec delay */
+ usleep_range(1000, 1100);
+ }
+ if (retry == 0) {
dev_err(codec->dev,
"%s get devnum %d for dev addr %lx failed\n",
__func__, devnum, dev->addr);
@@ -1108,8 +1112,9 @@
usleep_range(5000, 5010);
ret = swr_get_logical_dev_num(swr_dev, swr_dev->addr, &devnum);
if (ret) {
- dev_dbg(&swr_dev->dev, "%s failed to get devnum, err:%d\n",
- __func__, ret);
+ dev_dbg(&swr_dev->dev,
+ "%s get devnum %d for dev addr %lx failed\n",
+ __func__, devnum, swr_dev->addr);
goto err;
}
swr_dev->dev_num = devnum;
diff --git a/sound/soc/msm/Kconfig b/sound/soc/msm/Kconfig
index 5f9d42c..18585749 100644
--- a/sound/soc/msm/Kconfig
+++ b/sound/soc/msm/Kconfig
@@ -30,16 +30,6 @@
is inducing kernel panic upon encountering critical
errors from DSP audio modules
-config DOLBY_DAP
- bool "Enable Dolby DAP"
- depends on SND_SOC_MSM_QDSP6V2_INTF
- help
- To add support for dolby DAP post processing.
- This support is to configure the post processing parameters
- to DSP. The configuration includes sending the end point
- device, end point dependent post processing parameters and
- the various posrt processing parameters
-
config DOLBY_DS2
bool "Enable Dolby DS2"
depends on SND_SOC_MSM_QDSP6V2_INTF
@@ -108,7 +98,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 +109,19 @@
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 SND_SOC_MSM_HDMI_CODEC_RX
select QTI_PP
select DTS_SRS_TM
- select DOLBY_DAP
- select DOLBY_DS2
+ select DOLBY_LICENSE
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 +130,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
@@ -152,18 +144,19 @@
select SND_SOC_WCD9335
select SND_SOC_WCD934X
select SND_SOC_WSA881X
+ select SND_SOC_MSM_HDMI_CODEC_RX
select MFD_CORE
select QTI_PP
select DTS_SRS_TM
- select DOLBY_DAP
- select DOLBY_DS2
+ select DOLBY_LICENSE
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 +223,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..7b65dda 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);
@@ -2108,7 +2148,8 @@
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "LSM_REG_SND_MODEL_V2");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&snd_model, (void *)arg,
@@ -2173,7 +2214,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);
}
@@ -2185,7 +2279,8 @@
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SNDRV_LSM_SET_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&det_params, (void *) arg,
@@ -2212,14 +2307,16 @@
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (!arg) {
dev_err(rtd->dev,
"%s: %s: No Param data to set\n",
__func__, "SET_MODULE_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&p_data, arg,
@@ -2227,7 +2324,8 @@
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "p_data", sizeof(p_data));
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
if (p_data.num_params > LSM_PARAMS_MAX) {
@@ -2235,7 +2333,8 @@
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS",
p_data.num_params);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
p_size = p_data.num_params *
@@ -2246,12 +2345,15 @@
"%s: %s: Invalid size %zd\n",
__func__, "SET_MODULE_PARAMS", p_size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
params = kzalloc(p_size, GFP_KERNEL);
- if (!params)
- return -ENOMEM;
+ if (!params) {
+ err = -ENOMEM;
+ goto done;
+ }
if (copy_from_user(params, p_data.params,
p_data.data_size)) {
@@ -2259,7 +2361,8 @@
"%s: %s: copy_from_user failed, size = %d\n",
__func__, "params", p_data.data_size);
kfree(params);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
err = msm_cpe_lsm_process_params(substream, &p_data, params);
@@ -2282,12 +2385,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 +2406,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 +2416,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 =
@@ -2378,7 +2473,8 @@
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "LSM_REG_SND_MODEL_V2_32");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
dev_dbg(rtd->dev,
@@ -2414,7 +2510,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 +2552,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 +2590,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);
@@ -2509,7 +2694,9 @@
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SNDRV_LSM_SET_PARAMS32");
- return -EINVAL;
+
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&det_params32, arg,
@@ -2553,14 +2740,8 @@
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS_32");
- return -EINVAL;
- }
-
- if (!arg) {
- dev_err(rtd->dev,
- "%s: %s: No Param data to set\n",
- __func__, "SET_MODULE_PARAMS_32");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&p_data_32, arg,
@@ -2569,7 +2750,8 @@
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "SET_MODULE_PARAMS_32",
sizeof(p_data_32));
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
p_data.params = compat_ptr(p_data_32.params);
@@ -2581,7 +2763,8 @@
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.num_params);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (p_data.data_size !=
@@ -2590,21 +2773,25 @@
"%s: %s: Invalid size %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.data_size);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
p_size = sizeof(struct lsm_params_info_32) *
p_data.num_params;
params32 = kzalloc(p_size, GFP_KERNEL);
- if (!params32)
- return -ENOMEM;
+ if (!params32) {
+ err = -ENOMEM;
+ goto done;
+ }
p_size = sizeof(struct lsm_params_info) * p_data.num_params;
params = kzalloc(p_size, GFP_KERNEL);
if (!params) {
kfree(params32);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto done;
}
if (copy_from_user(params32, p_data.params,
@@ -2614,7 +2801,8 @@
__func__, "params32", p_data.data_size);
kfree(params32);
kfree(params);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
p_info_32 = (struct lsm_params_info_32 *) params32;
@@ -2640,6 +2828,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..755b62a 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 |
@@ -894,7 +964,7 @@
.formats = (SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE),
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rate_min = 8000,
.rate_max = 192000,
},
@@ -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 73755ed..51c27b7 100644
--- a/sound/soc/msm/msm8998.c
+++ b/sound/soc/msm/msm8998.c
@@ -159,6 +159,21 @@
u32 index;
};
+enum pinctrl_pin_state {
+ STATE_DISABLE = 0, /* All pins are in sleep state */
+ STATE_MI2S_ACTIVE, /* IS2 = active, TDM = sleep */
+ STATE_TDM_ACTIVE, /* IS2 = sleep, TDM = active */
+};
+
+struct msm_pinctrl_info {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *mi2s_disable;
+ struct pinctrl_state *tdm_disable;
+ struct pinctrl_state *mi2s_active;
+ struct pinctrl_state *tdm_active;
+ enum pinctrl_pin_state curr_state;
+};
+
struct msm_asoc_mach_data {
u32 mclk_freq;
int us_euro_gpio; /* used by gpio driver API */
@@ -166,6 +181,7 @@
struct device_node *hph_en1_gpio_p; /* used by pinctrl API */
struct device_node *hph_en0_gpio_p; /* used by pinctrl API */
struct snd_info_entry *codec_root;
+ struct msm_pinctrl_info pinctrl_info;
};
struct msm_asoc_wcd93xx_codec {
@@ -174,6 +190,9 @@
void (*mbhc_hs_detect_exit)(struct snd_soc_codec *codec);
};
+static const char *const pin_states[] = {"sleep", "i2s-active",
+ "tdm-active"};
+
enum {
TDM_0 = 0,
TDM_1,
@@ -402,7 +421,8 @@
"KHZ_88P2", "KHZ_96", "KHZ_176P4",
"KHZ_192", "KHZ_352P8", "KHZ_384"};
static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
- "KHZ_192"};
+ "KHZ_192", "KHZ_32", "KHZ_44P1",
+ "KHZ_88P2", "KHZ_176P4"};
static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight"};
static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
@@ -514,6 +534,9 @@
.key_code[7] = 0,
.linein_th = 5000,
.moisture_en = true,
+ .mbhc_micbias = MIC_BIAS_2,
+ .anc_micbias = MIC_BIAS_2,
+ .enable_anc_mic_detect = false,
};
static struct snd_soc_dapm_route wcd_audio_paths_tasha[] = {
@@ -1479,6 +1502,22 @@
return idx;
switch (ext_disp_rx_cfg[idx].sample_rate) {
+ case SAMPLING_RATE_176P4KHZ:
+ sample_rate_val = 6;
+ break;
+
+ case SAMPLING_RATE_88P2KHZ:
+ sample_rate_val = 5;
+ break;
+
+ case SAMPLING_RATE_44P1KHZ:
+ sample_rate_val = 4;
+ break;
+
+ case SAMPLING_RATE_32KHZ:
+ sample_rate_val = 3;
+ break;
+
case SAMPLING_RATE_192KHZ:
sample_rate_val = 2;
break;
@@ -1509,6 +1548,18 @@
return idx;
switch (ucontrol->value.integer.value[0]) {
+ case 6:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_176P4KHZ;
+ break;
+ case 5:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_88P2KHZ;
+ break;
+ case 4:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_44P1KHZ;
+ break;
+ case 3:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_32KHZ;
+ break;
case 2:
ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
break;
@@ -3321,6 +3372,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 +3432,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;
@@ -3978,6 +4048,275 @@
return ret;
}
+static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info,
+ enum pinctrl_pin_state new_state)
+{
+ int ret = 0;
+ int curr_state = 0;
+
+ if (pinctrl_info == NULL) {
+ pr_err("%s: pinctrl_info is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ curr_state = pinctrl_info->curr_state;
+ pinctrl_info->curr_state = new_state;
+ pr_debug("%s: curr_state = %s new_state = %s\n", __func__,
+ pin_states[curr_state], pin_states[pinctrl_info->curr_state]);
+
+ if (curr_state == pinctrl_info->curr_state) {
+ pr_debug("%s: Already in same state\n", __func__);
+ goto err;
+ }
+
+ if (curr_state != STATE_DISABLE &&
+ pinctrl_info->curr_state != STATE_DISABLE) {
+ pr_debug("%s: state already active cannot switch\n", __func__);
+ ret = -EIO;
+ goto err;
+ }
+
+ switch (pinctrl_info->curr_state) {
+ case STATE_MI2S_ACTIVE:
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_active);
+ if (ret) {
+ pr_err("%s: MI2S state select failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ case STATE_TDM_ACTIVE:
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->tdm_active);
+ if (ret) {
+ pr_err("%s: TDM state select failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ case STATE_DISABLE:
+ if (curr_state == STATE_MI2S_ACTIVE) {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_disable);
+ } else {
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->tdm_disable);
+ }
+ if (ret) {
+ pr_err("%s: state disable failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ break;
+ default:
+ pr_err("%s: TLMM pin state is invalid\n", __func__);
+ return -EINVAL;
+ }
+
+err:
+ return ret;
+}
+
+static void msm_release_pinctrl(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ if (pinctrl_info->pinctrl) {
+ devm_pinctrl_put(pinctrl_info->pinctrl);
+ pinctrl_info->pinctrl = NULL;
+ }
+}
+
+static int msm_get_pinctrl(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = NULL;
+ struct pinctrl *pinctrl;
+ int ret;
+
+ pinctrl_info = &pdata->pinctrl_info;
+
+ if (pinctrl_info == NULL) {
+ pr_err("%s: pinctrl_info is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR_OR_NULL(pinctrl)) {
+ pr_err("%s: Unable to get pinctrl handle\n", __func__);
+ return -EINVAL;
+ }
+ pinctrl_info->pinctrl = pinctrl;
+
+ /* get all the states handles from Device Tree */
+ pinctrl_info->mi2s_disable = pinctrl_lookup_state(pinctrl,
+ "quat-mi2s-sleep");
+ if (IS_ERR(pinctrl_info->mi2s_disable)) {
+ pr_err("%s: could not get mi2s_disable pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->mi2s_active = pinctrl_lookup_state(pinctrl,
+ "quat-mi2s-active");
+ if (IS_ERR(pinctrl_info->mi2s_active)) {
+ pr_err("%s: could not get mi2s_active pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->tdm_disable = pinctrl_lookup_state(pinctrl,
+ "quat-tdm-sleep");
+ if (IS_ERR(pinctrl_info->tdm_disable)) {
+ pr_err("%s: could not get tdm_disable pinstate\n", __func__);
+ goto err;
+ }
+ pinctrl_info->tdm_active = pinctrl_lookup_state(pinctrl,
+ "quat-tdm-active");
+ if (IS_ERR(pinctrl_info->tdm_active)) {
+ pr_err("%s: could not get tdm_active pinstate\n",
+ __func__);
+ goto err;
+ }
+ /* Reset the TLMM pins to a default state */
+ ret = pinctrl_select_state(pinctrl_info->pinctrl,
+ pinctrl_info->mi2s_disable);
+ if (ret != 0) {
+ pr_err("%s: Disable TLMM pins failed with %d\n",
+ __func__, ret);
+ ret = -EIO;
+ goto err;
+ }
+ pinctrl_info->curr_state = STATE_DISABLE;
+
+ return 0;
+
+err:
+ devm_pinctrl_put(pinctrl);
+ pinctrl_info->pinctrl = NULL;
+ return -EINVAL;
+}
+
+static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) {
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format);
+ rate->min = rate->max =
+ tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate;
+ } else if (cpu_dai->id == AFE_PORT_ID_SECONDARY_TDM_RX) {
+ channels->min = channels->max =
+ tdm_rx_cfg[TDM_SEC][TDM_0].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ tdm_rx_cfg[TDM_SEC][TDM_0].bit_format);
+ rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate;
+ } else {
+ pr_err("%s: dai id 0x%x not supported\n",
+ __func__, cpu_dai->id);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: dai id = 0x%x channels = %d rate = %d format = 0x%x\n",
+ __func__, cpu_dai->id, channels->max, rate->max,
+ params_format(params));
+
+ return 0;
+}
+
+static int msm8998_tdm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ int channels, slot_width, slots;
+ unsigned int slot_mask;
+ unsigned int slot_offset[8] = {0, 4, 8, 12, 16, 20, 24, 28};
+
+ pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id);
+
+ slots = tdm_rx_cfg[TDM_QUAT][TDM_0].channels;
+ /*2 slot config - bits 0 and 1 set for the first two slots */
+ slot_mask = 0x0000FFFF >> (16-slots);
+ slot_width = 32;
+ channels = slots;
+
+ pr_debug("%s: slot_width %d slots %d\n", __func__, slot_width, slots);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ pr_debug("%s: slot_width %d\n", __func__, slot_width);
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask,
+ slots, slot_width);
+ if (ret < 0) {
+ pr_err("%s: failed to set tdm slot, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ 0, NULL, channels, slot_offset);
+ if (ret < 0) {
+ pr_err("%s: failed to set channel map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ pr_err("%s: invalid use case, err:%d\n",
+ __func__, ret);
+ }
+
+end:
+ return ret;
+}
+
+static int msm8998_tdm_snd_startup(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static void msm8998_tdm_snd_shutdown(struct snd_pcm_substream *substream)
+{
+ int ret = 0;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
+
+ ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+
+}
+
+static struct snd_soc_ops msm8998_tdm_be_ops = {
+ .hw_params = msm8998_tdm_snd_hw_params,
+ .startup = msm8998_tdm_snd_startup,
+ .shutdown = msm8998_tdm_snd_shutdown
+};
+
static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream)
{
int ret = 0;
@@ -3985,6 +4324,9 @@
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int index = cpu_dai->id;
unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
dev_dbg(rtd->card->dev,
"%s: substream = %s stream = %d, dai name %s, dai ID %d\n",
@@ -3998,6 +4340,15 @@
__func__, cpu_dai->id);
goto done;
}
+ if (index == QUAT_MI2S) {
+ ret = msm_set_pinctrl(pinctrl_info, STATE_MI2S_ACTIVE);
+ if (ret) {
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+ goto done;
+ }
+ }
+
/*
* Muxtex protection in case the same MI2S
* interface using for both TX and RX so
@@ -4050,6 +4401,9 @@
int ret;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int index = rtd->cpu_dai->id;
+ struct snd_soc_card *card = rtd->card;
+ struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info;
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
@@ -4068,6 +4422,13 @@
}
}
mutex_unlock(&mi2s_intf_conf[index].lock);
+
+ if (index == QUAT_MI2S) {
+ ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE);
+ if (ret)
+ pr_err("%s: MI2S TLMM pinctrl set failed with %d\n",
+ __func__, ret);
+ }
}
static struct snd_soc_ops msm_mi2s_be_ops = {
@@ -4952,6 +5313,42 @@
},
};
+static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = {
+ {
+ .name = MSM_DAILINK_NAME(ASM Loopback),
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .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[] = {
/* Backend AFE DAI Links */
{
@@ -5159,8 +5556,8 @@
.no_pcm = 1,
.dpcm_playback = 1,
.id = MSM_BACKEND_DAI_QUAT_TDM_RX_0,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
- .ops = &msm_tdm_be_ops,
+ .be_hw_params_fixup = msm_tdm_be_hw_params_fixup,
+ .ops = &msm8998_tdm_be_ops,
.ignore_suspend = 1,
},
{
@@ -5334,6 +5731,22 @@
.ignore_pmdown_time = 1,
.ignore_suspend = 1,
},
+ /* Slimbus VI Recording */
+ {
+ .name = LPASS_BE_SLIMBUS_TX_VI,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tasha_codec",
+ .codec_dai_name = "tasha_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_suspend = 1,
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .ignore_pmdown_time = 1,
+ },
};
static struct snd_soc_dai_link msm_tavil_be_dai_links[] = {
@@ -5506,6 +5919,22 @@
.ignore_pmdown_time = 1,
.ignore_suspend = 1,
},
+ /* Slimbus VI Recording */
+ {
+ .name = LPASS_BE_SLIMBUS_TX_VI,
+ .stream_name = "Slimbus4 Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.16393",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "tavil_codec",
+ .codec_dai_name = "tavil_vifeedback",
+ .be_id = MSM_BACKEND_DAI_SLIMBUS_4_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .ops = &msm_be_ops,
+ .ignore_suspend = 1,
+ .no_pcm = 1,
+ .dpcm_capture = 1,
+ .ignore_pmdown_time = 1,
+ },
};
static struct snd_soc_dai_link msm_wcn_be_dai_links[] = {
@@ -5842,6 +6271,7 @@
static struct snd_soc_dai_link msm_tasha_dai_links[
ARRAY_SIZE(msm_common_dai_links) +
ARRAY_SIZE(msm_tasha_fe_dai_links) +
+ ARRAY_SIZE(msm_common_misc_fe_dai_links) +
ARRAY_SIZE(msm_common_be_dai_links) +
ARRAY_SIZE(msm_tasha_be_dai_links) +
ARRAY_SIZE(msm_wcn_be_dai_links) +
@@ -5852,6 +6282,7 @@
static struct snd_soc_dai_link msm_tavil_dai_links[
ARRAY_SIZE(msm_common_dai_links) +
ARRAY_SIZE(msm_tavil_fe_dai_links) +
+ ARRAY_SIZE(msm_common_misc_fe_dai_links) +
ARRAY_SIZE(msm_common_be_dai_links) +
ARRAY_SIZE(msm_tavil_be_dai_links) +
ARRAY_SIZE(msm_wcn_be_dai_links) +
@@ -6185,7 +6616,7 @@
{
struct snd_soc_card *card = NULL;
struct snd_soc_dai_link *dailink;
- int len_1, len_2, len_3;
+ int len_1, len_2, len_3, len_4;
int total_links;
const struct of_device_id *match;
@@ -6200,8 +6631,9 @@
card = &snd_soc_card_tasha_msm;
len_1 = ARRAY_SIZE(msm_common_dai_links);
len_2 = len_1 + ARRAY_SIZE(msm_tasha_fe_dai_links);
- len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
- total_links = len_3 + ARRAY_SIZE(msm_tasha_be_dai_links);
+ len_3 = len_2 + ARRAY_SIZE(msm_common_misc_fe_dai_links);
+ len_4 = len_3 + ARRAY_SIZE(msm_common_be_dai_links);
+ total_links = len_4 + ARRAY_SIZE(msm_tasha_be_dai_links);
memcpy(msm_tasha_dai_links,
msm_common_dai_links,
sizeof(msm_common_dai_links));
@@ -6209,9 +6641,12 @@
msm_tasha_fe_dai_links,
sizeof(msm_tasha_fe_dai_links));
memcpy(msm_tasha_dai_links + len_2,
+ msm_common_misc_fe_dai_links,
+ sizeof(msm_common_misc_fe_dai_links));
+ memcpy(msm_tasha_dai_links + len_3,
msm_common_be_dai_links,
sizeof(msm_common_be_dai_links));
- memcpy(msm_tasha_dai_links + len_3,
+ memcpy(msm_tasha_dai_links + len_4,
msm_tasha_be_dai_links,
sizeof(msm_tasha_be_dai_links));
@@ -6252,8 +6687,9 @@
card = &snd_soc_card_tavil_msm;
len_1 = ARRAY_SIZE(msm_common_dai_links);
len_2 = len_1 + ARRAY_SIZE(msm_tavil_fe_dai_links);
- len_3 = len_2 + ARRAY_SIZE(msm_common_be_dai_links);
- total_links = len_3 + ARRAY_SIZE(msm_tavil_be_dai_links);
+ len_3 = len_2 + ARRAY_SIZE(msm_common_misc_fe_dai_links);
+ len_4 = len_3 + ARRAY_SIZE(msm_common_be_dai_links);
+ total_links = len_4 + ARRAY_SIZE(msm_tavil_be_dai_links);
memcpy(msm_tavil_dai_links,
msm_common_dai_links,
sizeof(msm_common_dai_links));
@@ -6261,9 +6697,12 @@
msm_tavil_fe_dai_links,
sizeof(msm_tavil_fe_dai_links));
memcpy(msm_tavil_dai_links + len_2,
+ msm_common_misc_fe_dai_links,
+ sizeof(msm_common_misc_fe_dai_links));
+ memcpy(msm_tavil_dai_links + len_3,
msm_common_be_dai_links,
sizeof(msm_common_be_dai_links));
- memcpy(msm_tavil_dai_links + len_3,
+ memcpy(msm_tavil_dai_links + len_4,
msm_tavil_be_dai_links,
sizeof(msm_tavil_be_dai_links));
@@ -6751,14 +7190,19 @@
pdev->dev.of_node->full_name);
dev_dbg(&pdev->dev, "Jack type properties set to default");
} else {
- if (!strcmp(mbhc_audio_jack_type, "4-pole-jack"))
+ if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = false;
dev_dbg(&pdev->dev, "This hardware has 4 pole jack");
- else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack"))
+ } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = true;
dev_dbg(&pdev->dev, "This hardware has 5 pole jack");
- else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack"))
+ } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) {
+ wcd_mbhc_cfg.enable_anc_mic_detect = true;
dev_dbg(&pdev->dev, "This hardware has 6 pole jack");
- else
+ } else {
+ wcd_mbhc_cfg.enable_anc_mic_detect = false;
dev_dbg(&pdev->dev, "Unknown value, set to default");
+ }
}
/*
* Parse US-Euro gpio info from DT. Report no error if us-euro
@@ -6784,6 +7228,17 @@
dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n",
ret);
+ /* Parse pinctrl info from devicetree */
+ ret = msm_get_pinctrl(pdev);
+ if (!ret) {
+ pr_debug("%s: pinctrl parsing successful\n", __func__);
+ } else {
+ dev_dbg(&pdev->dev,
+ "%s: Parsing pinctrl failed with %d. Cannot use Ports\n",
+ __func__, ret);
+ ret = 0;
+ }
+
i2s_auxpcm_init(pdev);
is_initial_boot = true;
@@ -6801,6 +7256,7 @@
gpio_free(pdata->us_euro_gpio);
pdata->us_euro_gpio = 0;
}
+ msm_release_pinctrl(pdev);
devm_kfree(&pdev->dev, pdata);
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/Makefile b/sound/soc/msm/qdsp6v2/Makefile
index 469ab1a..d4db55f 100644
--- a/sound/soc/msm/qdsp6v2/Makefile
+++ b/sound/soc/msm/qdsp6v2/Makefile
@@ -10,7 +10,6 @@
msm-dai-stub-v2.o
obj-$(CONFIG_SND_HWDEP) += msm-pcm-routing-devdep.o
obj-$(CONFIG_DTS_EAGLE) += msm-dts-eagle.o
-obj-$(CONFIG_DOLBY_DAP) += msm-dolby-dap-config.o
obj-$(CONFIG_DOLBY_DS2) += msm-ds2-dap-config.o
obj-$(CONFIG_DOLBY_LICENSE) += msm-ds2-dap-config.o
obj-$(CONFIG_DTS_SRS_TM) += msm-dts-srs-tm-config.o
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..e8e4e04 100644
--- a/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
@@ -56,8 +56,8 @@
#define FLAC_BLK_SIZE_LIMIT 65535
/* Timestamp mode payload offsets */
-#define TS_LSW_OFFSET 6
-#define TS_MSW_OFFSET 7
+#define CAPTURE_META_DATA_TS_OFFSET_LSW 6
+#define CAPTURE_META_DATA_TS_OFFSET_MSW 7
/* decoder parameter length */
#define DDP_DEC_MAX_NUM_PARAM 18
@@ -100,7 +100,7 @@
static unsigned int supported_sample_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000,
- 88200, 96000, 176400, 192000, 352800, 384000, 2822400, 5644800
+ 88200, 96000, 128000, 176400, 192000, 352800, 384000, 2822400, 5644800
};
struct msm_compr_pdata {
@@ -160,6 +160,10 @@
uint32_t stream_available;
uint32_t next_stream;
+ uint32_t run_mode;
+ uint32_t start_delay_lsw;
+ uint32_t start_delay_msw;
+
uint64_t marker_timestamp;
struct msm_compr_gapless_state gapless_state;
@@ -215,6 +219,99 @@
struct msm_compr_dec_params *dec_params,
int stream_id);
+static int msm_compr_set_render_mode(struct msm_compr_audio *prtd,
+ uint32_t render_mode) {
+ int ret = -EINVAL;
+ struct audio_client *ac = prtd->audio_client;
+
+ pr_debug("%s, got render mode %u\n", __func__, render_mode);
+
+ if (render_mode == SNDRV_COMPRESS_RENDER_MODE_AUDIO_MASTER) {
+ render_mode = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT;
+ } else if (render_mode == SNDRV_COMPRESS_RENDER_MODE_STC_MASTER) {
+ render_mode = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC;
+ prtd->run_mode = ASM_SESSION_CMD_RUN_STARTIME_RUN_WITH_DELAY;
+ } else {
+ pr_err("%s, Invalid render mode %u\n", __func__,
+ render_mode);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = q6asm_send_mtmx_strtr_render_mode(ac, render_mode);
+ if (ret) {
+ pr_err("%s, Render mode can't be set error %d\n", __func__,
+ ret);
+ }
+exit:
+ return ret;
+}
+
+static int msm_compr_set_clk_rec_mode(struct audio_client *ac,
+ uint32_t clk_rec_mode) {
+ int ret = -EINVAL;
+
+ pr_debug("%s, got clk rec mode %u\n", __func__, clk_rec_mode);
+
+ if (clk_rec_mode == SNDRV_COMPRESS_CLK_REC_MODE_NONE) {
+ clk_rec_mode = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE;
+ } else if (clk_rec_mode == SNDRV_COMPRESS_CLK_REC_MODE_AUTO) {
+ clk_rec_mode = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO;
+ } else {
+ pr_err("%s, Invalid clk rec_mode mode %u\n", __func__,
+ clk_rec_mode);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = q6asm_send_mtmx_strtr_clk_rec_mode(ac, clk_rec_mode);
+ if (ret) {
+ pr_err("%s, clk rec mode can't be set, error %d\n", __func__,
+ ret);
+ }
+
+exit:
+ return ret;
+}
+
+static int msm_compr_set_render_window(struct audio_client *ac,
+ uint32_t ws_lsw, uint32_t ws_msw,
+ uint32_t we_lsw, uint32_t we_msw)
+{
+ int ret = -EINVAL;
+ struct asm_session_mtmx_strtr_param_window_v2_t asm_mtmx_strtr_window;
+ uint32_t param_id;
+
+ pr_debug("%s, ws_lsw 0x%x ws_msw 0x%x we_lsw 0x%x we_ms 0x%x\n",
+ __func__, ws_lsw, ws_msw, we_lsw, we_msw);
+
+ memset(&asm_mtmx_strtr_window, 0,
+ sizeof(struct asm_session_mtmx_strtr_param_window_v2_t));
+ asm_mtmx_strtr_window.window_lsw = ws_lsw;
+ asm_mtmx_strtr_window.window_msw = ws_msw;
+ param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_START_V2;
+ ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window,
+ param_id);
+ if (ret) {
+ pr_err("%s, start window can't be set error %d\n", __func__,
+ ret);
+ goto exit;
+ }
+
+ asm_mtmx_strtr_window.window_lsw = we_lsw;
+ asm_mtmx_strtr_window.window_msw = we_msw;
+ param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_WINDOW_END_V2;
+ ret = q6asm_send_mtmx_strtr_window(ac, &asm_mtmx_strtr_window,
+ param_id);
+ if (ret) {
+ pr_err("%s, end window can't be set error %d\n", __func__,
+ ret);
+ }
+
+exit:
+ return ret;
+}
+
static int msm_compr_set_volume(struct snd_compr_stream *cstream,
uint32_t volume_l, uint32_t volume_r)
{
@@ -314,6 +411,7 @@
int buffer_length;
uint64_t bytes_available;
struct audio_aio_write_param param;
+ struct snd_codec_metadata *buff_addr;
if (!atomic_read(&prtd->start)) {
pr_err("%s: stream is not in started state\n", __func__);
@@ -347,23 +445,34 @@
}
if (buffer_length) {
- param.paddr = prtd->buffer_paddr + prtd->byte_offset;
+ param.paddr = prtd->buffer_paddr + prtd->byte_offset;
WARN(prtd->byte_offset % 32 != 0, "offset %x not multiple of 32\n",
prtd->byte_offset);
} else {
- param.paddr = prtd->buffer_paddr;
+ param.paddr = prtd->buffer_paddr;
}
-
param.len = buffer_length;
- param.msw_ts = 0;
- param.lsw_ts = 0;
- param.flags = NO_TIMESTAMP;
+ if (prtd->ts_header_offset) {
+ buff_addr = (struct snd_codec_metadata *)
+ (prtd->buffer + prtd->byte_offset);
+ param.len = buff_addr->length;
+ param.msw_ts = (uint32_t)
+ ((buff_addr->timestamp & 0xFFFFFFFF00000000LL) >> 32);
+ param.lsw_ts = (uint32_t) (buff_addr->timestamp & 0xFFFFFFFFLL);
+ param.paddr += prtd->ts_header_offset;
+ param.flags = SET_TIMESTAMP;
+ param.metadata_len = prtd->ts_header_offset;
+ } else {
+ param.msw_ts = 0;
+ param.lsw_ts = 0;
+ param.flags = NO_TIMESTAMP;
+ param.metadata_len = 0;
+ }
param.uid = buffer_length;
- param.metadata_len = 0;
param.last_buffer = prtd->last_buffer;
pr_debug("%s: sending %d bytes to DSP byte_offset = %d\n",
- __func__, buffer_length, prtd->byte_offset);
+ __func__, param.len, prtd->byte_offset);
if (q6asm_async_write(prtd->audio_client, ¶m) < 0) {
pr_err("%s:q6asm_async_write failed\n", __func__);
} else {
@@ -482,9 +591,21 @@
* written to ADSP in the last write, update offset and
* total copied data accordingly.
*/
-
- prtd->byte_offset += token;
- prtd->copied_total += token;
+ if (prtd->ts_header_offset) {
+ /* Always assume that the data will be sent to DSP on
+ * frame boundary.
+ * i.e, one frame of userspace write will result in
+ * one kernel write to DSP. This is needed as
+ * timestamp will be sent per frame.
+ */
+ prtd->byte_offset +=
+ prtd->codec_param.buffer.fragment_size;
+ prtd->copied_total +=
+ prtd->codec_param.buffer.fragment_size;
+ } else {
+ prtd->byte_offset += token;
+ prtd->copied_total += token;
+ }
if (prtd->byte_offset >= prtd->buffer_size)
prtd->byte_offset -= prtd->buffer_size;
@@ -539,10 +660,10 @@
*buff_addr = prtd->ts_header_offset;
buff_addr++;
/* Write the TS LSW */
- *buff_addr = payload[TS_LSW_OFFSET];
+ *buff_addr = payload[CAPTURE_META_DATA_TS_OFFSET_LSW];
buff_addr++;
/* Write the TS MSW */
- *buff_addr = payload[TS_MSW_OFFSET];
+ *buff_addr = payload[CAPTURE_META_DATA_TS_OFFSET_MSW];
}
/* Always assume read_size is same as fragment_size */
read_size = prtd->codec_param.buffer.fragment_size;
@@ -760,7 +881,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 +896,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 +916,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 +992,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 +1151,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;
@@ -1206,6 +1350,12 @@
prtd->buffer_paddr = ac->port[dir].buf[0].phys;
prtd->buffer_size = runtime->fragments * runtime->fragment_size;
+ /* Bit-0 of flags represent timestamp mode */
+ if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG)
+ prtd->ts_header_offset = sizeof(struct snd_codec_metadata);
+ else
+ prtd->ts_header_offset = 0;
+
ret = msm_compr_send_media_format_block(cstream, ac->stream_id, false);
if (ret < 0)
pr_err("%s, failed to send media format block\n", __func__);
@@ -1247,8 +1397,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;
@@ -1563,6 +1718,7 @@
kfree(pdata->dec_params[soc_prtd->dai_link->id]);
pdata->dec_params[soc_prtd->dai_link->id] = NULL;
kfree(prtd);
+ runtime->private_data = NULL;
return 0;
}
@@ -1622,6 +1778,7 @@
q6asm_audio_client_free(ac);
kfree(prtd);
+ runtime->private_data = NULL;
return 0;
}
@@ -1791,6 +1948,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;
@@ -1935,7 +2098,8 @@
msm_compr_read_buffer(prtd);
}
/* issue RUN command for the stream */
- q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ q6asm_run_nowait(prtd->audio_client, prtd->run_mode,
+ prtd->start_delay_msw, prtd->start_delay_lsw);
break;
case SNDRV_PCM_TRIGGER_STOP:
spin_lock_irqsave(&prtd->lock, flags);
@@ -2019,7 +2183,8 @@
prtd->gapless_state.gapless_transition);
if (!prtd->gapless_state.gapless_transition) {
atomic_set(&prtd->start, 1);
- q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ q6asm_run_nowait(prtd->audio_client, prtd->run_mode,
+ 0, 0);
}
break;
case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
@@ -2664,6 +2829,7 @@
case SND_AUDIOCODEC_DTS:
break;
case SND_AUDIOCODEC_DSD:
+ case SND_AUDIOCODEC_APTX:
break;
default:
pr_err("%s: Unsupported audio codec %d\n",
@@ -2690,11 +2856,14 @@
return -EINVAL;
}
- if (prtd->compr_passthr != LEGACY_PCM) {
+ if (((metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) ||
+ (metadata->key == SNDRV_COMPRESS_ENCODER_DELAY)) &&
+ (prtd->compr_passthr != LEGACY_PCM)) {
pr_debug("%s: No trailing silence for compress_type[%d]\n",
__func__, prtd->compr_passthr);
return 0;
}
+
ac = prtd->audio_client;
if (metadata->key == SNDRV_COMPRESS_ENCODER_PADDING) {
pr_debug("%s, got encoder padding %u",
@@ -2704,11 +2873,63 @@
pr_debug("%s, got encoder delay %u",
__func__, metadata->value[0]);
prtd->gapless_state.initial_samples_drop = metadata->value[0];
+ } else if (metadata->key == SNDRV_COMPRESS_RENDER_MODE) {
+ return msm_compr_set_render_mode(prtd, metadata->value[0]);
+ } else if (metadata->key == SNDRV_COMPRESS_CLK_REC_MODE) {
+ return msm_compr_set_clk_rec_mode(ac, metadata->value[0]);
+ } else if (metadata->key == SNDRV_COMPRESS_RENDER_WINDOW) {
+ return msm_compr_set_render_window(
+ ac,
+ metadata->value[0],
+ metadata->value[1],
+ metadata->value[2],
+ metadata->value[3]);
+ } else if (metadata->key == SNDRV_COMPRESS_START_DELAY) {
+ prtd->start_delay_lsw = metadata->value[0];
+ prtd->start_delay_msw = metadata->value[1];
}
return 0;
}
+static int msm_compr_get_metadata(struct snd_compr_stream *cstream,
+ struct snd_compr_metadata *metadata)
+{
+ struct msm_compr_audio *prtd;
+ struct audio_client *ac;
+ int ret = -EINVAL;
+
+ pr_debug("%s\n", __func__);
+
+ if (!metadata || !cstream || !cstream->runtime)
+ return ret;
+
+ if (metadata->key != SNDRV_COMPRESS_PATH_DELAY) {
+ pr_err("%s, unsupported key %d\n", __func__, metadata->key);
+ return ret;
+ }
+
+ prtd = cstream->runtime->private_data;
+ if (!prtd || !prtd->audio_client) {
+ pr_err("%s: prtd or audio client is NULL\n", __func__);
+ return ret;
+ }
+
+ ac = prtd->audio_client;
+ ret = q6asm_get_path_delay(prtd->audio_client);
+ if (ret) {
+ pr_err("%s: get_path_delay failed, ret=%d\n", __func__, ret);
+ return ret;
+ }
+
+ pr_debug("%s, path delay(in us) %u\n", __func__, ac->path_delay);
+
+ metadata->value[0] = ac->path_delay;
+
+ return ret;
+}
+
+
static int msm_compr_set_next_track_param(struct snd_compr_stream *cstream,
union snd_codec_options *codec_options)
{
@@ -3078,6 +3299,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 +3366,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;
@@ -3194,48 +3417,45 @@
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_compr_playback_app_type_cfg_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &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);
@@ -3245,8 +3465,8 @@
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_RX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -3256,48 +3476,45 @@
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_compr_capture_app_type_cfg_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &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);
@@ -3307,8 +3524,8 @@
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,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -3860,6 +4077,7 @@
.pointer = msm_compr_pointer,
.set_params = msm_compr_set_params,
.set_metadata = msm_compr_set_metadata,
+ .get_metadata = msm_compr_get_metadata,
.set_next_track_param = msm_compr_set_next_track_param,
.ack = msm_compr_ack,
.copy = msm_compr_copy,
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
index dffac45..9b072ea 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-hdmi-v2.c
@@ -124,6 +124,45 @@
SOC_ENUM_SINGLE_EXT(2, hdmi_format),
};
+static int msm_dai_q6_ext_disp_drift_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(struct afe_param_id_dev_timing_stats);
+
+ return 0;
+}
+
+static int msm_dai_q6_ext_disp_drift_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = -EINVAL;
+ struct afe_param_id_dev_timing_stats timing_stats;
+ struct snd_soc_dai *dai = kcontrol->private_data;
+ struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+ pr_err("%s: afe port not started. status_mask = %ld\n",
+ __func__, *dai_data->status_mask);
+ goto done;
+ }
+
+ memset(&timing_stats, 0, sizeof(struct afe_param_id_dev_timing_stats));
+ ret = afe_get_av_dev_drift(&timing_stats, dai->id);
+ if (ret) {
+ pr_err("%s: Error getting AFE Drift for port %d, err=%d\n",
+ __func__, dai->id, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(ucontrol->value.bytes.data, (void *)&timing_stats,
+ sizeof(struct afe_param_id_dev_timing_stats));
+done:
+ return ret;
+}
+
static const struct snd_kcontrol_new hdmi_config_controls[] = {
SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
msm_dai_q6_ext_disp_format_get,
@@ -132,6 +171,13 @@
HDMI_RX_CA_MAX, 0, 1,
msm_dai_q6_ext_disp_ca_get,
msm_dai_q6_ext_disp_ca_put),
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "HDMI RX Drift",
+ .info = msm_dai_q6_ext_disp_drift_info,
+ .get = msm_dai_q6_ext_disp_drift_get,
+ },
};
static const struct snd_kcontrol_new display_port_config_controls[] = {
@@ -142,6 +188,13 @@
HDMI_RX_CA_MAX, 0, 1,
msm_dai_q6_ext_disp_ca_get,
msm_dai_q6_ext_disp_ca_put),
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = "DISPLAY Port RX Drift",
+ .info = msm_dai_q6_ext_disp_drift_info,
+ .get = msm_dai_q6_ext_disp_drift_get,
+ },
};
/* Current implementation assumes hw_param is called once
@@ -297,6 +350,10 @@
kcontrol = &hdmi_config_controls[1];
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(kcontrol, dai_data));
+
+ kcontrol = &hdmi_config_controls[2];
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai));
} else if (dai->driver->id == DISPLAY_PORT_RX) {
kcontrol = &display_port_config_controls[0];
rc = snd_ctl_add(dai->component->card->snd_card,
@@ -305,6 +362,10 @@
kcontrol = &display_port_config_controls[1];
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(kcontrol, dai_data));
+
+ kcontrol = &display_port_config_controls[2];
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(kcontrol, dai));
} else {
dev_err(dai->dev, "%s: Invalid id:%d\n",
__func__, dai->driver->id);
@@ -370,8 +431,10 @@
.playback = {
.stream_name = "HDMI Playback",
.aif_name = "HDMI",
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
- SNDRV_PCM_RATE_192000,
+ .rates = 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,
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
.channels_min = 2,
.channels_max = 8,
@@ -389,7 +452,9 @@
.playback = {
.stream_name = "Display Port Playback",
.aif_name = "DISPLAY_PORT",
- .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 |
+ .rates = 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,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE,
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index 52c2296..0c46763 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 {
@@ -212,6 +218,7 @@
u32 rate;
u32 channels;
u32 bitwidth;
+ u32 num_group_ports;
struct afe_clk_set clk_set; /* hold LPASS clock config. */
union afe_port_group_config group_cfg; /* hold tdm group config */
struct afe_tdm_port_config port_cfg; /* hold tdm config */
@@ -230,8 +237,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[] = {
@@ -247,6 +260,7 @@
static const char *const tdm_data_format[] = {
"LPCM",
"Compr",
+ "Gen Compr"
};
static const char *const tdm_header_type[] = {
@@ -256,8 +270,8 @@
};
static const struct soc_enum tdm_config_enum[] = {
- SOC_ENUM_SINGLE_EXT(2, tdm_data_format),
- SOC_ENUM_SINGLE_EXT(3, tdm_header_type),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_data_format), tdm_data_format),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tdm_header_type), tdm_header_type),
};
static DEFINE_MUTEX(tdm_mutex);
@@ -285,6 +299,8 @@
0xFF,
};
+static u32 num_tdm_group_ports;
+
static struct afe_clk_set tdm_clk_set = {
AFE_API_VERSION_CLOCK_SET,
Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT,
@@ -1882,6 +1898,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 +1935,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];
@@ -2046,6 +2072,42 @@
return 0;
}
+static int msm_dai_q6_usb_audio_endian_cfg_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+ u32 val = ucontrol->value.integer.value[0];
+
+ if (dai_data) {
+ dai_data->port_config.usb_audio.endian = val;
+ pr_debug("%s: endian = 0x%x\n", __func__,
+ dai_data->port_config.usb_audio.endian);
+ } else {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int msm_dai_q6_usb_audio_endian_cfg_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
+
+ if (dai_data) {
+ ucontrol->value.integer.value[0] =
+ dai_data->port_config.usb_audio.endian;
+ pr_debug("%s: endian = 0x%x\n", __func__,
+ dai_data->port_config.usb_audio.endian);
+ } else {
+ pr_err("%s: dai_data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int msm_dai_q6_afe_enc_cfg_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -2293,9 +2355,15 @@
SOC_SINGLE_EXT("USB_AUDIO_RX dev_token", 0, 0, UINT_MAX, 0,
msm_dai_q6_usb_audio_cfg_get,
msm_dai_q6_usb_audio_cfg_put),
+ SOC_SINGLE_EXT("USB_AUDIO_RX endian", 0, 0, 1, 0,
+ msm_dai_q6_usb_audio_endian_cfg_get,
+ msm_dai_q6_usb_audio_endian_cfg_put),
SOC_SINGLE_EXT("USB_AUDIO_TX dev_token", 0, 0, UINT_MAX, 0,
msm_dai_q6_usb_audio_cfg_get,
msm_dai_q6_usb_audio_cfg_put),
+ SOC_SINGLE_EXT("USB_AUDIO_TX endian", 0, 0, 1, 0,
+ msm_dai_q6_usb_audio_endian_cfg_get,
+ msm_dai_q6_usb_audio_endian_cfg_put),
};
static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
@@ -2360,10 +2428,16 @@
rc = snd_ctl_add(dai->component->card->snd_card,
snd_ctl_new1(&usb_audio_cfg_controls[0],
dai_data));
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&usb_audio_cfg_controls[1],
+ dai_data));
break;
case AFE_PORT_ID_USB_TX:
rc = snd_ctl_add(dai->component->card->snd_card,
- snd_ctl_new1(&usb_audio_cfg_controls[1],
+ snd_ctl_new1(&usb_audio_cfg_controls[2],
+ dai_data));
+ rc = snd_ctl_add(dai->component->card->snd_card,
+ snd_ctl_new1(&usb_audio_cfg_controls[3],
dai_data));
break;
}
@@ -3308,6 +3382,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 +3436,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 +3456,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 +3498,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 +3514,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 +3775,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 =
@@ -4812,7 +4937,6 @@
static int msm_dai_tdm_q6_probe(struct platform_device *pdev)
{
int rc = 0;
- u32 num_ports = 0;
const uint32_t *port_id_array = NULL;
uint32_t array_length = 0;
int i = 0;
@@ -4835,18 +4959,19 @@
rc = of_property_read_u32(pdev->dev.of_node,
"qcom,msm-cpudai-tdm-group-num-ports",
- &num_ports);
+ &num_tdm_group_ports);
if (rc) {
dev_err(&pdev->dev, "%s: Group Num Ports from DT file %s\n",
__func__, "qcom,msm-cpudai-tdm-group-num-ports");
goto rtn;
}
dev_dbg(&pdev->dev, "%s: Group Num Ports from DT file 0x%x\n",
- __func__, num_ports);
+ __func__, num_tdm_group_ports);
- if (num_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
+ if (num_tdm_group_ports > AFE_GROUP_DEVICE_NUM_PORTS) {
dev_err(&pdev->dev, "%s Group Num Ports %d greater than Max %d\n",
- __func__, num_ports, AFE_GROUP_DEVICE_NUM_PORTS);
+ __func__, num_tdm_group_ports,
+ AFE_GROUP_DEVICE_NUM_PORTS);
rc = -EINVAL;
goto rtn;
}
@@ -4860,18 +4985,19 @@
rc = -EINVAL;
goto rtn;
}
- if (array_length != sizeof(uint32_t) * num_ports) {
+ if (array_length != sizeof(uint32_t) * num_tdm_group_ports) {
dev_err(&pdev->dev, "%s array_length is %d, expected is %zd\n",
- __func__, array_length, sizeof(uint32_t) * num_ports);
+ __func__, array_length,
+ sizeof(uint32_t) * num_tdm_group_ports);
rc = -EINVAL;
goto rtn;
}
- for (i = 0; i < num_ports; i++)
+ for (i = 0; i < num_tdm_group_ports; i++)
tdm_group_cfg.port_id[i] =
(u16)be32_to_cpu(port_id_array[i]);
/* Unused index should be filled with 0 or AFE_PORT_INVALID */
- for (i = num_ports; i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
+ for (i = num_tdm_group_ports; i < AFE_GROUP_DEVICE_NUM_PORTS; i++)
tdm_group_cfg.port_id[i] =
AFE_PORT_INVALID;
@@ -4938,7 +5064,20 @@
struct msm_dai_q6_tdm_dai_data *dai_data = kcontrol->private_data;
int value = ucontrol->value.integer.value[0];
- dai_data->port_cfg.tdm.data_format = value;
+ switch (value) {
+ case 0:
+ dai_data->port_cfg.tdm.data_format = AFE_LINEAR_PCM_DATA;
+ break;
+ case 1:
+ dai_data->port_cfg.tdm.data_format = AFE_NON_LINEAR_DATA;
+ break;
+ case 2:
+ dai_data->port_cfg.tdm.data_format = AFE_GENERIC_COMPRESSED;
+ break;
+ default:
+ pr_err("%s: data_format invalid\n", __func__);
+ break;
+ }
pr_debug("%s: data_format = %d\n",
__func__, dai_data->port_cfg.tdm.data_format);
return 0;
@@ -5875,6 +6014,9 @@
/* HW only supports 16 and 8 slots configuration */
switch (slots) {
+ case 2:
+ cap_mask = 0x03;
+ break;
case 8:
cap_mask = 0xFF;
break;
@@ -6295,17 +6437,25 @@
__func__, dai->id);
goto rtn;
}
- rc = afe_port_group_enable(group_id,
- &dai_data->group_cfg, true);
- if (rc < 0) {
- dev_err(dai->dev, "%s: fail to enable AFE group 0x%x\n",
+
+ /*
+ * if only one port, don't do group enable as there
+ * is no group need for only one port
+ */
+ if (dai_data->num_group_ports > 1) {
+ rc = afe_port_group_enable(group_id,
+ &dai_data->group_cfg, true);
+ if (rc < 0) {
+ dev_err(dai->dev,
+ "%s: fail to enable AFE group 0x%x\n",
__func__, group_id);
- goto rtn;
+ goto rtn;
+ }
}
}
rc = afe_tdm_port_start(dai->id, &dai_data->port_cfg,
- dai_data->rate);
+ dai_data->rate, dai_data->num_group_ports);
if (rc < 0) {
if (atomic_read(group_ref) == 0) {
afe_port_group_enable(group_id,
@@ -6399,13 +6549,15 @@
.stream_name = "Primary TDM0 Playback",
.aif_name = "PRI_TDM_RX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX,
@@ -6417,13 +6569,15 @@
.stream_name = "Primary TDM1 Playback",
.aif_name = "PRI_TDM_RX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_1,
@@ -6435,13 +6589,15 @@
.stream_name = "Primary TDM2 Playback",
.aif_name = "PRI_TDM_RX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_2,
@@ -6453,13 +6609,15 @@
.stream_name = "Primary TDM3 Playback",
.aif_name = "PRI_TDM_RX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_3,
@@ -6471,13 +6629,15 @@
.stream_name = "Primary TDM4 Playback",
.aif_name = "PRI_TDM_RX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_4,
@@ -6489,13 +6649,15 @@
.stream_name = "Primary TDM5 Playback",
.aif_name = "PRI_TDM_RX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_5,
@@ -6507,13 +6669,15 @@
.stream_name = "Primary TDM6 Playback",
.aif_name = "PRI_TDM_RX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_6,
@@ -6525,13 +6689,15 @@
.stream_name = "Primary TDM7 Playback",
.aif_name = "PRI_TDM_RX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_RX_7,
@@ -6543,13 +6709,15 @@
.stream_name = "Primary TDM0 Capture",
.aif_name = "PRI_TDM_TX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX,
@@ -6561,13 +6729,15 @@
.stream_name = "Primary TDM1 Capture",
.aif_name = "PRI_TDM_TX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_1,
@@ -6579,13 +6749,15 @@
.stream_name = "Primary TDM2 Capture",
.aif_name = "PRI_TDM_TX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_2,
@@ -6597,13 +6769,15 @@
.stream_name = "Primary TDM3 Capture",
.aif_name = "PRI_TDM_TX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_3,
@@ -6615,13 +6789,15 @@
.stream_name = "Primary TDM4 Capture",
.aif_name = "PRI_TDM_TX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_4,
@@ -6633,13 +6809,15 @@
.stream_name = "Primary TDM5 Capture",
.aif_name = "PRI_TDM_TX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_5,
@@ -6651,13 +6829,15 @@
.stream_name = "Primary TDM6 Capture",
.aif_name = "PRI_TDM_TX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_6,
@@ -6669,13 +6849,15 @@
.stream_name = "Primary TDM7 Capture",
.aif_name = "PRI_TDM_TX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_PRIMARY_TDM_TX_7,
@@ -6687,13 +6869,15 @@
.stream_name = "Secondary TDM0 Playback",
.aif_name = "SEC_TDM_RX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX,
@@ -6705,13 +6889,15 @@
.stream_name = "Secondary TDM1 Playback",
.aif_name = "SEC_TDM_RX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_1,
@@ -6723,13 +6909,15 @@
.stream_name = "Secondary TDM2 Playback",
.aif_name = "SEC_TDM_RX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_2,
@@ -6741,13 +6929,15 @@
.stream_name = "Secondary TDM3 Playback",
.aif_name = "SEC_TDM_RX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_3,
@@ -6759,13 +6949,15 @@
.stream_name = "Secondary TDM4 Playback",
.aif_name = "SEC_TDM_RX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_4,
@@ -6777,13 +6969,15 @@
.stream_name = "Secondary TDM5 Playback",
.aif_name = "SEC_TDM_RX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_5,
@@ -6795,13 +6989,15 @@
.stream_name = "Secondary TDM6 Playback",
.aif_name = "SEC_TDM_RX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_6,
@@ -6813,13 +7009,15 @@
.stream_name = "Secondary TDM7 Playback",
.aif_name = "SEC_TDM_RX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_RX_7,
@@ -6831,13 +7029,15 @@
.stream_name = "Secondary TDM0 Capture",
.aif_name = "SEC_TDM_TX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX,
@@ -6849,13 +7049,15 @@
.stream_name = "Secondary TDM1 Capture",
.aif_name = "SEC_TDM_TX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_1,
@@ -6867,13 +7069,15 @@
.stream_name = "Secondary TDM2 Capture",
.aif_name = "SEC_TDM_TX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_2,
@@ -6885,13 +7089,15 @@
.stream_name = "Secondary TDM3 Capture",
.aif_name = "SEC_TDM_TX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_3,
@@ -6903,13 +7109,15 @@
.stream_name = "Secondary TDM4 Capture",
.aif_name = "SEC_TDM_TX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_4,
@@ -6921,13 +7129,15 @@
.stream_name = "Secondary TDM5 Capture",
.aif_name = "SEC_TDM_TX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_5,
@@ -6939,13 +7149,15 @@
.stream_name = "Secondary TDM6 Capture",
.aif_name = "SEC_TDM_TX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_6,
@@ -6957,13 +7169,15 @@
.stream_name = "Secondary TDM7 Capture",
.aif_name = "SEC_TDM_TX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_SECONDARY_TDM_TX_7,
@@ -6975,13 +7189,15 @@
.stream_name = "Tertiary TDM0 Playback",
.aif_name = "TERT_TDM_RX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX,
@@ -6993,13 +7209,15 @@
.stream_name = "Tertiary TDM1 Playback",
.aif_name = "TERT_TDM_RX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_1,
@@ -7011,13 +7229,15 @@
.stream_name = "Tertiary TDM2 Playback",
.aif_name = "TERT_TDM_RX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_2,
@@ -7029,13 +7249,15 @@
.stream_name = "Tertiary TDM3 Playback",
.aif_name = "TERT_TDM_RX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_3,
@@ -7047,13 +7269,15 @@
.stream_name = "Tertiary TDM4 Playback",
.aif_name = "TERT_TDM_RX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_4,
@@ -7065,13 +7289,15 @@
.stream_name = "Tertiary TDM5 Playback",
.aif_name = "TERT_TDM_RX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_5,
@@ -7083,13 +7309,15 @@
.stream_name = "Tertiary TDM6 Playback",
.aif_name = "TERT_TDM_RX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_6,
@@ -7101,13 +7329,15 @@
.stream_name = "Tertiary TDM7 Playback",
.aif_name = "TERT_TDM_RX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_RX_7,
@@ -7119,13 +7349,15 @@
.stream_name = "Tertiary TDM0 Capture",
.aif_name = "TERT_TDM_TX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX,
@@ -7137,13 +7369,15 @@
.stream_name = "Tertiary TDM1 Capture",
.aif_name = "TERT_TDM_TX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_1,
@@ -7155,13 +7389,15 @@
.stream_name = "Tertiary TDM2 Capture",
.aif_name = "TERT_TDM_TX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_2,
@@ -7173,13 +7409,15 @@
.stream_name = "Tertiary TDM3 Capture",
.aif_name = "TERT_TDM_TX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_3,
@@ -7191,13 +7429,15 @@
.stream_name = "Tertiary TDM4 Capture",
.aif_name = "TERT_TDM_TX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_4,
@@ -7209,13 +7449,15 @@
.stream_name = "Tertiary TDM5 Capture",
.aif_name = "TERT_TDM_TX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_5,
@@ -7227,13 +7469,15 @@
.stream_name = "Tertiary TDM6 Capture",
.aif_name = "TERT_TDM_TX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_6,
@@ -7245,13 +7489,15 @@
.stream_name = "Tertiary TDM7 Capture",
.aif_name = "TERT_TDM_TX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_TERTIARY_TDM_TX_7,
@@ -7263,13 +7509,15 @@
.stream_name = "Quaternary TDM0 Playback",
.aif_name = "QUAT_TDM_RX_0",
.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
- SNDRV_PCM_RATE_16000,
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX,
@@ -7281,13 +7529,15 @@
.stream_name = "Quaternary TDM1 Playback",
.aif_name = "QUAT_TDM_RX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_1,
@@ -7299,13 +7549,15 @@
.stream_name = "Quaternary TDM2 Playback",
.aif_name = "QUAT_TDM_RX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_2,
@@ -7317,13 +7569,15 @@
.stream_name = "Quaternary TDM3 Playback",
.aif_name = "QUAT_TDM_RX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_3,
@@ -7335,13 +7589,15 @@
.stream_name = "Quaternary TDM4 Playback",
.aif_name = "QUAT_TDM_RX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_4,
@@ -7353,13 +7609,15 @@
.stream_name = "Quaternary TDM5 Playback",
.aif_name = "QUAT_TDM_RX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_5,
@@ -7371,13 +7629,15 @@
.stream_name = "Quaternary TDM6 Playback",
.aif_name = "QUAT_TDM_RX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_6,
@@ -7389,13 +7649,15 @@
.stream_name = "Quaternary TDM7 Playback",
.aif_name = "QUAT_TDM_RX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_RX_7,
@@ -7407,13 +7669,15 @@
.stream_name = "Quaternary TDM0 Capture",
.aif_name = "QUAT_TDM_TX_0",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX,
@@ -7425,13 +7689,15 @@
.stream_name = "Quaternary TDM1 Capture",
.aif_name = "QUAT_TDM_TX_1",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_1,
@@ -7443,13 +7709,15 @@
.stream_name = "Quaternary TDM2 Capture",
.aif_name = "QUAT_TDM_TX_2",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_2,
@@ -7461,13 +7729,15 @@
.stream_name = "Quaternary TDM3 Capture",
.aif_name = "QUAT_TDM_TX_3",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_3,
@@ -7479,13 +7749,15 @@
.stream_name = "Quaternary TDM4 Capture",
.aif_name = "QUAT_TDM_TX_4",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_4,
@@ -7497,13 +7769,15 @@
.stream_name = "Quaternary TDM5 Capture",
.aif_name = "QUAT_TDM_TX_5",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_5,
@@ -7515,13 +7789,15 @@
.stream_name = "Quaternary TDM6 Capture",
.aif_name = "QUAT_TDM_TX_6",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_6,
@@ -7533,13 +7809,15 @@
.stream_name = "Quaternary TDM7 Capture",
.aif_name = "QUAT_TDM_TX_7",
.rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
- SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_352800,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE,
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
- .rate_max = 48000,
+ .rate_max = 352800,
},
.ops = &msm_dai_q6_tdm_ops,
.id = AFE_PORT_ID_QUATERNARY_TDM_TX_7,
@@ -7732,6 +8010,9 @@
dai_data->clk_set = tdm_clk_set;
/* copy static group cfg per parent node */
dai_data->group_cfg.tdm_cfg = tdm_group_cfg;
+ /* copy static num group ports per parent node */
+ dai_data->num_group_ports = num_tdm_group_ports;
+
dev_set_drvdata(&pdev->dev, dai_data);
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
deleted file mode 100644
index 29a1b3d..0000000
--- a/sound/soc/msm/qdsp6v2/msm-dolby-dap-config.c
+++ /dev/null
@@ -1,1071 +0,0 @@
-/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved.
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-#include <sound/control.h>
-#include <sound/q6adm-v2.h>
-#include <sound/q6core.h>
-
-#include "msm-dolby-dap-config.h"
-
-/* dolby endp based parameters */
-struct dolby_dap_endp_params_s {
- int device;
- int device_ch_caps;
- int dap_device;
- int params_id[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
- int params_len[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
- int params_offset[DOLBY_NUM_ENDP_DEPENDENT_PARAMS];
- int params_val[DOLBY_ENDDEP_PARAM_LENGTH];
-};
-
-const struct dolby_dap_endp_params_s
- dolby_dap_endp_params[NUM_DOLBY_ENDP_DEVICE] = {
- {EARPIECE, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {SPEAKER, 2, DOLBY_ENDP_INT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {WIRED_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {WIRED_HEADPHONE, 2, DOLBY_ENDP_HEADPHONES,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {BLUETOOTH_SCO, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {BLUETOOTH_SCO_HEADSET, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {BLUETOOTH_SCO_CARKIT, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {BLUETOOTH_A2DP, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {BLUETOOTH_A2DP_HEADPHONES, 2, DOLBY_ENDP_HEADPHONES,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {BLUETOOTH_A2DP_SPEAKER, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {AUX_DIGITAL, 2, DOLBY_ENDP_HDMI,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-496, -496, 0}
- },
- {AUX_DIGITAL, 6, DOLBY_ENDP_HDMI,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-496, -496, 0}
- },
- {AUX_DIGITAL, 8, DOLBY_ENDP_HDMI,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-496, -496, 0}
- },
- {ANLG_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {DGTL_DOCK_HEADSET, 2, DOLBY_ENDP_HEADPHONES,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {USB_ACCESSORY, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {USB_DEVICE, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {REMOTE_SUBMIX, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {PROXY, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {PROXY, 6, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {FM, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
- {FM_TX, 2, DOLBY_ENDP_EXT_SPEAKERS,
- {DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_VMB},
- {DOLBY_ENDDEP_PARAM_DVLO_LENGTH, DOLBY_ENDDEP_PARAM_DVLI_LENGTH,
- DOLBY_ENDDEP_PARAM_VMB_LENGTH},
- {DOLBY_ENDDEP_PARAM_DVLO_OFFSET, DOLBY_ENDDEP_PARAM_DVLI_OFFSET,
- DOLBY_ENDDEP_PARAM_VMB_OFFSET},
- {-320, -320, 144}
- },
-};
-
-/* dolby param ids to/from dsp */
-static uint32_t dolby_dap_params_id[ALL_DOLBY_PARAMS] = {
- DOLBY_PARAM_ID_VDHE, DOLBY_PARAM_ID_VSPE, DOLBY_PARAM_ID_DSSF,
- DOLBY_PARAM_ID_DVLI, DOLBY_PARAM_ID_DVLO, DOLBY_PARAM_ID_DVLE,
- DOLBY_PARAM_ID_DVMC, DOLBY_PARAM_ID_DVME, DOLBY_PARAM_ID_IENB,
- DOLBY_PARAM_ID_IEBF, DOLBY_PARAM_ID_IEON, DOLBY_PARAM_ID_DEON,
- DOLBY_PARAM_ID_NGON, DOLBY_PARAM_ID_GEON, DOLBY_PARAM_ID_GENB,
- DOLBY_PARAM_ID_GEBF, DOLBY_PARAM_ID_AONB, DOLBY_PARAM_ID_AOBF,
- DOLBY_PARAM_ID_AOBG, DOLBY_PARAM_ID_AOON, DOLBY_PARAM_ID_ARNB,
- DOLBY_PARAM_ID_ARBF, DOLBY_PARAM_ID_PLB, DOLBY_PARAM_ID_PLMD,
- DOLBY_PARAM_ID_DHSB, DOLBY_PARAM_ID_DHRG, DOLBY_PARAM_ID_DSSB,
- DOLBY_PARAM_ID_DSSA, DOLBY_PARAM_ID_DVLA, DOLBY_PARAM_ID_IEBT,
- DOLBY_PARAM_ID_IEA, DOLBY_PARAM_ID_DEA, DOLBY_PARAM_ID_DED,
- DOLBY_PARAM_ID_GEBG, DOLBY_PARAM_ID_AOCC, DOLBY_PARAM_ID_ARBI,
- DOLBY_PARAM_ID_ARBL, DOLBY_PARAM_ID_ARBH, DOLBY_PARAM_ID_AROD,
- DOLBY_PARAM_ID_ARTP, DOLBY_PARAM_ID_VMON, DOLBY_PARAM_ID_VMB,
- DOLBY_PARAM_ID_VCNB, DOLBY_PARAM_ID_VCBF, DOLBY_PARAM_ID_PREG,
- DOLBY_PARAM_ID_VEN, DOLBY_PARAM_ID_PSTG, DOLBY_COMMIT_ALL_TO_DSP,
- DOLBY_COMMIT_TO_DSP, DOLBY_USE_CACHE, DOLBY_AUTO_ENDP,
- DOLBY_AUTO_ENDDEP_PARAMS
-};
-
-/* modifed state: 0x00000000 - Not updated
- * > 0x00000000 && < 0x00010000
- * Updated and not committed to DSP
- * 0x00010001 - Updated and committed to DSP
- * > 0x00010001 - Modified the committed value
- */
-static int dolby_dap_params_modified[MAX_DOLBY_PARAMS] = { 0 };
-/* param offset */
-static uint32_t dolby_dap_params_offset[MAX_DOLBY_PARAMS] = {
- DOLBY_PARAM_VDHE_OFFSET, DOLBY_PARAM_VSPE_OFFSET,
- DOLBY_PARAM_DSSF_OFFSET, DOLBY_PARAM_DVLI_OFFSET,
- DOLBY_PARAM_DVLO_OFFSET, DOLBY_PARAM_DVLE_OFFSET,
- DOLBY_PARAM_DVMC_OFFSET, DOLBY_PARAM_DVME_OFFSET,
- DOLBY_PARAM_IENB_OFFSET, DOLBY_PARAM_IEBF_OFFSET,
- DOLBY_PARAM_IEON_OFFSET, DOLBY_PARAM_DEON_OFFSET,
- DOLBY_PARAM_NGON_OFFSET, DOLBY_PARAM_GEON_OFFSET,
- DOLBY_PARAM_GENB_OFFSET, DOLBY_PARAM_GEBF_OFFSET,
- DOLBY_PARAM_AONB_OFFSET, DOLBY_PARAM_AOBF_OFFSET,
- DOLBY_PARAM_AOBG_OFFSET, DOLBY_PARAM_AOON_OFFSET,
- DOLBY_PARAM_ARNB_OFFSET, DOLBY_PARAM_ARBF_OFFSET,
- DOLBY_PARAM_PLB_OFFSET, DOLBY_PARAM_PLMD_OFFSET,
- DOLBY_PARAM_DHSB_OFFSET, DOLBY_PARAM_DHRG_OFFSET,
- DOLBY_PARAM_DSSB_OFFSET, DOLBY_PARAM_DSSA_OFFSET,
- DOLBY_PARAM_DVLA_OFFSET, DOLBY_PARAM_IEBT_OFFSET,
- DOLBY_PARAM_IEA_OFFSET, DOLBY_PARAM_DEA_OFFSET,
- DOLBY_PARAM_DED_OFFSET, DOLBY_PARAM_GEBG_OFFSET,
- DOLBY_PARAM_AOCC_OFFSET, DOLBY_PARAM_ARBI_OFFSET,
- DOLBY_PARAM_ARBL_OFFSET, DOLBY_PARAM_ARBH_OFFSET,
- DOLBY_PARAM_AROD_OFFSET, DOLBY_PARAM_ARTP_OFFSET,
- DOLBY_PARAM_VMON_OFFSET, DOLBY_PARAM_VMB_OFFSET,
- DOLBY_PARAM_VCNB_OFFSET, DOLBY_PARAM_VCBF_OFFSET,
- DOLBY_PARAM_PREG_OFFSET, DOLBY_PARAM_VEN_OFFSET,
- DOLBY_PARAM_PSTG_OFFSET
-};
-/* param_length */
-static uint32_t dolby_dap_params_length[MAX_DOLBY_PARAMS] = {
- DOLBY_PARAM_VDHE_LENGTH, DOLBY_PARAM_VSPE_LENGTH,
- DOLBY_PARAM_DSSF_LENGTH, DOLBY_PARAM_DVLI_LENGTH,
- DOLBY_PARAM_DVLO_LENGTH, DOLBY_PARAM_DVLE_LENGTH,
- DOLBY_PARAM_DVMC_LENGTH, DOLBY_PARAM_DVME_LENGTH,
- DOLBY_PARAM_IENB_LENGTH, DOLBY_PARAM_IEBF_LENGTH,
- DOLBY_PARAM_IEON_LENGTH, DOLBY_PARAM_DEON_LENGTH,
- DOLBY_PARAM_NGON_LENGTH, DOLBY_PARAM_GEON_LENGTH,
- DOLBY_PARAM_GENB_LENGTH, DOLBY_PARAM_GEBF_LENGTH,
- DOLBY_PARAM_AONB_LENGTH, DOLBY_PARAM_AOBF_LENGTH,
- DOLBY_PARAM_AOBG_LENGTH, DOLBY_PARAM_AOON_LENGTH,
- DOLBY_PARAM_ARNB_LENGTH, DOLBY_PARAM_ARBF_LENGTH,
- DOLBY_PARAM_PLB_LENGTH, DOLBY_PARAM_PLMD_LENGTH,
- DOLBY_PARAM_DHSB_LENGTH, DOLBY_PARAM_DHRG_LENGTH,
- DOLBY_PARAM_DSSB_LENGTH, DOLBY_PARAM_DSSA_LENGTH,
- DOLBY_PARAM_DVLA_LENGTH, DOLBY_PARAM_IEBT_LENGTH,
- DOLBY_PARAM_IEA_LENGTH, DOLBY_PARAM_DEA_LENGTH,
- DOLBY_PARAM_DED_LENGTH, DOLBY_PARAM_GEBG_LENGTH,
- DOLBY_PARAM_AOCC_LENGTH, DOLBY_PARAM_ARBI_LENGTH,
- DOLBY_PARAM_ARBL_LENGTH, DOLBY_PARAM_ARBH_LENGTH,
- DOLBY_PARAM_AROD_LENGTH, DOLBY_PARAM_ARTP_LENGTH,
- DOLBY_PARAM_VMON_LENGTH, DOLBY_PARAM_VMB_LENGTH,
- DOLBY_PARAM_VCNB_LENGTH, DOLBY_PARAM_VCBF_LENGTH,
- DOLBY_PARAM_PREG_LENGTH, DOLBY_PARAM_VEN_LENGTH,
- DOLBY_PARAM_PSTG_LENGTH
-};
-
-/* param_value */
-static uint32_t dolby_dap_params_value[TOTAL_LENGTH_DOLBY_PARAM] = {0};
-
-struct dolby_dap_params_get_s {
- int32_t port_id;
- uint32_t device_id;
- uint32_t param_id;
- uint32_t offset;
- uint32_t length;
-};
-
-struct dolby_dap_params_states_s {
- bool use_cache;
- bool auto_endp;
- bool enddep_params;
- int port_id[AFE_MAX_PORTS];
- int copp_idx[AFE_MAX_PORTS];
- int port_open_count;
- int port_ids_dolby_can_be_enabled;
- int device;
-};
-
-static struct dolby_dap_params_get_s dolby_dap_params_get = {-1, DEVICE_OUT_ALL,
- 0, 0, 0};
-static struct dolby_dap_params_states_s dolby_dap_params_states = { true, true,
- true, {DOLBY_INVALID_PORT_ID},
- {-1}, 0, DEVICE_OUT_ALL, 0 };
-/*
- * port_ids_dolby_can_be_enabled is set to 0x7FFFFFFF.
- * this needs to be removed after interface validation
- */
-
-static int msm_dolby_dap_map_device_to_dolby_endpoint(int device)
-{
- int i, dolby_dap_device = DOLBY_ENDP_EXT_SPEAKERS;
-
- for (i = 0; i < NUM_DOLBY_ENDP_DEVICE; i++) {
- if (dolby_dap_endp_params[i].device == device) {
- dolby_dap_device = dolby_dap_endp_params[i].dap_device;
- break;
- }
- }
- /* default the endpoint to speaker if corresponding device entry */
- /* not found */
- if (i >= NUM_DOLBY_ENDP_DEVICE)
- dolby_dap_params_states.device = SPEAKER;
- return dolby_dap_device;
-}
-
-static int msm_dolby_dap_send_end_point(int port_id, int copp_idx)
-{
- int rc = 0;
- char *params_value;
- int *update_params_value;
- uint32_t params_length = (DOLBY_PARAM_INT_ENDP_LENGTH +
- DOLBY_PARAM_PAYLOAD_SIZE) * sizeof(uint32_t);
-
- pr_debug("%s\n", __func__);
- params_value = kzalloc(params_length, GFP_KERNEL);
- if (!params_value) {
- pr_err("%s, params memory alloc failed", __func__);
- return -ENOMEM;
- }
- update_params_value = (int *)params_value;
- *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
- *update_params_value++ = DOLBY_PARAM_ID_INIT_ENDP;
- *update_params_value++ = DOLBY_PARAM_INT_ENDP_LENGTH * sizeof(uint32_t);
- *update_params_value++ =
- msm_dolby_dap_map_device_to_dolby_endpoint(
- dolby_dap_params_states.device);
- rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
- params_length);
- if (rc) {
- pr_err("%s: send dolby params failed\n", __func__);
- rc = -EINVAL;
- }
- kfree(params_value);
- return rc;
-}
-
-static int msm_dolby_dap_send_enddep_params(int port_id, int copp_idx,
- int device_channels)
-{
- int i, j, rc = 0, idx, offset;
- char *params_value;
- int *update_params_value;
- uint32_t params_length = (DOLBY_ENDDEP_PARAM_LENGTH +
- DOLBY_NUM_ENDP_DEPENDENT_PARAMS *
- DOLBY_PARAM_PAYLOAD_SIZE) *
- sizeof(uint32_t);
-
- pr_debug("%s\n", __func__);
- params_value = kzalloc(params_length, GFP_KERNEL);
- if (!params_value) {
- pr_err("%s, params memory alloc failed", __func__);
- return -ENOMEM;
- }
- update_params_value = (int *)params_value;
- for (idx = 0; idx < NUM_DOLBY_ENDP_DEVICE; idx++) {
- if (dolby_dap_endp_params[idx].device ==
- dolby_dap_params_states.device) {
- if (dolby_dap_params_states.device == AUX_DIGITAL ||
- dolby_dap_params_states.device == PROXY) {
- if (dolby_dap_endp_params[idx].device_ch_caps ==
- device_channels)
- break;
- } else {
- break;
- }
- }
- }
- if (idx >= NUM_DOLBY_ENDP_DEVICE) {
- pr_err("%s: device is not set accordingly\n", __func__);
- kfree(params_value);
- return -EINVAL;
- }
- for (i = 0; i < DOLBY_ENDDEP_PARAM_LENGTH; i++) {
- *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
- *update_params_value++ =
- dolby_dap_endp_params[idx].params_id[i];
- *update_params_value++ =
- dolby_dap_endp_params[idx].params_len[i] *
- sizeof(uint32_t);
- offset = dolby_dap_endp_params[idx].params_offset[i];
- for (j = 0; j < dolby_dap_endp_params[idx].params_len[i]; j++)
- *update_params_value++ =
- dolby_dap_endp_params[idx].params_val[offset+j];
- }
- rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
- params_length);
- if (rc) {
- pr_err("%s: send dolby params failed\n", __func__);
- rc = -EINVAL;
- }
- kfree(params_value);
- return rc;
-}
-
-static int msm_dolby_dap_send_cached_params(int port_id, int copp_idx,
- int commit)
-{
- char *params_value;
- int *update_params_value, rc = 0;
- uint32_t index_offset, i, j;
- uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
- MAX_DOLBY_PARAMS * DOLBY_PARAM_PAYLOAD_SIZE) *
- sizeof(uint32_t);
-
- params_value = kzalloc(params_length, GFP_KERNEL);
- if (!params_value)
- return -ENOMEM;
-
- update_params_value = (int *)params_value;
- params_length = 0;
- for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
- if ((dolby_dap_params_modified[i] == 0) ||
- ((commit) &&
- ((dolby_dap_params_modified[i] & 0x00010000) &&
- ((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1))))
- continue;
- *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
- *update_params_value++ = dolby_dap_params_id[i];
- *update_params_value++ = dolby_dap_params_length[i] *
- sizeof(uint32_t);
- index_offset = dolby_dap_params_offset[i];
- for (j = 0; j < dolby_dap_params_length[i]; j++) {
- *update_params_value++ =
- dolby_dap_params_value[index_offset+j];
- }
- params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
- dolby_dap_params_length[i]) * sizeof(uint32_t);
- }
- pr_debug("%s, valid param length: %d", __func__, params_length);
- if (params_length) {
- rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
- params_length);
- if (rc) {
- pr_err("%s: send dolby params failed\n", __func__);
- kfree(params_value);
- return -EINVAL;
- }
- for (i = 0; i < MAX_DOLBY_PARAMS; i++) {
- if ((dolby_dap_params_modified[i] == 0) ||
- ((commit) &&
- ((dolby_dap_params_modified[i] & 0x00010000) &&
- ((dolby_dap_params_modified[i] & 0x0000FFFF) <= 1))
- ))
- continue;
- dolby_dap_params_modified[i] = 0x00010001;
- }
- }
- kfree(params_value);
- return 0;
-}
-
-int msm_dolby_dap_init(int port_id, int copp_idx, int channels,
- bool is_custom_stereo_on)
-{
- int ret = 0;
- int index = adm_validate_and_get_port_index(port_id);
-
- if (index < 0) {
- pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
- port_id);
- return -EINVAL;
- }
- if ((port_id != DOLBY_INVALID_PORT_ID) &&
- (port_id & dolby_dap_params_states.port_ids_dolby_can_be_enabled)) {
- dolby_dap_params_states.port_id[index] = port_id;
- dolby_dap_params_states.copp_idx[index] = copp_idx;
- dolby_dap_params_states.port_open_count++;
- if (dolby_dap_params_states.auto_endp) {
- ret = msm_dolby_dap_send_end_point(port_id, copp_idx);
- if (ret) {
- pr_err("%s: err sending endppoint\n", __func__);
- return ret;
- }
- }
- if (dolby_dap_params_states.use_cache) {
- ret = msm_dolby_dap_send_cached_params(port_id,
- copp_idx, 0);
- if (ret) {
- pr_err("%s: err sending cached params\n",
- __func__);
- return ret;
- }
- }
- if (dolby_dap_params_states.enddep_params) {
- msm_dolby_dap_send_enddep_params(port_id, copp_idx,
- channels);
- if (ret) {
- pr_err("%s: err sending endp dependent params\n",
- __func__);
- return ret;
- }
- }
- if (is_custom_stereo_on)
- dolby_dap_set_custom_stereo_onoff(port_id, copp_idx,
- is_custom_stereo_on);
- }
- return ret;
-}
-
-void msm_dolby_dap_deinit(int port_id)
-{
- int index = adm_validate_and_get_port_index(port_id);
-
- if (index < 0) {
- pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
- port_id);
- return;
- }
- dolby_dap_params_states.port_open_count--;
- if ((dolby_dap_params_states.port_id[index] == port_id) &&
- (!dolby_dap_params_states.port_open_count)) {
- dolby_dap_params_states.port_id[index] = DOLBY_INVALID_PORT_ID;
- dolby_dap_params_states.copp_idx[index] = -1;
- }
-}
-
-static int msm_dolby_dap_set_vspe_vdhe(int port_id, int copp_idx,
- bool is_custom_stereo_enabled)
-{
- char *params_value;
- int *update_params_value, rc = 0;
- uint32_t index_offset, i, j;
- uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
- 2 * DOLBY_PARAM_PAYLOAD_SIZE) *
- sizeof(uint32_t);
- if (port_id == DOLBY_INVALID_PORT_ID) {
- pr_err("%s: Not a Dolby topology. Do not set custom stereo mixing\n",
- __func__);
- return -EINVAL;
- }
- params_value = kzalloc(params_length, GFP_KERNEL);
- if (!params_value)
- return -ENOMEM;
-
- update_params_value = (int *)params_value;
- params_length = 0;
- /* for VDHE and VSPE DAP params at index 0 and 1 in table */
- for (i = 0; i < 2; i++) {
- *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
- *update_params_value++ = dolby_dap_params_id[i];
- *update_params_value++ = dolby_dap_params_length[i] *
- sizeof(uint32_t);
- index_offset = dolby_dap_params_offset[i];
- for (j = 0; j < dolby_dap_params_length[i]; j++) {
- if (is_custom_stereo_enabled)
- *update_params_value++ = 0;
- else
- *update_params_value++ =
- dolby_dap_params_value[index_offset+j];
- }
- params_length += (DOLBY_PARAM_PAYLOAD_SIZE +
- dolby_dap_params_length[i]) * sizeof(uint32_t);
- }
- pr_debug("%s, valid param length: %d", __func__, params_length);
- if (params_length) {
- rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
- params_length);
- if (rc) {
- pr_err("%s: send vdhe/vspe params failed with rc=%d\n",
- __func__, rc);
- kfree(params_value);
- return -EINVAL;
- }
- }
- kfree(params_value);
- return 0;
-}
-
-int dolby_dap_set_custom_stereo_onoff(int port_id, int copp_idx,
- bool is_custom_stereo_enabled)
-{
- char *params_value;
- int *update_params_value, rc = 0;
- uint32_t params_length = (TOTAL_LENGTH_DOLBY_PARAM +
- DOLBY_PARAM_PAYLOAD_SIZE) *
- sizeof(uint32_t);
- if (port_id == DOLBY_INVALID_PORT_ID)
- return -EINVAL;
-
- msm_dolby_dap_set_vspe_vdhe(port_id, copp_idx,
- is_custom_stereo_enabled);
- params_value = kzalloc(params_length, GFP_KERNEL);
- if (!params_value) {
- pr_err("%s, params memory alloc failed\n", __func__);
- return -ENOMEM;
- }
- update_params_value = (int *)params_value;
- params_length = 0;
- *update_params_value++ = DOLBY_BUNDLE_MODULE_ID;
- *update_params_value++ = DOLBY_ENABLE_CUSTOM_STEREO;
- *update_params_value++ = sizeof(uint32_t);
- if (is_custom_stereo_enabled)
- *update_params_value++ = 1;
- else
- *update_params_value++ = 0;
- params_length += (DOLBY_PARAM_PAYLOAD_SIZE + 1) * sizeof(uint32_t);
- pr_debug("%s, valid param length: %d", __func__, params_length);
- if (params_length) {
- rc = adm_dolby_dap_send_params(port_id, copp_idx, params_value,
- params_length);
- if (rc) {
- pr_err("%s: setting ds1 custom stereo param failed with rc=%d\n",
- __func__, rc);
- kfree(params_value);
- return -EINVAL;
- }
- }
- kfree(params_value);
- return 0;
-}
-
-static int msm_dolby_dap_map_device_to_port_id(int device)
-{
- int port_id = SLIMBUS_0_RX;
-
- device = DEVICE_OUT_ALL;
- /*update the device when single stream to multiple device is handled*/
- if (device == DEVICE_OUT_ALL) {
- port_id = PRIMARY_I2S_RX | SLIMBUS_0_RX | HDMI_RX |
- INT_BT_SCO_RX | INT_FM_RX |
- RT_PROXY_PORT_001_RX |
- AFE_PORT_ID_PRIMARY_PCM_RX |
- MI2S_RX | SECONDARY_I2S_RX |
- SLIMBUS_1_RX | SLIMBUS_4_RX | SLIMBUS_3_RX |
- AFE_PORT_ID_SECONDARY_MI2S_RX;
- } else {
- /* update port_id based on the device */
- }
- return port_id;
-}
-
-int msm_dolby_dap_param_to_set_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* not used while setting the parameters */
- return 0;
-}
-
-int msm_dolby_dap_param_to_set_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int rc = 0, port_id, copp_idx;
- uint32_t idx, j;
- uint32_t device = ucontrol->value.integer.value[0];
- uint32_t param_id = ucontrol->value.integer.value[1];
- uint32_t offset = ucontrol->value.integer.value[2];
- uint32_t length = ucontrol->value.integer.value[3];
-
- dolby_dap_params_states.port_ids_dolby_can_be_enabled =
- msm_dolby_dap_map_device_to_port_id(device);
- for (idx = 0; idx < ALL_DOLBY_PARAMS; idx++) {
- /*paramid from user space*/
- if (param_id == dolby_dap_params_id[idx])
- break;
- }
- if (idx > ALL_DOLBY_PARAMS-1) {
- pr_err("%s: invalid param id 0x%x to set\n", __func__,
- param_id);
- return -EINVAL;
- }
- switch (idx) {
- case DOLBY_COMMIT_ALL_IDX: {
- /* COMIIT ALL: Send all parameters to DSP */
- pr_debug("%s: COMMIT_ALL recvd\n", __func__);
- for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
- port_id = dolby_dap_params_states.port_id[idx];
- copp_idx =
- dolby_dap_params_states.copp_idx[idx];
- if ((copp_idx > 0) &&
- (copp_idx < MAX_COPPS_PER_PORT) &&
- (port_id != DOLBY_INVALID_PORT_ID))
- rc |= msm_dolby_dap_send_cached_params(
- port_id,
- copp_idx,
- 0);
- }
- }
- break;
- case DOLBY_COMMIT_IDX: {
- pr_debug("%s: COMMIT recvd\n", __func__);
- /* COMMIT: Send only modified parameters to DSP */
- for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
- port_id = dolby_dap_params_states.port_id[idx];
- copp_idx =
- dolby_dap_params_states.copp_idx[idx];
- if ((copp_idx > 0) &&
- (copp_idx < MAX_COPPS_PER_PORT) &&
- (port_id == DOLBY_INVALID_PORT_ID))
- rc |= msm_dolby_dap_send_cached_params(
- port_id,
- copp_idx,
- 1);
- }
- }
- break;
- case DOLBY_USE_CACHE_IDX: {
- pr_debug("%s: USE CACHE recvd val: %ld\n", __func__,
- ucontrol->value.integer.value[4]);
- dolby_dap_params_states.use_cache =
- ucontrol->value.integer.value[4];
- }
- break;
- case DOLBY_AUTO_ENDP_IDX: {
- pr_debug("%s: AUTO_ENDP recvd val: %ld\n", __func__,
- ucontrol->value.integer.value[4]);
- dolby_dap_params_states.auto_endp =
- ucontrol->value.integer.value[4];
- }
- break;
- case DOLBY_AUTO_ENDDEP_IDX: {
- pr_debug("%s: USE_ENDDEP_PARAMS recvd val: %ld\n",
- __func__, ucontrol->value.integer.value[4]);
- dolby_dap_params_states.enddep_params =
- ucontrol->value.integer.value[4];
- }
- break;
- default: {
- /* cache the parameters */
- dolby_dap_params_modified[idx] += 1;
- dolby_dap_params_length[idx] = length;
- pr_debug("%s: param recvd deviceId=0x%x paramId=0x%x offset=%d length=%d\n",
- __func__, device, param_id, offset, length);
- for (j = 0; j < length; j++) {
- dolby_dap_params_value[
- dolby_dap_params_offset[idx] +
- offset + j]
- = ucontrol->value.integer.value[4+j];
- pr_debug("value[%d]: %ld\n", j,
- ucontrol->value.integer.value[4+j]);
- }
- }
- }
-
- return rc;
-}
-
-int msm_dolby_dap_param_to_get_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int rc = 0, i, index;
- char *params_value;
- int *update_params_value;
- uint32_t params_length = DOLBY_MAX_LENGTH_INDIVIDUAL_PARAM *
- sizeof(uint32_t);
- uint32_t param_payload_len =
- DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
- int port_id = dolby_dap_params_get.port_id, copp_idx;
-
- if (port_id == DOLBY_INVALID_PORT_ID) {
- pr_err("%s, port_id not set, do not query ADM\n", __func__);
- return -EINVAL;
- }
- index = adm_validate_and_get_port_index(port_id);
- if (index < 0) {
- pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
- port_id);
- return -EINVAL;
- }
- copp_idx = dolby_dap_params_states.copp_idx[index];
- if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) {
- pr_debug("%s: get params called before copp open.copp_idx:%d\n",
- __func__, copp_idx);
- return -EINVAL;
- }
- params_value = kzalloc(params_length, GFP_KERNEL);
- if (!params_value)
- return -ENOMEM;
-
- if (dolby_dap_params_get.param_id == DOLBY_PARAM_ID_VER) {
- rc = adm_get_params(port_id, copp_idx,
- DOLBY_BUNDLE_MODULE_ID, DOLBY_PARAM_ID_VER,
- params_length + param_payload_len,
- params_value);
- } else {
- for (i = 0; i < MAX_DOLBY_PARAMS; i++)
- if (dolby_dap_params_id[i] ==
- dolby_dap_params_get.param_id)
- break;
- if (i > MAX_DOLBY_PARAMS-1) {
- pr_err("%s: invalid param id to set", __func__);
- rc = -EINVAL;
- } else {
- params_length = (dolby_dap_params_length[i] +
- DOLBY_PARAM_PAYLOAD_SIZE) *
- sizeof(uint32_t);
- rc = adm_get_params(port_id, copp_idx,
- DOLBY_BUNDLE_MODULE_ID,
- dolby_dap_params_id[i],
- params_length + param_payload_len,
- params_value);
- }
- }
- if (rc) {
- pr_err("%s: get parameters failed rc:%d\n", __func__, rc);
- kfree(params_value);
- return -EINVAL;
- }
- update_params_value = (int *)params_value;
- ucontrol->value.integer.value[0] = dolby_dap_params_get.device_id;
- ucontrol->value.integer.value[1] = dolby_dap_params_get.param_id;
- ucontrol->value.integer.value[2] = dolby_dap_params_get.offset;
- ucontrol->value.integer.value[3] = dolby_dap_params_get.length;
-
- pr_debug("%s: FROM DSP value[0] 0x%x value[1] %d value[2] 0x%x\n",
- __func__, update_params_value[0],
- update_params_value[1], update_params_value[2]);
- for (i = 0; i < dolby_dap_params_get.length; i++) {
- ucontrol->value.integer.value[DOLBY_PARAM_PAYLOAD_SIZE+i] =
- update_params_value[i];
- pr_debug("value[%d]:%d\n", i, update_params_value[i]);
- }
- pr_debug("%s: Returning param_id=0x%x offset=%d length=%d\n",
- __func__, dolby_dap_params_get.param_id,
- dolby_dap_params_get.offset,
- dolby_dap_params_get.length);
- kfree(params_value);
- return 0;
-}
-
-int msm_dolby_dap_param_to_get_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int port_id, idx, copp_idx;
-
- dolby_dap_params_get.device_id = ucontrol->value.integer.value[0];
- port_id = msm_dolby_dap_map_device_to_port_id(
- dolby_dap_params_get.device_id);
- for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
- port_id = dolby_dap_params_states.port_id[idx];
- copp_idx = dolby_dap_params_states.copp_idx[idx];
- if ((copp_idx < 0) ||
- (copp_idx >= MAX_COPPS_PER_PORT) ||
- (port_id == DOLBY_INVALID_PORT_ID))
- continue;
- else
- break;
- }
- if (idx == AFE_MAX_PORTS)
- port_id = SLIMBUS_0_RX;
- dolby_dap_params_get.port_id = port_id;
- dolby_dap_params_get.param_id = ucontrol->value.integer.value[1];
- dolby_dap_params_get.offset = ucontrol->value.integer.value[2];
- dolby_dap_params_get.length = ucontrol->value.integer.value[3];
- pr_debug("%s: param_id=0x%x offset=%d length=%d\n", __func__,
- dolby_dap_params_get.param_id, dolby_dap_params_get.offset,
- dolby_dap_params_get.length);
- return 0;
-}
-
-int msm_dolby_dap_param_visualizer_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- uint32_t length = dolby_dap_params_value[DOLBY_PARAM_VCNB_OFFSET];
- char *visualizer_data;
- int i, rc;
- int *update_visualizer_data;
- uint32_t offset, params_length =
- (2*length + DOLBY_VIS_PARAM_HEADER_SIZE)*sizeof(uint32_t);
- uint32_t param_payload_len =
- DOLBY_PARAM_PAYLOAD_SIZE * sizeof(uint32_t);
- int port_id, copp_idx, idx;
-
- for (idx = 0; idx < AFE_MAX_PORTS; idx++) {
- port_id = dolby_dap_params_states.port_id[idx];
- copp_idx = dolby_dap_params_states.copp_idx[idx];
- if ((copp_idx < 0) ||
- (copp_idx >= MAX_COPPS_PER_PORT) ||
- (port_id == DOLBY_INVALID_PORT_ID))
- continue;
- else
- break;
- }
- if (idx == AFE_MAX_PORTS) {
- pr_debug("%s, port_id not set, returning error", __func__);
- ucontrol->value.integer.value[0] = 0;
- return -EINVAL;
- }
- visualizer_data = kzalloc(params_length, GFP_KERNEL);
- if (!visualizer_data)
- return -ENOMEM;
-
- offset = 0;
- params_length = length * sizeof(uint32_t);
- rc = adm_get_params(port_id, copp_idx, DOLBY_BUNDLE_MODULE_ID,
- DOLBY_PARAM_ID_VCBG,
- params_length + param_payload_len,
- visualizer_data + offset);
- if (rc) {
- pr_err("%s: get parameters failed\n", __func__);
- kfree(visualizer_data);
- return -EINVAL;
- }
-
- offset = length * sizeof(uint32_t);
- rc = adm_get_params(port_id, copp_idx, DOLBY_BUNDLE_MODULE_ID,
- DOLBY_PARAM_ID_VCBE,
- params_length + param_payload_len,
- visualizer_data + offset);
- if (rc) {
- pr_err("%s: get parameters failed\n", __func__);
- kfree(visualizer_data);
- return -EINVAL;
- }
-
- ucontrol->value.integer.value[0] = 2*length;
- pr_debug("%s: visualizer data length %ld\n", __func__,
- ucontrol->value.integer.value[0]);
- update_visualizer_data = (int *)visualizer_data;
- for (i = 0; i < 2*length; i++) {
- ucontrol->value.integer.value[1+i] = update_visualizer_data[i];
- pr_debug("value[%d] %d\n", i, update_visualizer_data[i]);
- }
- kfree(visualizer_data);
- return 0;
-}
-
-int msm_dolby_dap_param_visualizer_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* not used while getting the visualizer data */
- return 0;
-}
-
-int msm_dolby_dap_endpoint_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* not used while setting the endpoint */
- return 0;
-}
-
-int msm_dolby_dap_endpoint_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int device = ucontrol->value.integer.value[0];
-
- dolby_dap_params_states.device = device;
- return 0;
-}
-
-int msm_dolby_dap_security_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- /* not used while setting the manfr id*/
- return 0;
-}
-
-int msm_dolby_dap_security_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int manufacturer_id = ucontrol->value.integer.value[0];
-
- core_set_dolby_manufacturer_id(manufacturer_id);
- return 0;
-}
-
-int msm_dolby_dap_license_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- ucontrol->value.integer.value[0] =
- core_get_license_status(DOLBY_DS1_LICENSE_ID);
- return 0;
-}
-
-int msm_dolby_dap_license_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- return core_set_license(ucontrol->value.integer.value[0],
- DOLBY_DS1_LICENSE_ID);
-}
-
-static const struct snd_kcontrol_new dolby_license_controls[] = {
- SOC_SINGLE_MULTI_EXT("DS1 License", SND_SOC_NOPM, 0,
- 0xFFFFFFFF, 0, 1, msm_dolby_dap_license_control_get,
- msm_dolby_dap_license_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_security_controls[] = {
- SOC_SINGLE_MULTI_EXT("DS1 Security", SND_SOC_NOPM, 0,
- 0xFFFFFFFF, 0, 1, msm_dolby_dap_security_control_get,
- msm_dolby_dap_security_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_dap_param_to_set_controls[] = {
- SOC_SINGLE_MULTI_EXT("DS1 DAP Set Param", SND_SOC_NOPM, 0, 0xFFFFFFFF,
- 0, 128, msm_dolby_dap_param_to_set_control_get,
- msm_dolby_dap_param_to_set_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_dap_param_to_get_controls[] = {
- SOC_SINGLE_MULTI_EXT("DS1 DAP Get Param", SND_SOC_NOPM, 0, 0xFFFFFFFF,
- 0, 128, msm_dolby_dap_param_to_get_control_get,
- msm_dolby_dap_param_to_get_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_dap_param_visualizer_controls[] = {
- SOC_SINGLE_MULTI_EXT("DS1 DAP Get Visualizer", SND_SOC_NOPM, 0,
- 0xFFFFFFFF, 0, 41, msm_dolby_dap_param_visualizer_control_get,
- msm_dolby_dap_param_visualizer_control_put),
-};
-
-static const struct snd_kcontrol_new dolby_dap_param_end_point_controls[] = {
- SOC_SINGLE_MULTI_EXT("DS1 DAP Endpoint", SND_SOC_NOPM, 0,
- 0xFFFFFFFF, 0, 1, msm_dolby_dap_endpoint_control_get,
- msm_dolby_dap_endpoint_control_put),
-};
-
-void msm_dolby_dap_add_controls(struct snd_soc_platform *platform)
-{
- snd_soc_add_platform_controls(platform,
- dolby_license_controls,
- ARRAY_SIZE(dolby_license_controls));
-
- snd_soc_add_platform_controls(platform,
- dolby_security_controls,
- ARRAY_SIZE(dolby_security_controls));
-
- snd_soc_add_platform_controls(platform,
- dolby_dap_param_to_set_controls,
- ARRAY_SIZE(dolby_dap_param_to_set_controls));
-
- snd_soc_add_platform_controls(platform,
- dolby_dap_param_to_get_controls,
- ARRAY_SIZE(dolby_dap_param_to_get_controls));
-
- snd_soc_add_platform_controls(platform,
- dolby_dap_param_visualizer_controls,
- ARRAY_SIZE(dolby_dap_param_visualizer_controls));
-
- snd_soc_add_platform_controls(platform,
- dolby_dap_param_end_point_controls,
- ARRAY_SIZE(dolby_dap_param_end_point_controls));
-}
diff --git a/sound/soc/msm/qdsp6v2/msm-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 d19c346..37dd31f 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;
@@ -84,10 +86,16 @@
atomic_t buf_count;
atomic_t read_abort;
wait_queue_head_t period_wait;
+ struct mutex lsm_api_lock;
int appl_cnt;
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 +201,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 +281,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 +671,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 +759,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 +791,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;
@@ -730,8 +809,13 @@
switch (cmd) {
case SNDRV_LSM_SET_SESSION_DATA:
dev_dbg(rtd->dev, "%s: set session data\n", __func__);
- memcpy(&session_data, arg,
- sizeof(struct snd_lsm_session_data));
+ if (copy_from_user(&session_data, arg,
+ sizeof(session_data))) {
+ dev_err(rtd->dev, "%s: %s: copy_from_user failed\n",
+ __func__, "LSM_SET_SESSION_DATA");
+ return -EFAULT;
+ }
+
if (session_data.app_id != LSM_VOICE_WAKEUP_APP_ID_V2) {
dev_err(rtd->dev,
"%s:Invalid App id %d for Listen client\n",
@@ -820,13 +904,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;
- }
-
dev_dbg(rtd->dev, "%s: set_params\n", __func__);
memcpy(&det_params, arg,
sizeof(det_params));
@@ -872,21 +949,36 @@
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);
+
+ /*
+ * Release the api lock before wait to allow
+ * other IOCTLs to be invoked while waiting
+ * for event
+ */
+ mutex_unlock(&prtd->lsm_api_lock);
rc = wait_event_freezable(prtd->event_wait,
(cmpxchg(&prtd->event_avail, 1, 0) ||
(xchg = atomic_cmpxchg(&prtd->event_wait_stop,
1, 0))));
+ mutex_lock(&prtd->lsm_api_lock);
dev_dbg(rtd->dev, "%s: wait_event_freezable %d event_wait_stop %d\n",
__func__, rc, xchg);
if (!rc && !xchg) {
dev_dbg(rtd->dev, "%s: New event available %ld\n",
__func__, prtd->event_avail);
spin_lock_irqsave(&prtd->event_lock, flags);
+
if (prtd->event_status) {
- size = sizeof(*(prtd->event_status)) +
- prtd->event_status->payload_size;
+ 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 {
@@ -898,15 +990,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 ==
@@ -931,6 +1051,7 @@
rc = 0;
}
break;
+ }
case SNDRV_LSM_ABORT_EVENT:
dev_dbg(rtd->dev, "%s: Aborting event status wait\n",
@@ -978,46 +1099,43 @@
break;
}
case SNDRV_LSM_LAB_CONTROL: {
- u32 *enable = NULL;
+ u32 enable;
- if (!arg) {
- dev_err(rtd->dev,
- "%s: Invalid param arg for ioctl %s session %d\n",
- __func__, "SNDRV_LSM_LAB_CONTROL",
- prtd->lsm_client->session);
- rc = -EINVAL;
- break;
+ if (copy_from_user(&enable, arg, sizeof(enable))) {
+ dev_err(rtd->dev, "%s: %s: copy_frm_user failed\n",
+ __func__, "LSM_LAB_CONTROL");
+ return -EFAULT;
}
- enable = (int *)arg;
+
dev_dbg(rtd->dev, "%s: ioctl %s, enable = %d\n",
- __func__, "SNDRV_LSM_LAB_CONTROL", *enable);
+ __func__, "SNDRV_LSM_LAB_CONTROL", enable);
if (!prtd->lsm_client->started) {
- if (prtd->lsm_client->lab_enable == *enable) {
+ if (prtd->lsm_client->lab_enable == enable) {
dev_dbg(rtd->dev,
"%s: Lab for session %d already %s\n",
__func__, prtd->lsm_client->session,
- ((*enable) ? "enabled" : "disabled"));
+ enable ? "enabled" : "disabled");
rc = 0;
break;
}
- rc = q6lsm_lab_control(prtd->lsm_client, *enable);
+ rc = q6lsm_lab_control(prtd->lsm_client, enable);
if (rc) {
dev_err(rtd->dev,
"%s: ioctl %s failed rc %d to %s lab for session %d\n",
__func__, "SNDRV_LAB_CONTROL", rc,
- ((*enable) ? "enable" : "disable"),
+ enable ? "enable" : "disable",
prtd->lsm_client->session);
} else {
rc = msm_lsm_lab_buffer_alloc(prtd,
- ((*enable) ? LAB_BUFFER_ALLOC
- : LAB_BUFFER_DEALLOC));
+ enable ? LAB_BUFFER_ALLOC
+ : LAB_BUFFER_DEALLOC);
if (rc)
dev_err(rtd->dev,
"%s: msm_lsm_lab_buffer_alloc failed rc %d for %s",
__func__, rc,
- ((*enable) ? "ALLOC" : "DEALLOC"));
+ enable ? "ALLOC" : "DEALLOC");
if (!rc)
- prtd->lsm_client->lab_enable = *enable;
+ prtd->lsm_client->lab_enable = enable;
}
} else {
dev_err(rtd->dev, "%s: ioctl %s issued after start",
@@ -1040,6 +1158,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",
@@ -1058,12 +1213,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;
@@ -1085,7 +1249,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 {
@@ -1095,14 +1259,14 @@
};
enum {
- SNDRV_LSM_EVENT_STATUS32 =
- _IOW('U', 0x02, struct snd_lsm_event_status32),
SNDRV_LSM_REG_SND_MODEL_V2_32 =
_IOW('U', 0x07, struct snd_lsm_sound_model_v2_32),
SNDRV_LSM_SET_PARAMS_32 =
_IOW('U', 0x0A, struct snd_lsm_detection_params_32),
SNDRV_LSM_SET_MODULE_PARAMS_32 =
_IOW('U', 0x0B, struct snd_lsm_module_params_32),
+ 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,
@@ -1126,15 +1290,18 @@
rtd = substream->private_data;
prtd = runtime->private_data;
+ mutex_lock(&prtd->lsm_api_lock);
+
switch (cmd) {
- case SNDRV_LSM_EVENT_STATUS32: {
- struct snd_lsm_event_status32 userarg32, *user32 = NULL;
- struct snd_lsm_event_status *user = NULL;
+ case SNDRV_LSM_EVENT_STATUS: {
+ struct snd_lsm_event_status *user = NULL, userarg32;
+ struct snd_lsm_event_status *user32 = NULL;
if (copy_from_user(&userarg32, arg, sizeof(userarg32))) {
dev_err(rtd->dev, "%s: err copyuser ioctl %s\n",
- __func__, "SNDRV_LSM_EVENT_STATUS32");
- return -EFAULT;
+ __func__, "SNDRV_LSM_EVENT_STATUS");
+ err = -EFAULT;
+ goto done;
}
if (userarg32.payload_size >
@@ -1142,7 +1309,8 @@
pr_err("%s: payload_size %d is invalid, max allowed = %d\n",
__func__, userarg32.payload_size,
LISTEN_MAX_STATUS_PAYLOAD_SIZE);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
size = sizeof(*user) + userarg32.payload_size;
@@ -1151,7 +1319,8 @@
dev_err(rtd->dev,
"%s: Allocation failed event status size %d\n",
__func__, size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
} else {
cmd = SNDRV_LSM_EVENT_STATUS;
user->payload_size = userarg32.payload_size;
@@ -1193,6 +1362,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;
@@ -1201,7 +1437,8 @@
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "REG_SND_MODEL_V2");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&snd_modelv232, arg,
@@ -1242,7 +1479,7 @@
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SET_PARAMS_32");
- return -EINVAL;
+ err = -EINVAL;
}
if (copy_from_user(&det_params32, arg,
@@ -1285,14 +1522,8 @@
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS_32");
- return -EINVAL;
- }
-
- if (!arg) {
- dev_err(rtd->dev,
- "%s: %s: No Param data to set\n",
- __func__, "SET_MODULE_PARAMS_32");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&p_data_32, arg,
@@ -1301,7 +1532,8 @@
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "SET_MODULE_PARAMS_32",
sizeof(p_data_32));
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
p_data.params = compat_ptr(p_data_32.params);
@@ -1313,7 +1545,8 @@
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.num_params);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (p_data.data_size !=
@@ -1322,15 +1555,18 @@
"%s: %s: Invalid size %d\n",
__func__, "SET_MODULE_PARAMS_32",
p_data.data_size);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
p_size = sizeof(struct lsm_params_info_32) *
p_data.num_params;
params32 = kzalloc(p_size, GFP_KERNEL);
- if (!params32)
- return -ENOMEM;
+ if (!params32) {
+ err = -ENOMEM;
+ goto done;
+ }
p_size = sizeof(struct lsm_params_info) * p_data.num_params;
params = kzalloc(p_size, GFP_KERNEL);
@@ -1339,7 +1575,8 @@
"%s: no memory for params, size = %zd\n",
__func__, p_size);
kfree(params32);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto done;
}
if (copy_from_user(params32, p_data.params,
@@ -1349,7 +1586,8 @@
__func__, "params32", p_data.data_size);
kfree(params32);
kfree(params);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
p_info_32 = (struct lsm_params_info_32 *) params32;
@@ -1375,10 +1613,25 @@
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_lsm_ioctl_shared(substream, cmd, arg);
break;
}
+done:
+ mutex_unlock(&prtd->lsm_api_lock);
return err;
}
#else
@@ -1390,7 +1643,6 @@
{
int err = 0;
u32 size = 0;
- struct snd_lsm_session_data session_data;
struct snd_pcm_runtime *runtime;
struct snd_soc_pcm_runtime *rtd;
struct lsm_priv *prtd;
@@ -1404,27 +1656,8 @@
prtd = runtime->private_data;
rtd = substream->private_data;
+ mutex_lock(&prtd->lsm_api_lock);
switch (cmd) {
- case SNDRV_LSM_SET_SESSION_DATA:
- dev_dbg(rtd->dev,
- "%s: SNDRV_LSM_SET_SESSION_DATA\n",
- __func__);
- if (copy_from_user(&session_data, (void *)arg,
- sizeof(struct snd_lsm_session_data))) {
- err = -EFAULT;
- dev_err(rtd->dev,
- "%s: copy from user failed, size %zd\n",
- __func__, sizeof(struct snd_lsm_session_data));
- break;
- }
- if (!err)
- err = msm_lsm_ioctl_shared(substream,
- cmd, &session_data);
- if (err)
- dev_err(rtd->dev,
- "%s REG_SND_MODEL failed err %d\n",
- __func__, err);
- break;
case SNDRV_LSM_REG_SND_MODEL_V2: {
struct snd_lsm_sound_model_v2 snd_model_v2;
@@ -1432,14 +1665,10 @@
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "REG_SND_MODEL_V2");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
- if (!arg) {
- dev_err(rtd->dev,
- "%s: Invalid params snd_model\n", __func__);
- return -EINVAL;
- }
if (copy_from_user(&snd_model_v2, arg, sizeof(snd_model_v2))) {
err = -EFAULT;
dev_err(rtd->dev,
@@ -1464,16 +1693,11 @@
dev_err(rtd->dev,
"%s: %s: not supported if using topology\n",
__func__, "SET_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
pr_debug("%s: SNDRV_LSM_SET_PARAMS\n", __func__);
- if (!arg) {
- dev_err(rtd->dev,
- "%s: %s, Invalid params\n",
- __func__, "SNDRV_LSM_SET_PARAMS");
- return -EINVAL;
- }
if (copy_from_user(&det_params, arg,
sizeof(det_params))) {
@@ -1491,7 +1715,8 @@
dev_err(rtd->dev,
"%s: LSM_SET_PARAMS failed, err %d\n",
__func__, err);
- return err;
+
+ goto done;
}
case SNDRV_LSM_SET_MODULE_PARAMS: {
@@ -1503,14 +1728,8 @@
dev_err(rtd->dev,
"%s: %s: not supported if not using topology\n",
__func__, "SET_MODULE_PARAMS");
- return -EINVAL;
- }
-
- if (!arg) {
- dev_err(rtd->dev,
- "%s: %s: No Param data to set\n",
- __func__, "SET_MODULE_PARAMS");
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
if (copy_from_user(&p_data, arg,
@@ -1518,7 +1737,8 @@
dev_err(rtd->dev,
"%s: %s: copy_from_user failed, size = %zd\n",
__func__, "p_data", sizeof(p_data));
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
if (p_data.num_params > LSM_PARAMS_MAX) {
@@ -1526,7 +1746,8 @@
"%s: %s: Invalid num_params %d\n",
__func__, "SET_MODULE_PARAMS",
p_data.num_params);
- return -EINVAL;
+ err = -EINVAL;
+ goto done;
}
p_size = p_data.num_params *
@@ -1537,12 +1758,15 @@
"%s: %s: Invalid size %zd\n",
__func__, "SET_MODULE_PARAMS", p_size);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
params = kzalloc(p_size, GFP_KERNEL);
- if (!params)
- return -ENOMEM;
+ if (!params) {
+ err = -ENOMEM;
+ goto done;
+ }
if (copy_from_user(params, p_data.params,
p_data.data_size)) {
@@ -1550,7 +1774,8 @@
"%s: %s: copy_from_user failed, size = %d\n",
__func__, "params", p_data.data_size);
kfree(params);
- return -EFAULT;
+ err = -EFAULT;
+ goto done;
}
err = msm_lsm_process_params(substream, &p_data, params);
@@ -1567,15 +1792,72 @@
dev_dbg(rtd->dev,
"%s: SNDRV_LSM_EVENT_STATUS\n", __func__);
+ if (copy_from_user(&userarg, arg, sizeof(userarg))) {
+ dev_err(rtd->dev,
+ "%s: err copyuser event_status\n",
+ __func__);
+ err = -EFAULT;
+ goto done;
+ }
+
+ 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);
+ err = -EINVAL;
+ goto done;
+ }
+
+ size = sizeof(struct snd_lsm_event_status) +
+ userarg.payload_size;
+ user = kmalloc(size, GFP_KERNEL);
+ if (!user) {
+ dev_err(rtd->dev,
+ "%s: Allocation failed event status size %d\n",
+ __func__, size);
+ err = -EFAULT;
+ goto done;
+ }
+ user->payload_size = userarg.payload_size;
+ err = msm_lsm_ioctl_shared(substream, cmd, user);
+
+ /* Update size with actual payload size */
+ size = sizeof(*user) + user->payload_size;
+ if (!err && !access_ok(VERIFY_WRITE, arg, size)) {
+ dev_err(rtd->dev,
+ "%s: write verify failed size %d\n",
+ __func__, size);
+ err = -EFAULT;
+ }
+ if (!err && (copy_to_user(arg, user, size))) {
+ dev_err(rtd->dev,
+ "%s: failed to copy payload %d",
+ __func__, size);
+ err = -EFAULT;
+ }
+ kfree(user);
+ if (err)
+ dev_err(rtd->dev,
+ "%s: lsmevent failed %d", __func__, err);
+ goto done;
+ }
+
+ 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\n",
+ "%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\n",
+ "%s: err copyuser event_status_v3\n",
__func__);
return -EFAULT;
}
@@ -1588,8 +1870,8 @@
return -EINVAL;
}
- size = sizeof(struct snd_lsm_event_status) +
- userarg.payload_size;
+ size = sizeof(struct snd_lsm_event_status_v3) +
+ userarg.payload_size;
user = kmalloc(size, GFP_KERNEL);
if (!user) {
dev_err(rtd->dev,
@@ -1617,13 +1899,16 @@
kfree(user);
if (err)
dev_err(rtd->dev,
- "%s: lsmevent failed %d", __func__, err);
- return err;
+ "%s: lsm_event_v3 failed %d", __func__, err);
+ break;
}
+
default:
err = msm_lsm_ioctl_shared(substream, cmd, arg);
break;
}
+done:
+ mutex_unlock(&prtd->lsm_api_lock);
return err;
}
@@ -1640,6 +1925,7 @@
__func__);
return -ENOMEM;
}
+ mutex_init(&prtd->lsm_api_lock);
spin_lock_init(&prtd->event_lock);
init_waitqueue_head(&prtd->event_wait);
init_waitqueue_head(&prtd->period_wait);
@@ -1687,6 +1973,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;
}
@@ -1695,6 +1986,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__);
@@ -1708,9 +2000,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)
@@ -1759,6 +2072,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;
@@ -1769,6 +2085,7 @@
kfree(prtd->event_status);
prtd->event_status = NULL;
spin_unlock_irqrestore(&prtd->event_lock, flags);
+ mutex_destroy(&prtd->lsm_api_lock);
kfree(prtd);
runtime->private_data = NULL;
@@ -1780,7 +2097,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) {
@@ -1796,25 +2113,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;
}
@@ -1910,6 +2238,105 @@
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 session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ 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: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
+
+ 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 session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &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, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
+ 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,
@@ -1924,11 +2351,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-afe-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
index 8d43186..ab9b310 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-afe-v2.c
@@ -682,6 +682,7 @@
mutex_unlock(&prtd->lock);
prtd->prepared--;
kfree(prtd);
+ runtime->private_data = NULL;
return 0;
}
static int msm_afe_prepare(struct snd_pcm_substream *substream)
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-loopback-v2.c
index 15809ce..f668e95 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) {
@@ -542,48 +557,45 @@
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &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);
@@ -593,8 +605,8 @@
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_RX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -604,48 +616,45 @@
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &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);
@@ -655,8 +664,8 @@
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,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -746,9 +755,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-noirq.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
index ecf194f..9b7c6fb 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-noirq.c
@@ -139,6 +139,17 @@
.mask = 0,
};
+static unsigned long msm_pcm_fe_topology[MSM_FRONTEND_DAI_MAX];
+
+/* default value is DTS (i.e read from device tree) */
+static char const *msm_pcm_fe_topology_text[] = {
+ "DTS", "ULL", "ULL_PP", "LL" };
+
+static const struct soc_enum msm_pcm_fe_topology_enum[] = {
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm_pcm_fe_topology_text),
+ msm_pcm_fe_topology_text),
+};
+
static void event_handler(uint32_t opcode,
uint32_t token, uint32_t *payload, void *priv)
{
@@ -258,6 +269,8 @@
uint16_t bits_per_sample;
int ret;
int dir = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? IN : OUT;
+ unsigned long topology;
+ int perf_mode;
pdata = (struct msm_plat_data *)
dev_get_drvdata(soc_prtd->platform->dev);
@@ -268,11 +281,24 @@
return ret;
}
+ topology = msm_pcm_fe_topology[soc_prtd->dai_link->id];
+
+ if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL_PP"))
+ perf_mode = ULL_POST_PROCESSING_PCM_MODE;
+ else if (!strcmp(msm_pcm_fe_topology_text[topology], "ULL"))
+ perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ else if (!strcmp(msm_pcm_fe_topology_text[topology], "LL"))
+ perf_mode = LOW_LATENCY_PCM_MODE;
+ else
+ /* use the default from the device tree */
+ perf_mode = pdata->perf_mode;
+
+
/* need to set LOW_LATENCY_PCM_MODE for capture since
* push mode does not support ULL
*/
prtd->audio_client->perf_mode = (dir == IN) ?
- pdata->perf_mode :
+ perf_mode :
LOW_LATENCY_PCM_MODE;
/* rate and channels are sent to audio driver */
@@ -544,6 +570,8 @@
SNDRV_PCM_STREAM_PLAYBACK :
SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
+ runtime->private_data = NULL;
+
return 0;
}
@@ -721,6 +749,269 @@
return 0;
}
+static int msm_pcm_fe_topology_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ const struct soc_enum *e = &msm_pcm_fe_topology_enum[0];
+
+ return snd_ctl_enum_info(uinfo, 1, e->items, e->texts);
+}
+
+static int msm_pcm_fe_topology_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned long fe_id = kcontrol->private_value;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: %lu topology %s\n", __func__, fe_id,
+ msm_pcm_fe_topology_text[msm_pcm_fe_topology[fe_id]]);
+ ucontrol->value.enumerated.item[0] = msm_pcm_fe_topology[fe_id];
+ return 0;
+}
+
+static int msm_pcm_fe_topology_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ unsigned long fe_id = kcontrol->private_value;
+ unsigned int item;
+
+ if (fe_id >= MSM_FRONTEND_DAI_MAX) {
+ pr_err("%s Received out of bound fe_id %lu\n", __func__, fe_id);
+ return -EINVAL;
+ }
+
+ item = ucontrol->value.enumerated.item[0];
+ if (item >= ARRAY_SIZE(msm_pcm_fe_topology_text)) {
+ pr_err("%s Received out of bound topology %lu\n", __func__,
+ fe_id);
+ return -EINVAL;
+ }
+
+ pr_debug("%s: %lu new topology %s\n", __func__, fe_id,
+ msm_pcm_fe_topology_text[item]);
+ msm_pcm_fe_topology[fe_id] = item;
+ return 0;
+}
+
+static int msm_pcm_add_fe_topology_control(struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = "PCM_Dev";
+ const char *deviceNo = "NN";
+ const char *topo_text = "Topology";
+ char *mixer_str = NULL;
+ int ctl_len;
+ int ret;
+ struct snd_kcontrol_new topology_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .name = "?",
+ .info = msm_pcm_fe_topology_info,
+ .get = msm_pcm_fe_topology_get,
+ .put = msm_pcm_fe_topology_put,
+ .private_value = 0,
+ },
+ };
+
+ ctl_len = strlen(mixer_ctl_name) + 1 + strlen(deviceNo) + 1 +
+ strlen(topo_text) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+ if (!mixer_str)
+ return -ENOMEM;
+
+ snprintf(mixer_str, ctl_len, "%s %d %s", mixer_ctl_name,
+ rtd->pcm->device, topo_text);
+
+ topology_control[0].name = mixer_str;
+ topology_control[0].private_value = rtd->dai_link->id;
+ ret = snd_soc_add_platform_controls(rtd->platform, topology_control,
+ ARRAY_SIZE(topology_control));
+ msm_pcm_fe_topology[rtd->dai_link->id] = 0;
+ kfree(mixer_str);
+ return ret;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_put failed, err %d\n",
+ __func__, ret);
+
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ return ret;
+}
+
+static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_playback_app_type_cfg_ctl_get failed, err: %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, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate = 48000;
+
+ app_type = ucontrol->value.integer.value[0];
+ acdb_dev_id = ucontrol->value.integer.value[1];
+ if (ucontrol->value.integer.value[2] != 0)
+ sample_rate = ucontrol->value.integer.value[2];
+
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_put failed, err: %d\n",
+ __func__, ret);
+
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+
+ return ret;
+}
+
+static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
+ int app_type;
+ int acdb_dev_id;
+ int sample_rate;
+
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &app_type,
+ &acdb_dev_id,
+ &sample_rate);
+ if (ret < 0) {
+ pr_err("%s: msm_pcm_capture_app_type_cfg_ctl_get failed, err: %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, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+done:
+ return ret;
+}
+
+static int msm_pcm_add_app_type_controls(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_pcm *pcm = rtd->pcm;
+ struct snd_pcm_usr *app_type_info;
+ struct snd_kcontrol *kctl;
+ const char *playback_mixer_ctl_name = "Audio Stream";
+ const char *capture_mixer_ctl_name = "Audio Stream Capture";
+ const char *deviceNo = "NN";
+ const char *suffix = "App Type Cfg";
+ int ctl_len, ret = 0;
+
+ if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
+ ctl_len = strlen(playback_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 +
+ strlen(suffix) + 1;
+ pr_debug("%s: Playback app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ NULL, 1, ctl_len, rtd->dai_link->id,
+ &app_type_info);
+ if (ret < 0) {
+ pr_err("%s: playback app type cntrl add failed, err: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ playback_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_playback_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_playback_app_type_cfg_ctl_get;
+ }
+
+ if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
+ ctl_len = strlen(capture_mixer_ctl_name) + 1 +
+ strlen(deviceNo) + 1 + strlen(suffix) + 1;
+ pr_debug("%s: Capture app type cntrl add\n", __func__);
+ ret = snd_pcm_add_usr_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE,
+ NULL, 1, ctl_len, rtd->dai_link->id,
+ &app_type_info);
+ if (ret < 0) {
+ pr_err("%s: capture app type cntrl add failed, err: %d\n",
+ __func__, ret);
+ return ret;
+ }
+ kctl = app_type_info->kctl;
+ snprintf(kctl->id.name, ctl_len, "%s %d %s",
+ capture_mixer_ctl_name, rtd->pcm->device, suffix);
+ kctl->put = msm_pcm_capture_app_type_cfg_ctl_put;
+ kctl->get = msm_pcm_capture_app_type_cfg_ctl_get;
+ }
+
+ return 0;
+}
+
+
static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_card *card = rtd->card->snd_card;
@@ -741,6 +1032,19 @@
pr_err("%s: Could not add pcm Volume Control %d\n",
__func__, ret);
}
+
+ ret = msm_pcm_add_fe_topology_control(rtd);
+ if (ret) {
+ pr_err("%s: Could not add pcm topology control %d\n",
+ __func__, ret);
+ }
+
+ ret = msm_pcm_add_app_type_controls(rtd);
+ if (ret) {
+ pr_err("%s: Could not add app type controls failed %d\n",
+ __func__, ret);
+ }
+
pcm->nonatomic = true;
exit:
return ret;
@@ -778,8 +1082,12 @@
rc = of_property_read_string(pdev->dev.of_node,
"qcom,latency-level", &latency_level);
- if (!rc && !strcmp(latency_level, "ultra"))
- perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ if (!rc) {
+ if (!strcmp(latency_level, "ultra"))
+ perf_mode = ULTRA_LOW_LATENCY_PCM_MODE;
+ else if (!strcmp(latency_level, "ull-pp"))
+ perf_mode = ULL_POST_PROCESSING_PCM_MODE;
+ }
}
pdata = devm_kzalloc(&pdev->dev,
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
index e899f5e..1799d0d 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.c
@@ -110,7 +110,7 @@
/* Conventional and unconventional sample rate supported */
static unsigned int supported_sample_rates[] = {
8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
- 88200, 96000, 176400, 192000, 384000
+ 88200, 96000, 176400, 192000, 352800, 384000
};
static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
@@ -286,6 +286,7 @@
struct msm_plat_data *pdata;
struct snd_pcm_hw_params *params;
int ret;
+ uint32_t fmt_type = FORMAT_LINEAR_PCM;
uint16_t bits_per_sample;
uint16_t sample_word_size;
@@ -334,38 +335,67 @@
sample_word_size = 16;
break;
}
+ if (prtd->compress_enable) {
+ fmt_type = FORMAT_GEN_COMPR;
+ pr_debug("%s: Compressed enabled!\n", __func__);
+ ret = q6asm_open_write_compressed(prtd->audio_client, fmt_type,
+ COMPRESSED_PASSTHROUGH_GEN);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_write_compressed failed (%d)\n",
+ __func__, ret);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return -ENOMEM;
+ }
+ } else {
+ ret = q6asm_open_write_v4(prtd->audio_client,
+ fmt_type, bits_per_sample);
- ret = q6asm_open_write_v4(prtd->audio_client,
- FORMAT_LINEAR_PCM, bits_per_sample);
+ if (ret < 0) {
+ pr_err("%s: q6asm_open_write_v4 failed (%d)\n",
+ __func__, ret);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return -ENOMEM;
+ }
- if (ret < 0) {
- pr_err("%s: q6asm_open_write_v2 failed\n", __func__);
- q6asm_audio_client_free(prtd->audio_client);
- prtd->audio_client = NULL;
- return -ENOMEM;
+ ret = q6asm_send_cal(prtd->audio_client);
+ if (ret < 0)
+ pr_debug("%s : Send cal failed : %d", __func__, ret);
}
-
- ret = q6asm_send_cal(prtd->audio_client);
- if (ret < 0)
- pr_debug("%s : Send cal failed : %d", __func__, ret);
-
pr_debug("%s: session ID %d\n", __func__,
prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
- ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id,
+
+ if (prtd->compress_enable) {
+ ret = msm_pcm_routing_reg_phy_compr_stream(
+ soc_prtd->dai_link->id,
+ prtd->audio_client->perf_mode,
+ prtd->session_id,
+ SNDRV_PCM_STREAM_PLAYBACK,
+ COMPRESSED_PASSTHROUGH_GEN);
+ } else {
+ ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id,
prtd->audio_client->perf_mode,
prtd->session_id, substream->stream);
+ }
if (ret) {
pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
return ret;
}
-
- ret = q6asm_media_format_block_multi_ch_pcm_v4(
+ if (prtd->compress_enable) {
+ ret = q6asm_media_format_block_gen_compr(
+ prtd->audio_client, runtime->rate,
+ runtime->channels, !prtd->set_channel_map,
+ prtd->channel_map, bits_per_sample);
+ } else {
+ ret = q6asm_media_format_block_multi_ch_pcm_v4(
prtd->audio_client, runtime->rate,
runtime->channels, !prtd->set_channel_map,
prtd->channel_map, bits_per_sample,
sample_word_size, ASM_LITTLE_ENDIAN,
DEFAULT_QF);
+ }
if (ret < 0)
pr_info("%s: CMD Format block failed\n", __func__);
@@ -424,7 +454,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);
@@ -774,6 +804,8 @@
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
SNDRV_PCM_STREAM_PLAYBACK);
kfree(prtd);
+ runtime->private_data = NULL;
+
return 0;
}
@@ -879,6 +911,7 @@
msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->id,
SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
+ runtime->private_data = NULL;
return 0;
}
@@ -1091,6 +1124,136 @@
return 0;
}
+static int msm_pcm_compress_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 0x2000;
+ return 0;
+}
+
+static int msm_pcm_compress_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+ struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+
+ if (!pdata) {
+ pr_err("%s pdata is NULL\n", __func__);
+ return -ENODEV;
+ }
+ substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -EINVAL;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd)
+ ucontrol->value.integer.value[0] = prtd->compress_enable;
+ return 0;
+}
+
+static int msm_pcm_compress_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int rc = 0;
+ struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_platform *platform = snd_soc_component_to_platform(comp);
+ struct msm_plat_data *pdata = dev_get_drvdata(platform->dev);
+ struct snd_pcm_substream *substream;
+ struct msm_audio *prtd;
+ int compress = ucontrol->value.integer.value[0];
+
+ if (!pdata) {
+ pr_err("%s pdata is NULL\n", __func__);
+ return -ENODEV;
+ }
+ substream = pdata->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ pr_debug("%s: compress : 0x%x\n", __func__, compress);
+ if (!substream) {
+ pr_err("%s substream not found\n", __func__);
+ return -EINVAL;
+ }
+ if (!substream->runtime) {
+ pr_err("%s substream runtime not found\n", __func__);
+ return 0;
+ }
+ prtd = substream->runtime->private_data;
+ if (prtd) {
+ pr_debug("%s: setting compress flag to 0x%x\n",
+ __func__, compress);
+ prtd->compress_enable = compress;
+ }
+ return rc;
+}
+
+static int msm_pcm_add_compress_control(struct snd_soc_pcm_runtime *rtd)
+{
+ const char *mixer_ctl_name = "Playback ";
+ const char *mixer_ctl_end_name = " Compress";
+ const char *deviceNo = "NN";
+ char *mixer_str = NULL;
+ int ctl_len;
+ int ret = 0;
+ struct msm_plat_data *pdata;
+ struct snd_kcontrol_new pcm_compress_control[1] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "?",
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = msm_pcm_compress_ctl_info,
+ .get = msm_pcm_compress_ctl_get,
+ .put = msm_pcm_compress_ctl_put,
+ .private_value = 0,
+ }
+ };
+
+ if (!rtd) {
+ pr_err("%s: NULL rtd\n", __func__);
+ return -EINVAL;
+ }
+
+ ctl_len = strlen(mixer_ctl_name) + strlen(deviceNo) +
+ strlen(mixer_ctl_end_name) + 1;
+ mixer_str = kzalloc(ctl_len, GFP_KERNEL);
+
+ if (!mixer_str)
+ return -ENOMEM;
+
+ snprintf(mixer_str, ctl_len, "%s%d%s", mixer_ctl_name,
+ rtd->pcm->device, mixer_ctl_end_name);
+
+ pcm_compress_control[0].name = mixer_str;
+ pcm_compress_control[0].private_value = rtd->dai_link->id;
+ pr_debug("%s: Registering new mixer ctl %s\n", __func__, mixer_str);
+ pdata = dev_get_drvdata(rtd->platform->dev);
+ if (pdata) {
+ if (!pdata->pcm) {
+ pdata->pcm = rtd->pcm;
+ snd_soc_add_platform_controls(rtd->platform,
+ pcm_compress_control,
+ ARRAY_SIZE
+ (pcm_compress_control));
+ pr_debug("%s: add control success plt = %pK\n",
+ __func__, rtd->platform);
+ }
+ } else {
+ pr_err("%s: NULL pdata\n", __func__);
+ ret = -EINVAL;
+ }
+ kfree(mixer_str);
+ return ret;
+}
+
static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1182,48 +1345,45 @@
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_RX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_RX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_pcm_playback_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_RX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_RX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &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);
@@ -1233,8 +1393,8 @@
ucontrol->value.integer.value[0] = app_type;
ucontrol->value.integer.value[1] = acdb_dev_id;
ucontrol->value.integer.value[2] = sample_rate;
- pr_debug("%s: fedai_id %llu, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fe_id, SESSION_TYPE_RX,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -1244,48 +1404,45 @@
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
+ int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate = 48000;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- return -EINVAL;
- }
-
app_type = ucontrol->value.integer.value[0];
acdb_dev_id = ucontrol->value.integer.value[1];
if (ucontrol->value.integer.value[2] != 0)
sample_rate = ucontrol->value.integer.value[2];
- pr_debug("%s: app_type- %d acdb_dev_id- %d sample_rate- %d session_type- %d\n",
- __func__, app_type, acdb_dev_id, sample_rate, SESSION_TYPE_TX);
- msm_pcm_routing_reg_stream_app_type_cfg(fe_id, app_type,
- acdb_dev_id, sample_rate, SESSION_TYPE_TX);
+ pr_debug("%s: fe_id- %llu session_type- %d be_id- %d app_type- %d acdb_dev_id- %d sample_rate- %d\n",
+ __func__, fe_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+ ret = msm_pcm_routing_reg_stream_app_type_cfg(fe_id, session_type,
+ be_id, app_type,
+ acdb_dev_id, sample_rate);
+ if (ret < 0)
+ pr_err("%s: msm_pcm_routing_reg_stream_app_type_cfg failed returned %d\n",
+ __func__, ret);
- return 0;
+ return ret;
}
static int msm_pcm_capture_app_type_cfg_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
u64 fe_id = kcontrol->private_value;
+ int session_type = SESSION_TYPE_TX;
+ int be_id = ucontrol->value.integer.value[3];
int ret = 0;
int app_type;
int acdb_dev_id;
int sample_rate;
- pr_debug("%s: fe_id- %llu\n", __func__, fe_id);
- if (fe_id >= MSM_FRONTEND_DAI_MAX) {
- pr_err("%s: Received out of bounds fe_id %llu\n",
- __func__, fe_id);
- ret = -EINVAL;
- goto done;
- }
-
- ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, SESSION_TYPE_TX,
- &app_type, &acdb_dev_id, &sample_rate);
+ ret = msm_pcm_routing_get_stream_app_type_cfg(fe_id, session_type,
+ be_id, &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);
@@ -1295,8 +1452,8 @@
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,
+ pr_debug("%s: fedai_id %llu, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fe_id, session_type, be_id,
app_type, acdb_dev_id, sample_rate);
done:
return ret;
@@ -1388,6 +1545,11 @@
pr_err("%s: Could not add pcm Volume Control %d\n",
__func__, ret);
+ ret = msm_pcm_add_compress_control(rtd);
+ if (ret)
+ pr_err("%s: Could not add pcm Compress Control %d\n",
+ __func__, ret);
+
return ret;
}
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
index 5290d34..3b3f048 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-q6-v2.h
@@ -109,6 +109,7 @@
int cmd_interrupt;
bool meta_data_mode;
uint32_t volume;
+ bool compress_enable;
/* array of frame info */
struct msm_audio_in_frame_info in_frame_info[CAPTURE_MAX_NUM_PERIODS];
};
@@ -123,6 +124,7 @@
struct msm_plat_data {
int perf_mode;
+ struct snd_pcm *pcm;
};
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 3d13932..465634b 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -56,22 +56,26 @@
#define DS2_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFF
#endif
-static int get_cal_path(int path_type);
-
static struct mutex routing_lock;
static struct cal_type_data *cal_data;
static int fm_switch_enable;
static int hfp_switch_enable;
+static int 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 +89,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 +98,17 @@
#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 INT3_MI2S_TX_TEXT "INT3_MI2S_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,
+ INT3_MI2S_TX_TEXT
};
struct msm_pcm_route_bdai_pp_params {
@@ -113,6 +124,18 @@
{DISPLAY_PORT_RX, 0, 0, 0},
};
+/*
+ * The be_dai_name_table is passed to HAL so that it can specify the
+ * BE ID for the BE it wants to enable based on the name. Thus there
+ * is a matching table and structure in HAL that need to be updated
+ * if any changes to these are made.
+ */
+struct msm_pcm_route_bdai_name {
+ unsigned int be_id;
+ char be_name[LPASS_BE_NAME_MAX_LENGTH];
+};
+static struct msm_pcm_route_bdai_name be_dai_name_table[MSM_BACKEND_DAI_MAX];
+
static int msm_routing_send_device_pp_params(int port_id, int copp_idx);
static int msm_routing_get_bit_width(unsigned int format)
@@ -120,6 +143,9 @@
int bit_width;
switch (format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
+ bit_width = 32;
+ break;
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S24_3LE:
bit_width = 24;
@@ -265,253 +291,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 +603,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][MSM_BACKEND_DAI_MAX];
/* The caller of this should aqcuire routing lock */
void msm_pcm_routing_get_bedai_info(int be_idx,
@@ -618,44 +719,89 @@
return 0;
}
-void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
- int acdb_dev_id, int sample_rate, int session_type)
+static int msm_pcm_routing_get_lsm_app_type_idx(int app_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) {
+ 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;
+}
+
+int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
+ int be_id, int app_type,
+ int acdb_dev_id, int sample_rate)
+{
+ int ret = 0;
+
+ pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fedai_id, session_type, be_id,
+ app_type, acdb_dev_id, sample_rate);
+
+ if (!is_mm_lsm_fe_id(fedai_id)) {
pr_err("%s: Invalid machine driver ID %d\n",
__func__, fedai_id);
- return;
+ ret = -EINVAL;
+ goto done;
}
if (session_type != SESSION_TYPE_RX &&
session_type != SESSION_TYPE_TX) {
pr_err("%s: Invalid session type %d\n",
__func__, session_type);
- return;
+ ret = -EINVAL;
+ goto done;
}
- fe_dai_app_type_cfg[fedai_id][session_type].app_type = app_type;
- fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id = acdb_dev_id;
- fe_dai_app_type_cfg[fedai_id][session_type].sample_rate = sample_rate;
+ if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds be_id %d\n",
+ __func__, be_id);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type = app_type;
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id =
+ acdb_dev_id;
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate =
+ sample_rate;
+
+done:
+ return ret;
}
/**
* msm_pcm_routing_get_stream_app_type_cfg
*
- * Receives fedai_id, session_type and populates app_type, acdb_dev_id, &
- * sample rate. Returns 0 on success. On failure returns
+ * Receives fedai_id, session_type, be_id, and populates app_type,
+ * acdb_dev_id, & sample rate. Returns 0 on success. On failure returns
* -EINVAL and does not alter passed values.
*
* fedai_id - Passed value, front end ID for which app type config is wanted
* session_type - Passed value, session type for which app type config
* is wanted
+ * be_id - Passed value, back end device id for which app type config is wanted
* app_type - Returned value, app type used by app type config
* acdb_dev_id - Returned value, ACDB device ID used by app type config
* sample_rate - Returned value, sample rate used by app type config
*/
int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
- int *app_type, int *acdb_dev_id, int *sample_rate)
+ int be_id, int *app_type,
+ int *acdb_dev_id, int *sample_rate)
{
int ret = 0;
@@ -671,24 +817,31 @@
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;
goto done;
} else if (session_type != SESSION_TYPE_RX &&
- session_type != SESSION_TYPE_TX) {
+ session_type != SESSION_TYPE_TX) {
pr_err("%s: Invalid session type %d\n",
__func__, session_type);
ret = -EINVAL;
goto done;
+ } else if (be_id < 0 || be_id >= MSM_BACKEND_DAI_MAX) {
+ pr_err("%s: Received out of bounds be_id %d\n",
+ __func__, be_id);
+ return -EINVAL;
}
- *app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
- *acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
- *sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
- pr_debug("%s: fedai_id %d, session_type %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
- __func__, fedai_id, session_type,
+ *app_type = fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type;
+ *acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
+ *sample_rate =
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].sample_rate;
+
+ pr_debug("%s: fedai_id %d, session_type %d, be_id %d, app_type %d, acdb_dev_id %d, sample_rate %d\n",
+ __func__, fedai_id, session_type, be_id,
*app_type, *acdb_dev_id, *sample_rate);
done:
return ret;
@@ -719,8 +872,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,37 +890,37 @@
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);
}
-static int msm_routing_get_adm_topology(int path, int fedai_id,
- int session_type)
+static int msm_routing_get_adm_topology(int fedai_id, int session_type,
+ int be_id)
{
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__);
- path = get_cal_path(path);
+ pr_debug("%s: fedai_id %d, session_type %d, be_id %d\n",
+ __func__, fedai_id, session_type, be_id);
+
if (cal_data == NULL)
goto done;
mutex_lock(&cal_data->lock);
- app_type = fe_dai_app_type_cfg[fedai_id][session_type].app_type;
- acdb_dev_id = fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
- sample_rate = fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
+ app_type = fe_dai_app_type_cfg[fedai_id][session_type][be_id].app_type;
+ acdb_dev_id =
+ fe_dai_app_type_cfg[fedai_id][session_type][be_id].acdb_dev_id;
- cal_block = msm_routing_find_topology(path, app_type,
- acdb_dev_id, sample_rate);
+ cal_block = msm_routing_find_topology(session_type, app_type,
+ acdb_dev_id);
if (cal_block == NULL)
goto unlock;
@@ -792,20 +944,21 @@
}
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;
- port_type = ((path_type == ADM_PATH_PLAYBACK ||
- path_type == ADM_PATH_COMPRESSED_RX) ?
+ port_type = ((path_type == ADM_PATH_PLAYBACK ||
+ path_type == ADM_PATH_COMPRESSED_RX) ?
MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
if (!is_be_dai_extproc(i) &&
(afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
(msm_bedais[i].active) &&
- (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+ (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];
@@ -813,6 +966,18 @@
payload.port_id[num_copps] =
msm_bedais[i].port_id;
payload.copp_idx[num_copps] = j;
+ payload.app_type[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][sess_type][i]
+ .app_type;
+ payload.acdb_dev_id[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][sess_type][i]
+ .acdb_dev_id;
+ payload.sample_rate[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][sess_type][i]
+ .sample_rate;
num_copps++;
}
}
@@ -822,13 +987,7 @@
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fedai_id][sess_type].strm_id;
- payload.app_type =
- fe_dai_app_type_cfg[fedai_id][sess_type].app_type;
- payload.acdb_dev_id =
- fe_dai_app_type_cfg[fedai_id][sess_type].acdb_dev_id;
- payload.sample_rate =
- fe_dai_app_type_cfg[fedai_id][sess_type].sample_rate;
- adm_matrix_map(path_type, payload, perf_mode);
+ adm_matrix_map(path_type, payload, perf_mode, passthr_mode);
msm_pcm_routng_cfg_matrix_map_pp(payload, path_type, perf_mode);
}
}
@@ -862,7 +1021,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 +1031,52 @@
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;
+ int i, j, session_type, path_type, port_type, topology;
+ int 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 +1090,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 +1099,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;
/*
@@ -936,25 +1121,36 @@
bit_width = msm_routing_get_bit_width(
msm_bedais[i].format);
app_type =
- fe_dai_app_type_cfg[fe_id][session_type].app_type;
- if (app_type) {
+ fe_dai_app_type_cfg[fe_id][session_type][i].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][i]
+ .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);
sample_rate =
- fe_dai_app_type_cfg[fe_id][session_type].sample_rate;
+ fe_dai_app_type_cfg[fe_id][session_type][i].sample_rate;
bit_width =
app_type_cfg[app_type_idx].bit_width;
} else {
sample_rate = msm_bedais[i].sample_rate;
}
acdb_dev_id =
- fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
- topology = msm_routing_get_adm_topology(path_type,
- fe_id, session_type);
- if (compr_passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
- topology = COMPRESS_PASSTHROUGH_NONE_TOPOLOGY;
- pr_err("%s: Before adm open topology %d\n", __func__,
+ fe_dai_app_type_cfg[fe_id][session_type][i].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(fe_id,
+ session_type,
+ i);
+ if ((passthr_mode == COMPRESSED_PASSTHROUGH_DSD)
+ || (passthr_mode ==
+ COMPRESSED_PASSTHROUGH_GEN))
+ topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY;
+ pr_debug("%s: Before adm open topology %d\n", __func__,
topology);
copp_idx =
@@ -988,10 +1184,24 @@
payload.port_id[num_copps] =
msm_bedais[i].port_id;
payload.copp_idx[num_copps] = j;
+ payload.app_type[num_copps] =
+ fe_dai_app_type_cfg
+ [fe_id][session_type][i]
+ .app_type;
+ payload.acdb_dev_id[num_copps] =
+ fe_dai_app_type_cfg
+ [fe_id][session_type][i]
+ .acdb_dev_id;
+ payload.sample_rate[num_copps] =
+ fe_dai_app_type_cfg
+ [fe_id][session_type][i]
+ .sample_rate;
num_copps++;
}
}
- if (compr_passthr_mode != COMPRESSED_PASSTHROUGH_DSD) {
+ if (passthr_mode != COMPRESSED_PASSTHROUGH_DSD
+ && passthr_mode !=
+ COMPRESSED_PASSTHROUGH_GEN) {
msm_routing_send_device_pp_params(
msm_bedais[i].port_id,
copp_idx);
@@ -1001,11 +1211,7 @@
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fe_id][session_type].strm_id;
- payload.app_type =
- fe_dai_app_type_cfg[fe_id][session_type].app_type;
- payload.acdb_dev_id =
- fe_dai_app_type_cfg[fe_id][session_type].acdb_dev_id;
- adm_matrix_map(path_type, payload, perf_mode);
+ 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 +1262,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 +1292,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,29 +1302,31 @@
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(
msm_bedais[i].format);
app_type =
- fe_dai_app_type_cfg[fedai_id][session_type].app_type;
+ fe_dai_app_type_cfg[fedai_id][session_type][i].app_type;
if (app_type) {
app_type_idx =
msm_pcm_routing_get_app_type_idx(app_type);
sample_rate =
- fe_dai_app_type_cfg[fedai_id][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[fedai_id][session_type][i]
+ .sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
sample_rate = msm_bedais[i].sample_rate;
acdb_dev_id =
- fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
- topology = msm_routing_get_adm_topology(path_type,
- fedai_id, session_type);
+ fe_dai_app_type_cfg[fedai_id][session_type][i]
+ .acdb_dev_id;
+ topology = msm_routing_get_adm_topology(fedai_id,
+ session_type,
+ i);
copp_idx = adm_open(msm_bedais[i].port_id, path_type,
sample_rate, channels, topology,
perf_mode, bits_per_sample,
@@ -1148,11 +1357,23 @@
payload.port_id[num_copps] =
msm_bedais[i].port_id;
payload.copp_idx[num_copps] = j;
+ payload.app_type[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][session_type]
+ [i].app_type;
+ payload.acdb_dev_id[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][session_type]
+ [i].acdb_dev_id;
+ payload.sample_rate[num_copps] =
+ fe_dai_app_type_cfg
+ [fedai_id][session_type]
+ [i].sample_rate;
num_copps++;
}
}
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,
@@ -1162,13 +1383,7 @@
if (num_copps) {
payload.num_copps = num_copps;
payload.session_id = fe_dai_map[fedai_id][session_type].strm_id;
- payload.app_type =
- fe_dai_app_type_cfg[fedai_id][session_type].app_type;
- payload.acdb_dev_id =
- fe_dai_app_type_cfg[fedai_id][session_type].acdb_dev_id;
- payload.sample_rate =
- fe_dai_app_type_cfg[fedai_id][session_type].sample_rate;
- adm_matrix_map(path_type, payload, perf_mode);
+ 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 +1412,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 +1433,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 +1458,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 +1475,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 +1493,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 +1521,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) {
@@ -1336,22 +1561,31 @@
msm_bedais[reg].format);
app_type =
- fe_dai_app_type_cfg[val][session_type].app_type;
- if (app_type) {
+ fe_dai_app_type_cfg[val][session_type][reg].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][reg]
+ .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 =
- fe_dai_app_type_cfg[val][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[val][session_type][reg]
+ .sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
sample_rate = msm_bedais[reg].sample_rate;
- topology = msm_routing_get_adm_topology(path_type, val,
- session_type);
+ topology = msm_routing_get_adm_topology(val,
+ session_type,
+ reg);
acdb_dev_id =
- fe_dai_app_type_cfg[val][session_type].acdb_dev_id;
+ fe_dai_app_type_cfg[val][session_type][reg].acdb_dev_id;
copp_idx = adm_open(msm_bedais[reg].port_id, path_type,
sample_rate, channels, topology,
fdai->perf_mode, bits_per_sample,
@@ -1382,20 +1616,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 +1654,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 +1677,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 +1713,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 +1774,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 +1835,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 +1879,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 +1904,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,
@@ -1645,6 +1924,68 @@
return 1;
}
+/*
+ * Return the mapping between port ID and backend ID to enable the AFE callback
+ * to determine the acdb_dev_id from the port id
+ */
+int msm_pcm_get_be_id_from_port_id(int port_id)
+{
+ int i;
+ int be_id = -EINVAL;
+
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ if (msm_bedais[i].port_id == port_id) {
+ be_id = i;
+ break;
+ }
+ }
+
+ return be_id;
+}
+
+/*
+ * Return the registered dev_acdb_id given a port ID to enable identifying the
+ * correct AFE calibration information by comparing the header information.
+ */
+static int msm_pcm_get_dev_acdb_id_by_port_id(int port_id)
+{
+ int acdb_id = -EINVAL;
+ int i = 0;
+ int session;
+ int port_type = afe_get_port_type(port_id);
+ int be_id = msm_pcm_get_be_id_from_port_id(port_id);
+
+ pr_debug("%s:port_id %d be_id %d, port_type 0x%x\n",
+ __func__, port_id, be_id, port_type);
+
+ if (port_type == MSM_AFE_PORT_TYPE_TX) {
+ session = SESSION_TYPE_TX;
+ } else if (port_type == MSM_AFE_PORT_TYPE_RX) {
+ session = SESSION_TYPE_RX;
+ } else {
+ pr_err("%s: Invalid port type %d\n", __func__, port_type);
+ acdb_id = -EINVAL;
+ goto exit;
+ }
+
+ if (be_id < 0) {
+ pr_err("%s: Error getting backend id %d\n", __func__, be_id);
+ goto exit;
+ }
+
+ mutex_lock(&routing_lock);
+ i = find_first_bit(&msm_bedais[be_id].fe_sessions[0],
+ MSM_FRONTEND_DAI_MAX);
+ if (i < MSM_FRONTEND_DAI_MAX)
+ acdb_id = fe_dai_app_type_cfg[i][session][be_id].acdb_dev_id;
+
+ pr_debug("%s: FE[%d] session[%d] BE[%d] acdb_id(%d)\n",
+ __func__, i, session, be_id, acdb_id);
+ mutex_unlock(&routing_lock);
+exit:
+ return acdb_id;
+}
+
static int msm_routing_get_switch_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1703,6 +2044,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 +2280,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 +2323,21 @@
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;
+ case 10:
+ lsm_port = AFE_PORT_ID_INT3_MI2S_TX;
+ break;
default:
pr_err("Default lsm port");
break;
}
set_lsm_port(lsm_port);
-
- if (ucontrol->value.integer.value[0]) {
- lsm_mux_slim_port = ucontrol->value.integer.value[0];
- snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e,
- update);
- } else {
- snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e,
- update);
- lsm_mux_slim_port = ucontrol->value.integer.value[0];
- }
+ lsm_port_index = ucontrol->value.integer.value[0];
return 0;
}
@@ -1921,22 +2350,31 @@
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])) {
- ucontrol->value.integer.value[0] = MADSWAUDIO;
- return 0;
- }
-
port_id = i * 2 + 1 + SLIMBUS_0_RX;
+
+ /*Check for Tertiary/Quaternary/INT3 TX port*/
+ if (strnstr(kcontrol->id.name, lsm_port_text[7],
+ strlen(lsm_port_text[7])))
+ port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+
+ if (strnstr(kcontrol->id.name, lsm_port_text[8],
+ strlen(lsm_port_text[8])))
+ port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX;
+
+ if (strnstr(kcontrol->id.name, lsm_port_text[10],
+ strlen(lsm_port_text[10])))
+ port_id = AFE_PORT_ID_INT3_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 +2409,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;
}
@@ -2002,11 +2441,18 @@
return -EINVAL;
}
- /*Check for Tertiary TX port*/
- if (!strcmp(kcontrol->id.name, mad_audio_mux_text[7])) {
+ /*Check for Tertiary/Quaternary/INT3 TX port*/
+ 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;
+
+ if (strnstr(kcontrol->id.name, lsm_port_text[10],
+ strlen(lsm_port_text[10])))
+ port_id = AFE_PORT_ID_INT3_MI2S_TX;
pr_debug("%s: port_id 0x%x, mad_type %d\n", __func__, port_id,
mad_type);
@@ -2172,6 +2618,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)
{
@@ -2189,10 +2773,10 @@
struct snd_soc_dapm_widget_list *wlist =
dapm_kcontrol_get_wlist(kcontrol);
struct snd_soc_dapm_widget *widget = wlist->widgets[0];
- int mux = ucontrol->value.enumerated.item[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
struct snd_soc_dapm_update *update = NULL;
+
mutex_lock(&routing_lock);
switch (ucontrol->value.integer.value[0]) {
case 0:
@@ -2271,6 +2855,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",
@@ -2282,7 +2878,8 @@
pr_debug("%s: msm_route_ec_ref_rx = %d\n",
__func__, msm_route_ec_ref_rx);
mutex_unlock(&routing_lock);
- snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, mux, e, update);
+ snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+ msm_route_ec_ref_rx, e, update);
return 0;
}
@@ -2291,7 +2888,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 +2974,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 +4664,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 +4919,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 +5697,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 +5784,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 +5889,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 +5964,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 +6069,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 +6171,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 +6264,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 +6320,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 +7198,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 +7469,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 +7765,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 +8087,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 +8117,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 +9228,222 @@
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),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_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),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_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),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_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),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_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),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_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),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_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),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_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),
+ SOC_SINGLE_EXT("INT3_MI2S_TX", MSM_BACKEND_DAI_INT3_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 +9474,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 +9519,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 +9554,35 @@
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),
+ SOC_ENUM_EXT(INT3_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 +9636,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 +9746,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 +9816,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 +9980,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]
@@ -8010,6 +10024,9 @@
} else if (!strcmp(kcontrol->id.name + strlen(prefix),
"TERT_MI2S")) {
*port_id = AFE_PORT_ID_TERTIARY_MI2S_TX;
+ } else if (!strcmp(kcontrol->id.name + strlen(prefix),
+ "INT3_MI2S")) {
+ *port_id = AFE_PORT_ID_INT3_MI2S_TX;
} else {
pr_err("%s: mixer ctl name=%s, could not derive valid port id\n",
__func__, kcontrol->id.name);
@@ -8214,6 +10231,36 @@
.info = msm_source_tracking_info,
.get = msm_audio_source_tracking_get,
},
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Sound Focus Voice Tx INT3_MI2S",
+ .info = msm_sound_focus_info,
+ .get = msm_voice_sound_focus_get,
+ .put = msm_voice_sound_focus_put,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Source Tracking Voice Tx INT3_MI2S",
+ .info = msm_source_tracking_info,
+ .get = msm_voice_source_tracking_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Sound Focus Audio Tx INT3_MI2S",
+ .info = msm_sound_focus_info,
+ .get = msm_audio_sound_focus_get,
+ .put = msm_audio_sound_focus_put,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Source Tracking Audio Tx INT3_MI2S",
+ .info = msm_source_tracking_info,
+ .get = msm_audio_source_tracking_get,
+ },
};
static int spkr_prot_put_vi_lch_port(struct snd_kcontrol *kcontrol,
@@ -8319,6 +10366,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 +10386,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 +10409,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 +10436,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 +10518,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 +10533,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 +10566,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 +11005,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 +11063,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 +11081,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 +11134,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 +11205,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 +11311,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 +11422,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 +11470,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 +11512,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),
@@ -9550,10 +11724,14 @@
{"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia2", "MM_DL2"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia3", "MM_DL3"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia4", "MM_DL4"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia6", "MM_DL6"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SLIMBUS_7_RX Audio Mixer", "MultiMedia9", "MM_DL9"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia10", "MM_DL10"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia11", "MM_DL11"},
{"SLIMBUS_7_RX Audio Mixer", "MultiMedia12", "MM_DL12"},
@@ -9604,6 +11782,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"},
@@ -9769,6 +11948,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"},
@@ -9805,6 +12038,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"},
@@ -9931,6 +12218,42 @@
{"QUAT_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
{"QUAT_TDM_RX_0", NULL, "QUAT_TDM_RX_0 Audio Mixer"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"PRI_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"PRI_TDM_RX_0", NULL, "PRI_TDM_RX_0 Audio Mixer"},
+
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia4", "MM_DL4"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia5", "MM_DL5"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia6", "MM_DL6"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia7", "MM_DL7"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia8", "MM_DL8"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia9", "MM_DL9"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia10", "MM_DL10"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia11", "MM_DL11"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia12", "MM_DL12"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia13", "MM_DL13"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia14", "MM_DL14"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia15", "MM_DL15"},
+ {"SEC_TDM_RX_0 Audio Mixer", "MultiMedia16", "MM_DL16"},
+ {"SEC_TDM_RX_0", NULL, "SEC_TDM_RX_0 Audio Mixer"},
+
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia1", "MM_DL1"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia2", "MM_DL2"},
{"QUAT_TDM_TX_0 Audio Mixer", "MultiMedia3", "MM_DL3"},
@@ -10033,6 +12356,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"},
@@ -10050,6 +12375,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"},
@@ -10059,6 +12392,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"},
@@ -10068,6 +12409,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"},
@@ -10077,6 +12426,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"},
@@ -10086,6 +12443,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"},
@@ -10095,6 +12460,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"},
@@ -10104,6 +12477,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"},
@@ -10113,6 +12494,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"},
@@ -10227,6 +12617,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"},
@@ -10551,6 +12942,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"},
@@ -10716,6 +13110,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"},
@@ -10768,70 +13163,81 @@
{"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"},
+ {"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 Mixer", "INT3_MI2S_TX", "INT3_MI2S_TX"},
+ {"LSM1_UL_HL", NULL, "LSM1 Mixer"},
- {"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"},
+ {"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 Mixer", "INT3_MI2S_TX", "INT3_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 Mixer", "INT3_MI2S_TX", "INT3_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 Mixer", "INT3_MI2S_TX", "INT3_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 Mixer", "INT3_MI2S_TX", "INT3_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"},
@@ -10860,13 +13266,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"},
@@ -10880,26 +13290,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"},
@@ -10909,6 +13333,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"},
@@ -11053,6 +13621,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"},
@@ -11072,6 +13662,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"},
@@ -11300,7 +13896,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"},
@@ -11318,6 +13920,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" },
@@ -11346,11 +13949,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"},
@@ -11408,7 +14021,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;
@@ -11429,13 +14044,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;
@@ -11455,6 +14069,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);
@@ -11467,7 +14082,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;
@@ -11488,7 +14103,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;
@@ -11510,13 +14131,21 @@
bedai->format);
app_type =
- fe_dai_app_type_cfg[i][session_type].app_type;
- if (app_type) {
+ fe_dai_app_type_cfg[i][session_type][be_id].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][be_id]
+ .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 =
- fe_dai_app_type_cfg[i][session_type].
- sample_rate;
+ fe_dai_app_type_cfg[i][session_type]
+ [be_id].sample_rate;
bits_per_sample =
app_type_cfg[app_type_idx].bit_width;
} else
@@ -11530,9 +14159,9 @@
else
channels = bedai->adm_override_ch;
acdb_dev_id =
- fe_dai_app_type_cfg[i][session_type].acdb_dev_id;
- topology = msm_routing_get_adm_topology(path_type, i,
- session_type);
+ fe_dai_app_type_cfg[i][session_type][be_id].acdb_dev_id;
+ topology = msm_routing_get_adm_topology(i, session_type,
+ be_id);
copp_idx = adm_open(bedai->port_id, path_type,
sample_rate, channels, topology,
fdai->perf_mode, bits_per_sample,
@@ -11556,16 +14185,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__,
@@ -11630,6 +14259,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);
@@ -11666,14 +14296,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);
@@ -11683,9 +14315,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);
@@ -11701,6 +14331,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);
@@ -11725,7 +14356,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 =
@@ -11739,7 +14374,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__);
@@ -11747,9 +14382,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;
@@ -11761,9 +14394,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;
@@ -11790,6 +14421,92 @@
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 int msm_routing_be_dai_name_table_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = sizeof(be_dai_name_table);
+ return 0;
+}
+
+static int msm_routing_be_dai_name_table_tlv_get(struct snd_kcontrol *kcontrol,
+ unsigned int __user *bytes,
+ unsigned int size)
+{
+ int i;
+ int ret;
+
+ if (size < sizeof(be_dai_name_table)) {
+ pr_err("%s: invalid size %d requested, returning\n",
+ __func__, size);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * Fill be_dai_name_table from msm_bedais table to reduce code changes
+ * needed when adding new backends
+ */
+ for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+ be_dai_name_table[i].be_id = i;
+ strlcpy(be_dai_name_table[i].be_name,
+ msm_bedais[i].name,
+ LPASS_BE_NAME_MAX_LENGTH);
+ }
+
+ ret = copy_to_user(bytes, &be_dai_name_table,
+ sizeof(be_dai_name_table));
+ if (ret) {
+ pr_err("%s: failed to copy be_dai_name_table\n", __func__);
+ ret = -EFAULT;
+ }
+
+done:
+ return ret;
+}
+
+static const struct snd_kcontrol_new
+ msm_routing_be_dai_name_table_mixer_controls[] = {
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
+ .info = msm_routing_be_dai_name_table_info,
+ .name = "Backend DAI Name Table",
+ .tlv.c = snd_soc_bytes_tlv_callback,
+ .private_value = (unsigned long) &(struct soc_bytes_ext) {
+ .max = sizeof(be_dai_name_table),
+ .get = msm_routing_be_dai_name_table_tlv_get,
+ }
+ },
+};
+
static const struct snd_pcm_ops msm_routing_pcm_ops = {
.hw_params = msm_pcm_routing_hw_params,
.close = msm_pcm_routing_close,
@@ -11806,8 +14523,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));
@@ -11818,10 +14535,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);
@@ -11836,12 +14559,19 @@
device_pp_params_mixer_controls,
ARRAY_SIZE(device_pp_params_mixer_controls));
+ snd_soc_add_platform_controls(platform,
+ msm_routing_be_dai_name_table_mixer_controls,
+ ARRAY_SIZE(msm_routing_be_dai_name_table_mixer_controls));
+
msm_dts_eagle_add_controls(platform);
snd_soc_add_platform_controls(platform, msm_source_tracking_controls,
ARRAY_SIZE(msm_source_tracking_controls));
snd_soc_add_platform_controls(platform, adm_channel_config_controls,
ARRAY_SIZE(adm_channel_config_controls));
+
+ snd_soc_add_platform_controls(platform, aptx_dec_license_controls,
+ ARRAY_SIZE(aptx_dec_license_controls));
return 0;
}
@@ -11902,21 +14632,12 @@
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;
}
-static int get_cal_path(int path_type)
-{
- if (path_type == ADM_PATH_PLAYBACK ||
- path_type == ADM_PATH_COMPRESSED_RX)
- return RX_DEVICE;
- else
- return TX_DEVICE;
-}
-
static int msm_routing_set_cal(int32_t cal_type,
size_t data_size, void *data)
{
@@ -11974,6 +14695,11 @@
if (msm_routing_init_cal_data())
pr_err("%s: could not init cal data!\n", __func__);
+ afe_set_routing_callback(
+ (routing_cb)msm_pcm_get_dev_acdb_id_by_port_id);
+
+ memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
+
return platform_driver_register(&msm_routing_pcm_driver);
}
module_init(msm_soc_routing_platform_init);
@@ -11981,6 +14707,8 @@
static void __exit msm_soc_routing_platform_exit(void)
{
msm_routing_delete_cal_data();
+ memset(&be_dai_name_table, 0, sizeof(be_dai_name_table));
+ mutex_destroy(&routing_lock);
platform_driver_unregister(&msm_routing_pcm_driver);
}
module_exit(msm_soc_routing_platform_exit);
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.h
index d64fd64..fcd155e 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
@@ -13,6 +13,12 @@
#define _MSM_PCM_ROUTING_H
#include <sound/apr_audio-v2.h>
+/*
+ * These names are used by HAL to specify the BE. If any changes are
+ * made to the string names or the max name length corresponding
+ * changes need to be made in the HAL to ensure they still match.
+ */
+#define LPASS_BE_NAME_MAX_LENGTH 24
#define LPASS_BE_PRI_I2S_RX "PRIMARY_I2S_RX"
#define LPASS_BE_PRI_I2S_TX "PRIMARY_I2S_TX"
#define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX"
@@ -64,6 +70,7 @@
#define LPASS_BE_SLIMBUS_3_TX "SLIMBUS_3_TX"
#define LPASS_BE_SLIMBUS_4_RX "SLIMBUS_4_RX"
#define LPASS_BE_SLIMBUS_4_TX "SLIMBUS_4_TX"
+#define LPASS_BE_SLIMBUS_TX_VI "SLIMBUS_TX_VI"
#define LPASS_BE_SLIMBUS_5_RX "SLIMBUS_5_RX"
#define LPASS_BE_SLIMBUS_5_TX "SLIMBUS_5_TX"
#define LPASS_BE_SLIMBUS_6_RX "SLIMBUS_6_RX"
@@ -390,6 +397,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 +407,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 +423,7 @@
unsigned int channel;
unsigned int format;
unsigned int adm_override_ch;
- u32 compr_passthr_mode;
+ u32 passthr_mode;
char *name;
};
@@ -465,8 +475,10 @@
void msm_pcm_routing_acquire_lock(void);
void msm_pcm_routing_release_lock(void);
-void msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int app_type,
- int acdb_dev_id, int sample_rate, int session_type);
+int msm_pcm_routing_reg_stream_app_type_cfg(int fedai_id, int session_type,
+ int be_id, int app_type,
+ int acdb_dev_id, int sample_rate);
int msm_pcm_routing_get_stream_app_type_cfg(int fedai_id, int session_type,
- int *app_type, int *acdb_dev_id, int *sample_rate);
+ int be_id, int *app_type,
+ int *acdb_dev_id, int *sample_rate);
#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voice-v2.c
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-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 1a739a4..02225f0 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -815,20 +815,25 @@
if (prtd->mode == MODE_PCM) {
ret = copy_from_user(&buf_node->frame.voc_pkt,
buf, count);
+ if (ret) {
+ pr_err("%s: copy from user failed %d\n",
+ __func__, ret);
+ return -EFAULT;
+ }
buf_node->frame.pktlen = count;
} else {
ret = copy_from_user(&buf_node->frame,
buf, count);
+ if (ret) {
+ pr_err("%s: copy from user failed %d\n",
+ __func__, ret);
+ return -EFAULT;
+ }
if (buf_node->frame.pktlen >= count)
buf_node->frame.pktlen = count -
(sizeof(buf_node->frame.frm_hdr) +
sizeof(buf_node->frame.pktlen));
}
- if (ret) {
- pr_err("%s: copy from user failed %d\n",
- __func__, ret);
- return -EFAULT;
- }
spin_lock_irqsave(&prtd->dsp_lock, dsp_flags);
list_add_tail(&buf_node->list, &prtd->in_queue);
spin_unlock_irqrestore(&prtd->dsp_lock, dsp_flags);
diff --git a/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c b/sound/soc/msm/qdsp6v2/msm-qti-pp-config.c
index 9276231..c60b27f 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;
@@ -399,6 +405,7 @@
static int msm_afe_sec_mi2s_lb_vol_ctrl;
static int msm_afe_tert_mi2s_lb_vol_ctrl;
static int msm_afe_quat_mi2s_lb_vol_ctrl;
+static int msm_afe_slimbus_7_lb_vol_ctrl;
static int msm_afe_slimbus_8_lb_vol_ctrl;
static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
static const DECLARE_TLV_DB_LINEAR(afe_lb_vol_gain, 0, INT_RX_VOL_MAX_STEPS);
@@ -471,6 +478,29 @@
return 0;
}
+static int msm_qti_pp_get_slimbus_7_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm_afe_slimbus_7_lb_vol_ctrl;
+ return 0;
+}
+
+static int msm_qti_pp_set_slimbus_7_lb_vol_mixer(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = afe_loopback_gain(SLIMBUS_7_TX,
+ ucontrol->value.integer.value[0]);
+
+ if (ret)
+ pr_err("%s: failed to set LB vol for SLIMBUS_7_TX, err %d\n",
+ __func__, ret);
+ else
+ msm_afe_slimbus_7_lb_vol_ctrl =
+ ucontrol->value.integer.value[0];
+
+ return ret;
+}
+
static int msm_qti_pp_get_slimbus_8_lb_vol_mixer(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -495,6 +525,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 +628,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 +821,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,
@@ -801,6 +885,14 @@
msm_qti_pp_set_tert_mi2s_lb_vol_mixer, afe_lb_vol_gain),
};
+static const struct snd_kcontrol_new slimbus_7_lb_vol_mixer_controls[] = {
+ SOC_SINGLE_EXT_TLV("SLIMBUS_7 LOOPBACK Volume", SND_SOC_NOPM, 0,
+ INT_RX_VOL_GAIN, 0,
+ msm_qti_pp_get_slimbus_7_lb_vol_mixer,
+ msm_qti_pp_set_slimbus_7_lb_vol_mixer,
+ afe_lb_vol_gain),
+};
+
static const struct snd_kcontrol_new slimbus_8_lb_vol_mixer_controls[] = {
SOC_SINGLE_EXT_TLV("SLIMBUS_8 LOOPBACK Volume", SND_SOC_NOPM, 0,
INT_RX_VOL_GAIN, 0, msm_qti_pp_get_slimbus_8_lb_vol_mixer,
@@ -813,6 +905,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,
@@ -999,12 +1097,18 @@
snd_soc_add_platform_controls(platform, tert_mi2s_lb_vol_mixer_controls,
ARRAY_SIZE(tert_mi2s_lb_vol_mixer_controls));
+ snd_soc_add_platform_controls(platform, slimbus_7_lb_vol_mixer_controls,
+ ARRAY_SIZE(slimbus_7_lb_vol_mixer_controls));
+
snd_soc_add_platform_controls(platform, slimbus_8_lb_vol_mixer_controls,
ARRAY_SIZE(slimbus_8_lb_vol_mixer_controls));
snd_soc_add_platform_controls(platform, int_hfp_vol_mixer_controls,
ARRAY_SIZE(int_hfp_vol_mixer_controls));
+ snd_soc_add_platform_controls(platform, 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 +1135,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..90d640d 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;
@@ -2711,8 +2833,8 @@
[port_idx][copp_idx]),
get_cal_path(path),
payload_map.session_id,
- payload_map.app_type,
- payload_map.acdb_dev_id);
+ payload_map.app_type[i],
+ payload_map.acdb_dev_id[i]);
if (!test_bit(ADM_STATUS_CALIBRATION_REQUIRED,
(void *)&this_adm.copp.adm_status[port_idx]
@@ -2723,9 +2845,9 @@
}
send_adm_cal(payload_map.port_id[i], copp_idx,
get_cal_path(path), perf_mode,
- payload_map.app_type,
- payload_map.acdb_dev_id,
- payload_map.sample_rate);
+ payload_map.app_type[i],
+ payload_map.acdb_dev_id[i],
+ payload_map.sample_rate[i]);
/* ADM COPP calibration is already sent */
clear_bit(ADM_STATUS_CALIBRATION_REQUIRED,
(void *)&this_adm.copp.
@@ -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..176b8aa 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,
@@ -112,12 +113,15 @@
struct audio_cal_info_sp_ex_vi_ftm_cfg ex_ftm_cfg;
struct afe_sp_th_vi_get_param_resp th_vi_resp;
struct afe_sp_ex_vi_get_param_resp ex_vi_resp;
+ struct afe_av_dev_drift_get_param_resp av_dev_drift_resp;
int vi_tx_port;
int vi_rx_port;
uint32_t afe_sample_rates[AFE_MAX_PORTS];
struct aanc_data aanc_info;
struct mutex afe_cmd_lock;
int set_custom_topology;
+ int dev_acdb_id[AFE_MAX_PORTS];
+ routing_cb rt_cb;
};
static atomic_t afe_ports_mad_type[SLIMBUS_PORT_LAST - SLIMBUS_0_RX];
@@ -144,7 +148,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;
@@ -187,6 +191,38 @@
__func__, data->opcode, data->payload_size);
}
+static void av_dev_drift_afe_cb_handler(uint32_t *payload,
+ uint32_t payload_size)
+{
+ u32 param_id;
+ struct afe_av_dev_drift_get_param_resp *resp =
+ (struct afe_av_dev_drift_get_param_resp *) payload;
+
+ if (!(&(resp->pdata))) {
+ pr_err("%s: Error: resp pdata is NULL\n", __func__);
+ return;
+ }
+
+ param_id = resp->pdata.param_id;
+ if (param_id == AFE_PARAM_ID_DEV_TIMING_STATS) {
+ if (payload_size < sizeof(this_afe.av_dev_drift_resp)) {
+ pr_err("%s: Error: received size %d, resp size %zu\n",
+ __func__, payload_size,
+ sizeof(this_afe.av_dev_drift_resp));
+ return;
+ }
+ memcpy(&this_afe.av_dev_drift_resp, payload,
+ sizeof(this_afe.av_dev_drift_resp));
+ if (!this_afe.av_dev_drift_resp.status) {
+ atomic_set(&this_afe.state, 0);
+ } else {
+ pr_debug("%s: av_dev_drift_resp status: %d", __func__,
+ this_afe.av_dev_drift_resp.status);
+ atomic_set(&this_afe.state, -1);
+ }
+ }
+}
+
static int32_t sp_make_afe_callback(uint32_t *payload, uint32_t payload_size)
{
u32 param_id;
@@ -272,6 +308,7 @@
mutex_lock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
this_afe.set_custom_topology = 1;
mutex_unlock(&this_afe.cal_data[AFE_CUST_TOPOLOGY_CAL]->lock);
+ rtac_clear_mapping(AFE_RTAC_CAL);
if (this_afe.apr) {
apr_reset(this_afe.apr);
@@ -306,10 +343,7 @@
}
afe_callback_debug_print(data);
if (data->opcode == AFE_PORT_CMDRSP_GET_PARAM_V2) {
- u8 *payload = data->payload;
-
- if (rtac_make_afe_callback(data->payload, data->payload_size))
- return 0;
+ uint32_t *payload = data->payload;
if (!payload || (data->token >= AFE_MAX_PORTS)) {
pr_err("%s: Error: size %d payload %pK token %d\n",
@@ -317,9 +351,19 @@
payload, data->token);
return -EINVAL;
}
- if (sp_make_afe_callback(data->payload, data->payload_size))
- return -EINVAL;
+ if (payload[2] == AFE_PARAM_ID_DEV_TIMING_STATS) {
+ av_dev_drift_afe_cb_handler(data->payload,
+ data->payload_size);
+ } else {
+ if (rtac_make_afe_callback(data->payload,
+ data->payload_size))
+ return 0;
+
+ if (sp_make_afe_callback(data->payload,
+ data->payload_size))
+ return -EINVAL;
+ }
wake_up(&this_afe.wait[data->token]);
} else if (data->payload_size) {
uint32_t *payload;
@@ -726,7 +770,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 +914,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 +995,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;
@@ -1179,6 +1223,7 @@
pr_debug("%s:\n", __func__);
+ memset(&delay_entry, 0, sizeof(delay_entry));
delay_entry.sample_rate = rate;
if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
ret = afe_get_cal_hw_delay(TX_DEVICE, &delay_entry);
@@ -1197,7 +1242,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;
@@ -1246,6 +1291,10 @@
struct cal_block_data *cal_block = NULL;
int32_t path;
struct audio_cal_info_afe_top *afe_top;
+ int afe_port_index = q6audio_get_port_index(port_id);
+
+ if (afe_port_index < 0)
+ goto err_exit;
list_for_each_safe(ptr, next,
&cal_type->cal_blocks) {
@@ -1257,12 +1306,25 @@
afe_top =
(struct audio_cal_info_afe_top *)cal_block->cal_info;
if (afe_top->path == path) {
- pr_debug("%s: top_id:%x acdb_id:%d afe_port:%d\n",
- __func__, afe_top->topology, afe_top->acdb_id,
- q6audio_get_port_id(port_id));
- return cal_block;
+ if (this_afe.dev_acdb_id[afe_port_index] > 0) {
+ if (afe_top->acdb_id ==
+ this_afe.dev_acdb_id[afe_port_index]) {
+ pr_debug("%s: top_id:%x acdb_id:%d afe_port_id:%d\n",
+ __func__, afe_top->topology,
+ afe_top->acdb_id,
+ q6audio_get_port_id(port_id));
+ return cal_block;
+ }
+ } else {
+ pr_debug("%s: top_id:%x acdb_id:%d afe_port:%d\n",
+ __func__, afe_top->topology, afe_top->acdb_id,
+ q6audio_get_port_id(port_id));
+ return cal_block;
+ }
}
}
+
+err_exit:
return NULL;
}
@@ -1319,7 +1381,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;
@@ -1365,6 +1427,7 @@
}
this_afe.topology[index] = topology_id;
+ rtac_update_afe_topology(port_id);
done:
pr_debug("%s: AFE set topology id 0x%x enable for port 0x%x ret %d\n",
__func__, topology_id, port_id, ret);
@@ -1406,10 +1469,46 @@
return ret;
}
+static struct cal_block_data *afe_find_cal(int cal_index, int port_id)
+{
+ struct list_head *ptr, *next;
+ struct cal_block_data *cal_block = NULL;
+ struct audio_cal_info_afe *afe_cal_info = NULL;
+ int afe_port_index = q6audio_get_port_index(port_id);
+
+ pr_debug("%s: cal_index %d port_id %d port_index %d\n", __func__,
+ cal_index, port_id, afe_port_index);
+ if (afe_port_index < 0) {
+ pr_err("%s: Error getting AFE port index %d\n",
+ __func__, afe_port_index);
+ goto exit;
+ }
+
+ list_for_each_safe(ptr, next,
+ &this_afe.cal_data[cal_index]->cal_blocks) {
+ cal_block = list_entry(ptr, struct cal_block_data, list);
+ afe_cal_info = cal_block->cal_info;
+ if ((afe_cal_info->acdb_id ==
+ this_afe.dev_acdb_id[afe_port_index]) &&
+ (afe_cal_info->sample_rate ==
+ this_afe.afe_sample_rates[afe_port_index])) {
+ pr_debug("%s: cal block is a match, size is %zd\n",
+ __func__, cal_block->cal_data.size);
+ goto exit;
+ }
+ }
+ pr_err("%s: no matching cal_block found\n", __func__);
+ cal_block = NULL;
+
+exit:
+ return cal_block;
+}
+
static void send_afe_cal_type(int cal_index, int port_id)
{
struct cal_block_data *cal_block = NULL;
int ret;
+ int afe_port_index = q6audio_get_port_index(port_id);
pr_debug("%s:\n", __func__);
@@ -1419,8 +1518,22 @@
goto done;
}
+ if (afe_port_index < 0) {
+ pr_err("%s: Error getting AFE port index %d\n",
+ __func__, afe_port_index);
+ goto done;
+ }
+
mutex_lock(&this_afe.cal_data[cal_index]->lock);
- cal_block = cal_utils_get_only_cal_block(this_afe.cal_data[cal_index]);
+
+ if (((cal_index == AFE_COMMON_RX_CAL) ||
+ (cal_index == AFE_COMMON_TX_CAL)) &&
+ (this_afe.dev_acdb_id[afe_port_index] > 0))
+ cal_block = afe_find_cal(cal_index, port_id);
+ else
+ cal_block = cal_utils_get_only_cal_block(
+ this_afe.cal_data[cal_index]);
+
if (cal_block == NULL) {
pr_err("%s cal_block not found!!\n", __func__);
goto unlock;
@@ -1677,7 +1790,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 +1844,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 +1929,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;
@@ -1932,7 +2045,8 @@
{
int i;
- if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX) {
+ if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX ||
+ port_id == AFE_PORT_ID_INT3_MI2S_TX) {
mad_type = MAD_SW_AUDIO;
return 0;
}
@@ -1950,7 +2064,8 @@
{
int i;
- if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX)
+ if (port_id == AFE_PORT_ID_TERTIARY_MI2S_TX ||
+ port_id == AFE_PORT_ID_INT3_MI2S_TX)
return MAD_SW_AUDIO;
i = port_id - SLIMBUS_0_RX;
@@ -2039,7 +2154,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 +2240,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 +2314,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 +2385,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 +2460,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 +2539,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;
@@ -2488,7 +2603,7 @@
}
int afe_tdm_port_start(u16 port_id, struct afe_tdm_port_config *tdm_port,
- u32 rate)
+ u32 rate, u16 num_groups)
{
struct afe_audioif_config_command config;
int ret = 0;
@@ -2504,7 +2619,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;
@@ -2521,9 +2636,17 @@
return ret;
}
- /* Also send the topology id here: */
+ if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[index] = rate;
+
+ if (this_afe.rt_cb)
+ this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+ }
+
+ /* Also send the topology id here if multiple ports: */
port_index = afe_get_port_index(port_id);
- if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE)) {
+ if (!(this_afe.afe_cal_mode[port_index] == AFE_CAL_MODE_NONE) &&
+ num_groups > 1) {
/* One time call: only for first time */
afe_send_custom_topology();
afe_send_port_topology_id(port_id);
@@ -2585,11 +2708,14 @@
ret = -EINVAL;
goto fail_cmd;
}
-
- ret = afe_send_slot_mapping_cfg(&tdm_port->slot_mapping, port_id);
- if (ret < 0) {
- pr_err("%s: afe send failed %d\n", __func__, ret);
- goto fail_cmd;
+ /* slot mapping is not need if there is only one group */
+ if (num_groups > 1) {
+ ret = afe_send_slot_mapping_cfg(&tdm_port->slot_mapping,
+ port_id);
+ if (ret < 0) {
+ pr_err("%s: afe send failed %d\n", __func__, ret);
+ goto fail_cmd;
+ }
}
if (tdm_port->custom_tdm_header.header_type) {
@@ -2615,6 +2741,11 @@
this_afe.afe_cal_mode[port_index] = afe_cal_mode;
}
+void afe_set_routing_callback(routing_cb cb)
+{
+ this_afe.rt_cb = cb;
+}
+
int afe_port_send_usb_dev_param(u16 port_id, union afe_port_config *afe_config)
{
struct afe_usb_audio_dev_param_command config;
@@ -2626,7 +2757,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;
@@ -2660,6 +2791,21 @@
ret = -EINVAL;
goto exit;
}
+
+ config.pdata.param_id = AFE_PARAM_ID_USB_AUDIO_DEV_LPCM_FMT;
+ config.pdata.param_size = sizeof(config.lpcm_fmt);
+ config.lpcm_fmt.cfg_minor_version =
+ AFE_API_MINIOR_VERSION_USB_AUDIO_CONFIG;
+ config.lpcm_fmt.endian = afe_config->usb_audio.endian;
+
+ ret = afe_apr_send_pkt(&config, &this_afe.wait[index]);
+ if (ret) {
+ pr_err("%s: AFE device param cmd LPCM_FMT failed %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+
exit:
return ret;
}
@@ -2683,6 +2829,11 @@
}
memset(&config, 0, sizeof(config));
index = q6audio_get_port_index(port_id);
+ if (index < 0) {
+ pr_err("%s: Invalid index number: %d\n", __func__, index);
+ return -EINVAL;
+ }
+
config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
config.hdr.pkt_size = sizeof(config);
@@ -2820,7 +2971,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;
@@ -2837,6 +2988,13 @@
return ret;
}
+ if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[index] = rate;
+
+ if (this_afe.rt_cb)
+ this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+ }
+
mutex_lock(&this_afe.afe_cmd_lock);
/* Also send the topology id here: */
port_index = afe_get_port_index(port_id);
@@ -2934,6 +3092,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:
@@ -3026,7 +3198,6 @@
port_index = afe_get_port_index(port_id);
if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
- this_afe.afe_sample_rates[port_index] = rate;
/*
* If afe_port_start() for tx port called before
* rx port, then aanc rx sample rate is zero. So,
@@ -3311,6 +3482,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 +3534,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;
@@ -3360,6 +3559,14 @@
pr_err("%s: Q6 interface prepare failed %d\n", __func__, ret);
return -EINVAL;
}
+
+ if ((index >= 0) && (index < AFE_MAX_PORTS)) {
+ this_afe.afe_sample_rates[index] = rate;
+
+ if (this_afe.rt_cb)
+ this_afe.dev_acdb_id[index] = this_afe.rt_cb(port_id);
+ }
+
/* Also send the topology id here: */
afe_send_custom_topology(); /* One time call: only for first time */
afe_send_port_topology_id(port_id);
@@ -3503,7 +3710,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 +3776,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 +3879,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 +3922,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 +4083,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 +4369,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 +4633,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 +4973,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 +5002,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 +5377,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 +5511,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;
@@ -5130,6 +5542,7 @@
if ((port_index >= 0) && (port_index < AFE_MAX_PORTS)) {
this_afe.afe_sample_rates[port_index] = 0;
this_afe.topology[port_index] = 0;
+ this_afe.dev_acdb_id[port_index] = 0;
} else {
pr_err("%s: port %d\n", __func__, port_index);
ret = -EINVAL;
@@ -5257,7 +5670,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 +5836,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 +5869,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 +5950,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;
@@ -5798,6 +6211,88 @@
return ret;
}
+int afe_get_av_dev_drift(struct afe_param_id_dev_timing_stats *timing_stats,
+ u16 port)
+{
+ int ret = -EINVAL;
+ int index = 0;
+ struct afe_av_dev_drift_get_param av_dev_drift;
+
+ if (!timing_stats) {
+ pr_err("%s: Invalid params\n", __func__);
+ goto exit;
+ }
+
+ ret = q6audio_validate_port(port);
+ if (ret < 0) {
+ pr_err("%s: invalid port 0x%x ret %d\n", __func__, port, ret);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ index = q6audio_get_port_index(port);
+ if (index < 0 || index >= AFE_MAX_PORTS) {
+ pr_err("%s: Invalid AFE port index[%d]\n",
+ __func__, index);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ memset(&av_dev_drift, 0, sizeof(struct afe_av_dev_drift_get_param));
+
+ av_dev_drift.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+ av_dev_drift.hdr.pkt_size = sizeof(av_dev_drift);
+ av_dev_drift.hdr.src_port = 0;
+ av_dev_drift.hdr.dest_port = 0;
+ av_dev_drift.hdr.token = index;
+ av_dev_drift.hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2;
+ av_dev_drift.get_param.mem_map_handle = 0;
+ av_dev_drift.get_param.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ av_dev_drift.get_param.param_id = AFE_PARAM_ID_DEV_TIMING_STATS;
+ av_dev_drift.get_param.payload_address_lsw = 0;
+ av_dev_drift.get_param.payload_address_msw = 0;
+ av_dev_drift.get_param.payload_size = sizeof(av_dev_drift)
+ - sizeof(av_dev_drift.get_param) - sizeof(av_dev_drift.hdr);
+ av_dev_drift.get_param.port_id = q6audio_get_port_id(port);
+ av_dev_drift.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE;
+ av_dev_drift.pdata.param_id = AFE_PARAM_ID_DEV_TIMING_STATS;
+ av_dev_drift.pdata.param_size = sizeof(av_dev_drift.timing_stats);
+ atomic_set(&this_afe.status, 0);
+ atomic_set(&this_afe.state, 1);
+ ret = apr_send_pkt(this_afe.apr, (uint32_t *)&av_dev_drift);
+ if (ret < 0) {
+ pr_err("%s: get param port 0x%x param id[0x%x] failed %d\n",
+ __func__, port, av_dev_drift.get_param.param_id, ret);
+ goto exit;
+ }
+
+ ret = wait_event_timeout(this_afe.wait[index],
+ (atomic_read(&this_afe.state) == 0),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (atomic_read(&this_afe.status) > 0) {
+ pr_err("%s: config cmd failed [%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&this_afe.status)));
+ ret = adsp_err_get_lnx_err_code(
+ atomic_read(&this_afe.status));
+ goto exit;
+ }
+
+ memcpy(timing_stats, &this_afe.av_dev_drift_resp.timing_stats,
+ sizeof(this_afe.av_dev_drift_resp.timing_stats));
+ ret = 0;
+exit:
+ return ret;
+}
+
int afe_spk_prot_get_calib_data(struct afe_spkr_prot_get_vi_calib *calib_resp)
{
int ret = -EINVAL;
@@ -5817,7 +6312,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 +6441,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 +6974,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} },
@@ -6605,6 +7108,8 @@
mutex_init(&this_afe.afe_cmd_lock);
for (i = 0; i < AFE_MAX_PORTS; i++) {
this_afe.afe_cal_mode[i] = AFE_CAL_MODE_DEFAULT;
+ this_afe.afe_sample_rates[i] = 0;
+ this_afe.dev_acdb_id[i] = 0;
init_waitqueue_head(&this_afe.wait[i]);
}
wakeup_source_init(&wl.ws, "spkr-prot");
diff --git a/sound/soc/msm/qdsp6v2/q6asm.c b/sound/soc/msm/qdsp6v2/q6asm.c
index 78f70be..b52c83b 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);
@@ -2478,6 +2480,10 @@
case FORMAT_DSD:
open.fmt_id = ASM_MEDIA_FMT_DSD;
break;
+ case FORMAT_GEN_COMPR:
+ open.fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
+ break;
+
default:
pr_err("%s: Invalid format[%d]\n", __func__, format);
rc = -EINVAL;
@@ -2487,7 +2493,8 @@
* stream is not IEC 61937 or IEC 60958 packetizied
*/
if (passthrough_flag == COMPRESSED_PASSTHROUGH ||
- passthrough_flag == COMPRESSED_PASSTHROUGH_DSD) {
+ passthrough_flag == COMPRESSED_PASSTHROUGH_DSD ||
+ passthrough_flag == COMPRESSED_PASSTHROUGH_GEN) {
open.flags = 0x0;
pr_debug("%s: Flag 0 COMPRESSED_PASSTHROUGH\n", __func__);
} else if (passthrough_flag == COMPRESSED_PASSTHROUGH_CONVERT) {
@@ -2651,6 +2658,12 @@
case FORMAT_DSD:
open.dec_fmt_id = ASM_MEDIA_FMT_DSD;
break;
+ case FORMAT_APTX:
+ open.dec_fmt_id = ASM_MEDIA_FMT_APTX;
+ break;
+ case FORMAT_GEN_COMPR:
+ open.dec_fmt_id = ASM_MEDIA_FMT_GENERIC_COMPRESSED;
+ break;
default:
pr_err("%s: Invalid format 0x%x\n", __func__, format);
rc = -EINVAL;
@@ -2868,6 +2881,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 +2987,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 +2998,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) {
@@ -5141,6 +5192,82 @@
}
EXPORT_SYMBOL(q6asm_media_format_block_multi_ch_pcm_v4);
+/*
+ * q6asm_media_format_block_gen_compr - set up generic compress format params
+ *
+ * @ac: Client session handle
+ * @rate: sample rate
+ * @channels: number of channels
+ * @use_default_chmap: true if default channel map to be used
+ * @channel_map: input channel map
+ * @bits_per_sample: bit width of gen compress stream
+ */
+int q6asm_media_format_block_gen_compr(struct audio_client *ac,
+ uint32_t rate, uint32_t channels,
+ bool use_default_chmap, char *channel_map,
+ uint16_t bits_per_sample)
+{
+ struct asm_generic_compressed_fmt_blk_t fmt;
+ u8 *channel_mapping;
+ int rc = 0;
+
+ pr_debug("%s: session[%d]rate[%d]ch[%d]bps[%d]\n",
+ __func__, ac->session, rate,
+ channels, bits_per_sample);
+
+ memset(&fmt, 0, sizeof(fmt));
+ q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+ fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2;
+ fmt.fmt_blk.fmt_blk_size = sizeof(fmt) - sizeof(fmt.hdr) -
+ sizeof(fmt.fmt_blk);
+ fmt.num_channels = channels;
+ fmt.bits_per_sample = bits_per_sample;
+ fmt.sampling_rate = rate;
+
+ channel_mapping = fmt.channel_mapping;
+
+ memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+ if (use_default_chmap) {
+ if (q6asm_map_channels(channel_mapping, channels, false)) {
+ pr_err("%s: map channels failed %d\n",
+ __func__, channels);
+ return -EINVAL;
+ }
+ } else {
+ memcpy(channel_mapping, channel_map,
+ PCM_FORMAT_MAX_NUM_CHANNEL);
+ }
+
+ atomic_set(&ac->cmd_state, -1);
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+ if (rc < 0) {
+ pr_err("%s: Comamnd open failed %d\n", __func__, rc);
+ rc = -EINVAL;
+ goto fail_cmd;
+ }
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout. waited for format update\n", __func__);
+ rc = -ETIMEDOUT;
+ goto fail_cmd;
+ }
+
+ if (atomic_read(&ac->cmd_state) > 0) {
+ pr_err("%s: DSP returned error[%s]\n",
+ __func__, adsp_err_get_err_str(
+ atomic_read(&ac->cmd_state)));
+ rc = adsp_err_get_lnx_err_code(
+ atomic_read(&ac->cmd_state));
+ }
+ return 0;
+fail_cmd:
+ return rc;
+}
+EXPORT_SYMBOL(q6asm_media_format_block_gen_compr);
+
static int __q6asm_media_format_block_multi_aac(struct audio_client *ac,
struct asm_aac_cfg *cfg, int stream_id)
{
@@ -5727,6 +5854,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 +6924,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 +7428,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];
@@ -7208,9 +7449,13 @@
else if (ac->io_mode == io_compressed ||
ac->io_mode == io_compressed_stream)
lbuf_phys_addr = (param->paddr - param->metadata_len);
- else
- lbuf_phys_addr = param->paddr;
-
+ else {
+ if (param->flags & SET_TIMESTAMP)
+ lbuf_phys_addr = param->paddr -
+ sizeof(struct snd_codec_metadata);
+ else
+ lbuf_phys_addr = param->paddr;
+ }
dev_vdbg(ac->dev, "%s: token[0x%x], buf_addr[%pK], buf_size[0x%x], ts_msw[0x%x], ts_lsw[0x%x], lbuf_phys_addr: 0x[%pK]\n",
__func__,
write.hdr.token, ¶m->paddr,
@@ -7348,7 +7593,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 +7672,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);
@@ -7676,16 +7921,18 @@
matrix.param.data_payload_addr_lsw = 0;
matrix.param.data_payload_addr_msw = 0;
matrix.param.mem_map_handle = 0;
- matrix.param.data_payload_size = sizeof(matrix) -
- sizeof(matrix.hdr) - sizeof(matrix.param);
+ matrix.param.data_payload_size =
+ sizeof(struct asm_stream_param_data_v2) +
+ sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
matrix.param.direction = 0; /* RX */
matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
matrix.data.param_id = param_id;
- matrix.data.param_size = matrix.param.data_payload_size -
- sizeof(matrix.data);
+ matrix.data.param_size =
+ sizeof(struct asm_session_mtmx_strtr_param_window_v2_t);
matrix.data.reserved = 0;
- matrix.window_lsw = window_param->window_lsw;
- matrix.window_msw = window_param->window_msw;
+ memcpy(&(matrix.config.window_param),
+ window_param,
+ sizeof(struct asm_session_mtmx_strtr_param_window_v2_t));
rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
if (rc < 0) {
@@ -7715,7 +7962,177 @@
rc = 0;
fail_cmd:
return rc;
-};
+}
+
+int q6asm_send_mtmx_strtr_render_mode(struct audio_client *ac,
+ uint32_t render_mode)
+{
+ struct asm_mtmx_strtr_params matrix;
+ struct asm_session_mtmx_strtr_param_render_mode_t render_param;
+ int sz = 0;
+ int rc = 0;
+
+ pr_debug("%s: render mode is %d\n", __func__, render_mode);
+
+ if (!ac) {
+ pr_err("%s: audio client handle is NULL\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (ac->apr == NULL) {
+ pr_err("%s: ac->apr is NULL\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if ((render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_DEFAULT) &&
+ (render_mode != ASM_SESSION_MTMX_STRTR_PARAM_RENDER_LOCAL_STC)) {
+ pr_err("%s: Invalid render mode %d\n", __func__, render_mode);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ memset(&render_param, 0,
+ sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
+ render_param.flags = render_mode;
+
+ memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
+ sz = sizeof(struct asm_mtmx_strtr_params);
+ q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
+
+ matrix.param.data_payload_addr_lsw = 0;
+ matrix.param.data_payload_addr_msw = 0;
+ matrix.param.mem_map_handle = 0;
+ matrix.param.data_payload_size =
+ sizeof(struct asm_stream_param_data_v2) +
+ sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
+ matrix.param.direction = 0; /* RX */
+ matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
+ matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_RENDER_MODE_CMD;
+ matrix.data.param_size =
+ sizeof(struct asm_session_mtmx_strtr_param_render_mode_t);
+ matrix.data.reserved = 0;
+ memcpy(&(matrix.config.render_param),
+ &render_param,
+ sizeof(struct asm_session_mtmx_strtr_param_render_mode_t));
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
+ if (rc < 0) {
+ pr_err("%s: Render mode send failed paramid [0x%x]\n",
+ __func__, matrix.data.param_id);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, Render mode send paramid [0x%x]\n",
+ __func__, matrix.data.param_id);
+ rc = -ETIMEDOUT;
+ goto exit;
+ }
+
+ 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 exit;
+ }
+ rc = 0;
+exit:
+ return rc;
+}
+
+int q6asm_send_mtmx_strtr_clk_rec_mode(struct audio_client *ac,
+ uint32_t clk_rec_mode)
+{
+ struct asm_mtmx_strtr_params matrix;
+ struct asm_session_mtmx_strtr_param_clk_rec_t clk_rec_param;
+ int sz = 0;
+ int rc = 0;
+
+ pr_debug("%s: clk rec mode is %d\n", __func__, clk_rec_mode);
+
+ if (!ac) {
+ pr_err("%s: audio client handle is NULL\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if (ac->apr == NULL) {
+ pr_err("%s: ac->apr is NULL\n", __func__);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ if ((clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_NONE) &&
+ (clk_rec_mode != ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_AUTO)) {
+ pr_err("%s: Invalid clk rec mode %d\n", __func__, clk_rec_mode);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ memset(&clk_rec_param, 0,
+ sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
+ clk_rec_param.flags = clk_rec_mode;
+
+ memset(&matrix, 0, sizeof(struct asm_mtmx_strtr_params));
+ sz = sizeof(struct asm_mtmx_strtr_params);
+ q6asm_add_hdr(ac, &matrix.hdr, sz, TRUE);
+ atomic_set(&ac->cmd_state, -1);
+ matrix.hdr.opcode = ASM_SESSION_CMD_SET_MTMX_STRTR_PARAMS_V2;
+
+ matrix.param.data_payload_addr_lsw = 0;
+ matrix.param.data_payload_addr_msw = 0;
+ matrix.param.mem_map_handle = 0;
+ matrix.param.data_payload_size =
+ sizeof(struct asm_stream_param_data_v2) +
+ sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
+ matrix.param.direction = 0; /* RX */
+ matrix.data.module_id = ASM_SESSION_MTMX_STRTR_MODULE_ID_AVSYNC;
+ matrix.data.param_id = ASM_SESSION_MTMX_STRTR_PARAM_CLK_REC_CMD;
+ matrix.data.param_size =
+ sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t);
+ matrix.data.reserved = 0;
+ memcpy(&(matrix.config.clk_rec_param),
+ &clk_rec_param,
+ sizeof(struct asm_session_mtmx_strtr_param_clk_rec_t));
+
+ rc = apr_send_pkt(ac->apr, (uint32_t *) &matrix);
+ if (rc < 0) {
+ pr_err("%s: clk rec mode send failed paramid [0x%x]\n",
+ __func__, matrix.data.param_id);
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ rc = wait_event_timeout(ac->cmd_wait,
+ (atomic_read(&ac->cmd_state) >= 0), 5*HZ);
+ if (!rc) {
+ pr_err("%s: timeout, clk rec mode send paramid [0x%x]\n",
+ __func__, matrix.data.param_id);
+ rc = -ETIMEDOUT;
+ goto exit;
+ }
+
+ 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 exit;
+ }
+ rc = 0;
+exit:
+ return rc;
+}
static int __q6asm_cmd(struct audio_client *ac, int cmd, uint32_t stream_id)
{
@@ -7875,7 +8292,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 +8356,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 +8370,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 +8586,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 +8604,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/qdsp6v2/rtac.c b/sound/soc/msm/qdsp6v2/rtac.c
index 7a7db18..cd02501 100644
--- a/sound/soc/msm/qdsp6v2/rtac.c
+++ b/sound/soc/msm/qdsp6v2/rtac.c
@@ -400,6 +400,24 @@
return;
}
+void rtac_update_afe_topology(u32 port_id)
+{
+ u32 i = 0;
+
+ mutex_lock(&rtac_adm_mutex);
+ for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+ if (rtac_adm_data.device[i].afe_port == port_id) {
+ rtac_adm_data.device[i].afe_topology =
+ afe_get_topology(port_id);
+ pr_debug("%s: port_id = 0x%x topology_id = 0x%x copp_id = %d\n",
+ __func__, port_id,
+ rtac_adm_data.device[i].afe_topology,
+ rtac_adm_data.device[i].copp);
+ }
+ }
+ mutex_unlock(&rtac_adm_mutex);
+}
+
void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id,
u32 app_type, u32 acdb_id)
{
diff --git a/sound/soc/msm/msmfalcon-common.c b/sound/soc/msm/sdm660-common.c
similarity index 83%
rename from sound/soc/msm/msmfalcon-common.c
rename to sound/soc/msm/sdm660-common.c
index baf6a4f..f1fbce3 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
@@ -34,6 +36,11 @@
u32 channels;
};
+enum {
+ DP_RX_IDX,
+ EXT_DISP_RX_IDX_MAX,
+};
+
/* TDM default config */
static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = {
{ /* PRI TDM */
@@ -122,6 +129,10 @@
}
};
+/* Default configuration of external display BE */
+static struct dev_config ext_disp_rx_cfg[] = {
+ [DP_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
static struct dev_config usb_rx_cfg = {
.sample_rate = SAMPLING_RATE_48KHZ,
.bit_format = SNDRV_PCM_FORMAT_S16_LE,
@@ -158,20 +169,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 +198,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,
@@ -251,6 +260,8 @@
"Eight"};
static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
"S32_LE"};
+static char const *mi2s_format_text[] = {"S16_LE", "S24_LE", "S24_3LE",
+ "S32_LE"};
static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four",
"Five", "Six", "Seven", "Eight"};
static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"};
@@ -264,7 +275,11 @@
"KHZ_16", "KHZ_22P05",
"KHZ_32", "KHZ_44P1", "KHZ_48",
"KHZ_96", "KHZ_192", "KHZ_384"};
+static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE"};
+static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96",
+ "KHZ_192"};
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text);
@@ -282,6 +297,14 @@
static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_format, mi2s_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_format, mi2s_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text);
@@ -294,8 +317,11 @@
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_format, ext_disp_bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate,
+ ext_disp_sample_rate_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text);
static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text);
@@ -338,9 +364,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)
@@ -634,6 +693,54 @@
return value;
}
+static int mi2s_get_format(int value)
+{
+ int format = 0;
+
+ switch (value) {
+ case 0:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ case 1:
+ format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 2:
+ format = SNDRV_PCM_FORMAT_S24_3LE;
+ break;
+ case 3:
+ format = SNDRV_PCM_FORMAT_S32_LE;
+ break;
+ default:
+ format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ return format;
+}
+
+static int mi2s_get_format_value(int format)
+{
+ int value = 0;
+
+ switch (format) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ value = 0;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ value = 1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_3LE:
+ value = 2;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ value = 3;
+ break;
+ default:
+ value = 0;
+ break;
+ }
+ return value;
+}
+
static int tdm_rx_format_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1099,6 +1206,78 @@
return 0;
}
+static int mi2s_tx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_tx_cfg[idx].bit_format =
+ mi2s_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d] _tx_format = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_tx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_format_value(mi2s_tx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__,
+ idx, mi2s_tx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ mi2s_rx_cfg[idx].bit_format =
+ mi2s_get_format(ucontrol->value.enumerated.item[0]);
+
+ pr_debug("%s: idx[%d] _rx_format = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
+static int mi2s_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = mi2s_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.enumerated.item[0] =
+ mi2s_get_format_value(mi2s_rx_cfg[idx].bit_format);
+
+ pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+ idx, mi2s_rx_cfg[idx].bit_format,
+ ucontrol->value.enumerated.item[0]);
+
+ return 0;
+}
+
static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1481,6 +1660,162 @@
return rc;
}
+static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+ int idx;
+
+ if (strnstr(kcontrol->id.name, "Display Port RX",
+ sizeof("Display Port RX")))
+ idx = DP_RX_IDX;
+ else {
+ pr_err("%s: unsupported BE: %s",
+ __func__, kcontrol->id.name);
+ idx = -EINVAL;
+ }
+
+ return idx;
+}
+
+static int ext_disp_rx_format_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ switch (ext_disp_rx_cfg[idx].bit_format) {
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+
+ case SNDRV_PCM_FORMAT_S16_LE:
+ default:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ }
+
+ pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n",
+ __func__, idx, ext_disp_rx_cfg[idx].bit_format,
+ ucontrol->value.integer.value[0]);
+ return 0;
+}
+
+static int ext_disp_rx_format_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 1:
+ ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+ break;
+ case 0:
+ default:
+ ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE;
+ break;
+ }
+ pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n",
+ __func__, idx, ext_disp_rx_cfg[idx].bit_format,
+ ucontrol->value.integer.value[0]);
+
+ return 0;
+}
+
+static int ext_disp_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ucontrol->value.integer.value[0] =
+ ext_disp_rx_cfg[idx].channels - 2;
+
+ pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__,
+ idx, ext_disp_rx_cfg[idx].channels);
+
+ return 0;
+}
+
+static int ext_disp_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ ext_disp_rx_cfg[idx].channels =
+ ucontrol->value.integer.value[0] + 2;
+
+ pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__,
+ idx, ext_disp_rx_cfg[idx].channels);
+ return 1;
+}
+
+static int ext_disp_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int sample_rate_val;
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ switch (ext_disp_rx_cfg[idx].sample_rate) {
+ case SAMPLING_RATE_192KHZ:
+ sample_rate_val = 2;
+ break;
+
+ case SAMPLING_RATE_96KHZ:
+ sample_rate_val = 1;
+ break;
+
+ case SAMPLING_RATE_48KHZ:
+ default:
+ sample_rate_val = 0;
+ break;
+ }
+
+ ucontrol->value.integer.value[0] = sample_rate_val;
+ pr_debug("%s: ext_disp_rx[%d].sample_rate = %d\n", __func__,
+ idx, ext_disp_rx_cfg[idx].sample_rate);
+
+ return 0;
+}
+
+static int ext_disp_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int idx = ext_disp_get_port_idx(kcontrol);
+
+ if (idx < 0)
+ return idx;
+
+ switch (ucontrol->value.integer.value[0]) {
+ case 2:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ;
+ break;
+ case 1:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ;
+ break;
+ case 0:
+ default:
+ ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ;
+ break;
+ }
+
+ pr_debug("%s: control value = %ld, ext_disp_rx[%d].sample_rate = %d\n",
+ __func__, ucontrol->value.integer.value[0], idx,
+ ext_disp_rx_cfg[idx].sample_rate);
+ return 0;
+}
+
const struct snd_kcontrol_new msm_common_snd_controls[] = {
SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs,
proxy_rx_ch_get, proxy_rx_ch_put),
@@ -1532,6 +1867,30 @@
SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate,
mi2s_tx_sample_rate_get,
mi2s_tx_sample_rate_put),
+ SOC_ENUM_EXT("PRIM_MI2S_RX Format", prim_mi2s_rx_format,
+ mi2s_rx_format_get,
+ mi2s_rx_format_put),
+ SOC_ENUM_EXT("SEC_MI2S_RX Format", sec_mi2s_rx_format,
+ mi2s_rx_format_get,
+ mi2s_rx_format_put),
+ SOC_ENUM_EXT("TERT_MI2S_RX Format", tert_mi2s_rx_format,
+ mi2s_rx_format_get,
+ mi2s_rx_format_put),
+ SOC_ENUM_EXT("QUAT_MI2S_RX Format", quat_mi2s_rx_format,
+ mi2s_rx_format_get,
+ mi2s_rx_format_put),
+ SOC_ENUM_EXT("PRIM_MI2S_TX Format", prim_mi2s_tx_format,
+ mi2s_tx_format_get,
+ mi2s_tx_format_put),
+ SOC_ENUM_EXT("SEC_MI2S_TX Format", sec_mi2s_tx_format,
+ mi2s_tx_format_get,
+ mi2s_tx_format_put),
+ SOC_ENUM_EXT("TERT_MI2S_TX Format", tert_mi2s_tx_format,
+ mi2s_tx_format_get,
+ mi2s_tx_format_put),
+ SOC_ENUM_EXT("QUAT_MI2S_TX Format", quat_mi2s_tx_format,
+ mi2s_tx_format_get,
+ mi2s_tx_format_put),
SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs,
msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put),
SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs,
@@ -1552,16 +1911,23 @@
usb_audio_rx_ch_get, usb_audio_rx_ch_put),
SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs,
usb_audio_tx_ch_get, usb_audio_tx_ch_put),
+ SOC_ENUM_EXT("Display Port RX Channels", ext_disp_rx_chs,
+ ext_disp_rx_ch_get, ext_disp_rx_ch_put),
SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format,
usb_audio_rx_format_get, usb_audio_rx_format_put),
SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format,
usb_audio_tx_format_get, usb_audio_tx_format_put),
+ SOC_ENUM_EXT("Display Port RX Bit Format", ext_disp_rx_format,
+ ext_disp_rx_format_get, ext_disp_rx_format_put),
SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate,
usb_audio_rx_sample_rate_get,
usb_audio_rx_sample_rate_put),
SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate,
usb_audio_tx_sample_rate_get,
usb_audio_tx_sample_rate_put),
+ SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate,
+ ext_disp_rx_sample_rate_get,
+ ext_disp_rx_sample_rate_put),
SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate,
tdm_rx_sample_rate_get,
tdm_rx_sample_rate_put),
@@ -1636,6 +2002,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) &&
@@ -1661,6 +2038,23 @@
}
}
+static int msm_ext_disp_get_idx_from_beid(int32_t be_id)
+{
+ int idx;
+
+ switch (be_id) {
+ case MSM_BACKEND_DAI_DISPLAY_PORT_RX:
+ idx = DP_RX_IDX;
+ break;
+ default:
+ pr_err("%s: Incorrect ext_disp be_id %d\n", __func__, be_id);
+ idx = -EINVAL;
+ break;
+ }
+
+ return idx;
+}
+
/**
* msm_common_be_hw_params_fixup - updates settings of ALSA BE hw params.
*
@@ -1678,6 +2072,7 @@
struct snd_interval *channels = hw_param_interval(params,
SNDRV_PCM_HW_PARAM_CHANNELS);
int rc = 0;
+ int idx;
pr_debug("%s: format = %d, rate = %d\n",
__func__, params_format(params), params_rate(params));
@@ -1697,6 +2092,21 @@
channels->min = channels->max = usb_tx_cfg.channels;
break;
+ case MSM_BACKEND_DAI_DISPLAY_PORT_RX:
+ idx = msm_ext_disp_get_idx_from_beid(dai_link->be_id);
+ if (IS_ERR_VALUE(idx)) {
+ pr_err("%s: Incorrect ext disp idx %d\n",
+ __func__, idx);
+ rc = idx;
+ break;
+ }
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ ext_disp_rx_cfg[idx].bit_format);
+ rate->min = rate->max = ext_disp_rx_cfg[idx].sample_rate;
+ channels->min = channels->max = ext_disp_rx_cfg[idx].channels;
+ break;
+
case MSM_BACKEND_DAI_AFE_PCM_RX:
channels->min = channels->max = proxy_rx_cfg.channels;
rate->min = rate->max = SAMPLING_RATE_48KHZ;
@@ -1826,48 +2236,64 @@
rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate;
channels->min = channels->max =
mi2s_rx_cfg[PRIM_MI2S].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_rx_cfg[PRIM_MI2S].bit_format);
break;
case MSM_BACKEND_DAI_PRI_MI2S_TX:
rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate;
channels->min = channels->max =
mi2s_tx_cfg[PRIM_MI2S].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_tx_cfg[PRIM_MI2S].bit_format);
break;
case MSM_BACKEND_DAI_SECONDARY_MI2S_RX:
rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate;
channels->min = channels->max =
mi2s_rx_cfg[SEC_MI2S].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_rx_cfg[SEC_MI2S].bit_format);
break;
case MSM_BACKEND_DAI_SECONDARY_MI2S_TX:
rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate;
channels->min = channels->max =
mi2s_tx_cfg[SEC_MI2S].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_tx_cfg[SEC_MI2S].bit_format);
break;
case MSM_BACKEND_DAI_TERTIARY_MI2S_RX:
rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate;
channels->min = channels->max =
mi2s_rx_cfg[TERT_MI2S].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_rx_cfg[TERT_MI2S].bit_format);
break;
case MSM_BACKEND_DAI_TERTIARY_MI2S_TX:
rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate;
channels->min = channels->max =
mi2s_tx_cfg[TERT_MI2S].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_tx_cfg[TERT_MI2S].bit_format);
break;
case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX:
rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate;
channels->min = channels->max =
mi2s_rx_cfg[QUAT_MI2S].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_rx_cfg[QUAT_MI2S].bit_format);
break;
case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX:
rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate;
channels->min = channels->max =
mi2s_tx_cfg[QUAT_MI2S].channels;
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ mi2s_tx_cfg[QUAT_MI2S].bit_format);
break;
default:
@@ -1887,46 +2313,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 +2332,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);
@@ -2013,6 +2383,7 @@
u32 bit_per_sample;
switch (bit_format) {
+ case SNDRV_PCM_FORMAT_S32_LE:
case SNDRV_PCM_FORMAT_S24_3LE:
case SNDRV_PCM_FORMAT_S24_LE:
bit_per_sample = 32;
@@ -2093,6 +2464,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 +2487,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 +2499,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 +2506,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 +2542,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 +2560,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 +2621,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 +2701,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 +2984,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 +3006,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 +3044,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 +3081,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 +3121,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 +3171,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 +3184,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 95%
rename from sound/soc/msm/msmfalcon-ext-dai-links.c
rename to sound/soc/msm/sdm660-ext-dai-links.c
index 6f066c5..f64074d 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,
@@ -1301,6 +1302,39 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {/* hw:x,35 */
+ .name = "SLIMBUS7 Hostless",
+ .stream_name = "SLIMBUS7 Hostless",
+ .cpu_dai_name = "SLIMBUS7_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",
+ },
+ {/* hw:x,36 */
+ .name = "SDM660 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
};
static struct snd_soc_dai_link msm_ext_common_be_dai[] = {
@@ -1827,6 +1861,24 @@
},
};
+static struct snd_soc_dai_link ext_disp_be_dai_link[] = {
+ /* DISP PORT BACK END DAI Link */
+ {
+ .name = LPASS_BE_DISPLAY_PORT,
+ .stream_name = "Display Port Playback",
+ .cpu_dai_name = "msm-dai-q6-dp.24608",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-ext-disp-audio-codec-rx",
+ .codec_dai_name = "msm_dp_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .ignore_suspend = 1,
+ },
+};
+
static struct snd_soc_dai_link msm_ext_tasha_dai_links[
ARRAY_SIZE(msm_ext_common_fe_dai) +
ARRAY_SIZE(msm_ext_tasha_fe_dai) +
@@ -1834,7 +1886,8 @@
ARRAY_SIZE(msm_ext_tasha_be_dai) +
ARRAY_SIZE(msm_mi2s_be_dai_links) +
ARRAY_SIZE(msm_auxpcm_be_dai_links) +
-ARRAY_SIZE(msm_wcn_be_dai_links)];
+ARRAY_SIZE(msm_wcn_be_dai_links) +
+ARRAY_SIZE(ext_disp_be_dai_link)];
static struct snd_soc_dai_link msm_ext_tavil_dai_links[
ARRAY_SIZE(msm_ext_common_fe_dai) +
@@ -1843,7 +1896,8 @@
ARRAY_SIZE(msm_ext_tavil_be_dai) +
ARRAY_SIZE(msm_mi2s_be_dai_links) +
ARRAY_SIZE(msm_auxpcm_be_dai_links) +
-ARRAY_SIZE(msm_wcn_be_dai_links)];
+ARRAY_SIZE(msm_wcn_be_dai_links) +
+ARRAY_SIZE(ext_disp_be_dai_link)];
/**
* populate_snd_card_dailinks - prepares dailink array and initializes card.
@@ -1881,7 +1935,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);
@@ -1917,6 +1971,15 @@
sizeof(msm_wcn_be_dai_links));
len4 += ARRAY_SIZE(msm_wcn_be_dai_links);
}
+ if (of_property_read_bool(dev->of_node,
+ "qcom,ext-disp-audio-rx")) {
+ dev_dbg(dev, "%s(): ext disp audio support present\n",
+ __func__);
+ memcpy(msm_ext_tasha_dai_links + len4,
+ ext_disp_be_dai_link,
+ sizeof(ext_disp_be_dai_link));
+ len4 += ARRAY_SIZE(ext_disp_be_dai_link);
+ }
msm_ext_dai_links = msm_ext_tasha_dai_links;
} else if (strnstr(card->name, "tavil", strlen(card->name))) {
len1 = ARRAY_SIZE(msm_ext_common_fe_dai);
@@ -1953,6 +2016,15 @@
sizeof(msm_wcn_be_dai_links));
len4 += ARRAY_SIZE(msm_wcn_be_dai_links);
}
+ if (of_property_read_bool(dev->of_node,
+ "qcom,ext-disp-audio-rx")) {
+ dev_dbg(dev, "%s(): ext disp audio support present\n",
+ __func__);
+ memcpy(msm_ext_tavil_dai_links + len4,
+ ext_disp_be_dai_link,
+ sizeof(ext_disp_be_dai_link));
+ len4 += ARRAY_SIZE(ext_disp_be_dai_link);
+ }
msm_ext_dai_links = msm_ext_tavil_dai_links;
} else {
dev_err(dev, "%s: failing as no matching card name\n",
diff --git a/sound/soc/msm/msmfalcon-external.c b/sound/soc/msm/sdm660-external.c
similarity index 91%
rename from sound/soc/msm/msmfalcon-external.c
rename to sound/soc/msm/sdm660-external.c
index d7b002e..b603b8a 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 {
@@ -659,7 +676,7 @@
static int msm_ext_set_spk(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
pr_debug("%s()\n", __func__);
if (msm_ext_spk_control == ucontrol->value.integer.value[0])
@@ -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 90%
rename from sound/soc/msm/msmfalcon-internal.c
rename to sound/soc/msm/sdm660-internal.c
index 50efd69..b924cad 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,
@@ -131,7 +136,7 @@
[INT2_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[INT3_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
[INT4_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1},
- [INT5_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+ [INT5_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
[INT6_MI2S] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
};
@@ -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,15 +904,12 @@
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,
int_mi2s_sample_rate_get,
int_mi2s_sample_rate_put),
- SOC_ENUM_EXT("INT4_MI2S_RX SampleRate", int4_mi2s_rx_sample_rate,
- int_mi2s_sample_rate_get,
- int_mi2s_sample_rate_put),
SOC_ENUM_EXT("INT4_MI2S_RX Channels", int4_mi2s_rx_chs,
int_mi2s_ch_get, int_mi2s_ch_put),
SOC_ENUM_EXT("VI_FEED_TX Channels", int5_mi2s_tx_chs,
@@ -919,7 +927,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 +935,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 +962,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 +971,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 +1063,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 +1105,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 +1120,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 +1127,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 +1144,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 +1164,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 +1251,33 @@
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 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 +1298,78 @@
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);
+ 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_soc_pcm_runtime *rtd_aux = rtd->card->rtd_aux;
+ 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);
+ /*
+ * Send speaker configuration only for WSA8810.
+ * Default 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);
+ }
+ 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 +1592,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 +1760,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 +1807,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 +2199,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 +2215,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 +2232,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 +2249,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 +2266,53 @@
.codec_dai_name = "snd-soc-dummy-dai",
.codec_name = "snd-soc-dummy",
},
+ {/* hw:x,39 */
+ .name = "SDM660 HFP TX",
+ .stream_name = "MultiMedia6",
+ .cpu_dai_name = "MultiMedia6",
+ .platform_name = "msm-pcm-loopback",
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .trigger = {SND_SOC_DPCM_TRIGGER_POST,
+ SND_SOC_DPCM_TRIGGER_POST},
+ .ignore_suspend = 1,
+ .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
+ .ignore_pmdown_time = 1,
+ .be_id = MSM_FRONTEND_DAI_MULTIMEDIA6,
+ },
+};
+
+
+static struct snd_soc_dai_link msm_int_wsa_dai[] = {
+ {/* hw:x,40 */
+ .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 +2324,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 +2344,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 +2356,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 +2879,55 @@
},
};
+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 ext_disp_be_dai_link[] = {
+ /* DISP PORT BACK END DAI Link */
+ {
+ .name = LPASS_BE_DISPLAY_PORT,
+ .stream_name = "Display Port Playback",
+ .cpu_dai_name = "msm-dai-q6-dp.24608",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-ext-disp-audio-codec-rx",
+ .codec_dai_name = "msm_dp_audio_codec_rx_dai",
+ .no_pcm = 1,
+ .dpcm_playback = 1,
+ .be_id = MSM_BACKEND_DAI_DISPLAY_PORT_RX,
+ .be_hw_params_fixup = msm_common_be_hw_params_fixup,
+ .ignore_pmdown_time = 1,
+ .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) +
+ARRAY_SIZE(ext_disp_be_dai_link)];
-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 +2978,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 +2986,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 +3018,20 @@
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);
+ }
+ if (of_property_read_bool(dev->of_node, "qcom,ext-disp-audio-rx")) {
+ dev_dbg(dev, "%s(): ext disp audio support present\n",
+ __func__);
+ memcpy(dailink + len1,
+ ext_disp_be_dai_link,
+ sizeof(ext_disp_be_dai_link));
+ len1 += ARRAY_SIZE(ext_disp_be_dai_link);
+ }
card->dai_link = dailink;
card->num_links = len1;
return card;
@@ -2913,8 +3071,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>
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index e80017f..ad3cc68 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -528,6 +528,11 @@
cstream, &async_domain);
} else {
be_list[j++] = be;
+ if (j == DPCM_MAX_BE_USERS) {
+ dev_dbg(fe->dev,
+ "ASoC: MAX backend users!\n");
+ break;
+ }
}
}
for (i = 0; i < j; i++) {
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 7d505e2..94ea909 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -78,8 +78,7 @@
[snd_soc_dapm_dai_link] = 2,
[snd_soc_dapm_dai_in] = 4,
[snd_soc_dapm_dai_out] = 4,
- [snd_soc_dapm_aif_in] = 4,
- [snd_soc_dapm_aif_out] = 4,
+ [snd_soc_dapm_adc] = 4,
[snd_soc_dapm_mic] = 5,
[snd_soc_dapm_mux] = 6,
[snd_soc_dapm_demux] = 6,
@@ -88,7 +87,8 @@
[snd_soc_dapm_mixer] = 8,
[snd_soc_dapm_mixer_named_ctl] = 8,
[snd_soc_dapm_pga] = 9,
- [snd_soc_dapm_adc] = 10,
+ [snd_soc_dapm_aif_in] = 9,
+ [snd_soc_dapm_aif_out] = 9,
[snd_soc_dapm_out_drv] = 11,
[snd_soc_dapm_hp] = 11,
[snd_soc_dapm_spk] = 11,
@@ -100,7 +100,9 @@
static int dapm_down_seq[] = {
[snd_soc_dapm_pre] = 0,
[snd_soc_dapm_kcontrol] = 1,
- [snd_soc_dapm_adc] = 2,
+ [snd_soc_dapm_aif_in] = 2,
+ [snd_soc_dapm_aif_out] = 2,
+ [snd_soc_dapm_adc] = 5,
[snd_soc_dapm_hp] = 3,
[snd_soc_dapm_spk] = 3,
[snd_soc_dapm_line] = 3,
@@ -114,8 +116,6 @@
[snd_soc_dapm_micbias] = 8,
[snd_soc_dapm_mux] = 9,
[snd_soc_dapm_demux] = 9,
- [snd_soc_dapm_aif_in] = 10,
- [snd_soc_dapm_aif_out] = 10,
[snd_soc_dapm_dai_in] = 10,
[snd_soc_dapm_dai_out] = 10,
[snd_soc_dapm_dai_link] = 11,
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 4f4d230..be6290d 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -1931,14 +1931,14 @@
dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_FE);
- /* shutdown the BEs */
- dpcm_be_dai_shutdown(fe, substream->stream);
-
dev_dbg(fe->dev, "ASoC: close FE %s\n", fe->dai_link->name);
/* now shutdown the frontend */
soc_pcm_close(substream);
+ /* shutdown the BEs */
+ dpcm_be_dai_shutdown(fe, substream->stream);
+
/* run the stream event for each BE */
dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
@@ -2521,6 +2521,10 @@
dpcm, domain);
} else {
dpcm_async[i++] = dpcm;
+ if (i == DPCM_MAX_BE_USERS) {
+ dev_dbg(fe->dev, "ASoC: MAX backend users!\n");
+ break;
+ }
}
}