aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,kryocc.txt17
-rw-r--r--Documentation/devicetree/bindings/firmware/qcom,scm.txt3
-rw-r--r--Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt11
-rw-r--r--Documentation/devicetree/bindings/interconnect/interconnect.txt60
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom-msm8916.txt39
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom-msm8996.txt95
-rw-r--r--Documentation/devicetree/bindings/interconnect/qcom-smd.txt32
-rw-r--r--Documentation/devicetree/bindings/iommu/arm,smmu.txt42
-rw-r--r--Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt1
-rw-r--r--Documentation/devicetree/bindings/power/avs/qcom,cpr.txt125
-rw-r--r--Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt160
-rw-r--r--Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt2
-rw-r--r--Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt52
-rw-r--r--Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt84
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt137
-rw-r--r--Documentation/interconnect/interconnect.rst96
-rw-r--r--MAINTAINERS10
-rw-r--r--arch/arm64/Kconfig.platforms7
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi4
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi52
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi9
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c.dts4
-rw-r--r--arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi95
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi71
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996-pins.dtsi46
-rw-r--r--arch/arm64/boot/dts/qcom/msm8996.dtsi851
-rw-r--r--arch/arm64/boot/dts/qcom/pm8916.dtsi119
-rw-r--r--arch/arm64/boot/dts/qcom/pmi8994.dtsi14
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845-mtp.dts182
-rw-r--r--arch/arm64/boot/dts/qcom/sdm845.dtsi1412
-rw-r--r--arch/arm64/configs/defconfig90
-rw-r--r--arch/arm64/include/asm/io.h8
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/base/core.c10
-rw-r--r--drivers/base/regmap/regmap-slimbus.c27
-rw-r--r--drivers/clk/qcom/Kconfig17
-rw-r--r--drivers/clk/qcom/Makefile2
-rw-r--r--drivers/clk/qcom/clk-alpha-pll.c1
-rw-r--r--drivers/clk/qcom/clk-cpu-8996.c554
-rw-r--r--drivers/clk/qcom/clk-rpmh.c333
-rw-r--r--drivers/clk/qcom/gcc-msm8996.c186
-rw-r--r--drivers/clk/qcom/mmcc-msm8996.c21
-rw-r--r--drivers/cpufreq/cpufreq-dt-platdev.c4
-rw-r--r--drivers/cpufreq/cpufreq-dt.c51
-rw-r--r--drivers/firmware/qcom_scm.c3
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c3
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h3
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c10
-rw-r--r--drivers/i2c/busses/Kconfig13
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-qcom-geni.c649
-rw-r--r--drivers/input/misc/pm8941-pwrkey.c64
-rw-r--r--drivers/interconnect/Kconfig15
-rw-r--r--drivers/interconnect/Makefile3
-rw-r--r--drivers/interconnect/core.c737
-rw-r--r--drivers/interconnect/qcom/Kconfig29
-rw-r--r--drivers/interconnect/qcom/Makefile5
-rw-r--r--drivers/interconnect/qcom/msm8916.c508
-rw-r--r--drivers/interconnect/qcom/msm8996.c658
-rw-r--r--drivers/interconnect/qcom/smd-rpm.c91
-rw-r--r--drivers/interconnect/qcom/smd-rpm.h15
-rw-r--r--drivers/iommu/arm-smmu.c178
-rw-r--r--drivers/irqchip/irq-gic-v3.c5
-rw-r--r--drivers/mmc/host/mmci.c10
-rw-r--r--drivers/opp/core.c93
-rw-r--r--drivers/perf/qcom_l2_pmu.c50
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.c123
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp.h8
-rw-r--r--drivers/power/avs/Kconfig15
-rw-r--r--drivers/power/avs/Makefile1
-rw-r--r--drivers/power/avs/qcom-cpr.c2015
-rw-r--r--drivers/regulator/Kconfig9
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/qcom-rpmh-regulator.c753
-rw-r--r--drivers/regulator/qcom_smd-regulator.c52
-rw-r--r--drivers/remoteproc/qcom_adsp_pil.c12
-rw-r--r--drivers/reset/Kconfig9
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/reset-qcom-aoss.c133
-rw-r--r--drivers/rpmsg/rpmsg_core.c7
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c175
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h5
-rw-r--r--drivers/scsi/ufs/ufshcd.c1
-rw-r--r--drivers/scsi/ufs/ufshcd.h13
-rw-r--r--drivers/slimbus/Kconfig12
-rw-r--r--drivers/slimbus/Makefile5
-rw-r--r--drivers/slimbus/core.c39
-rw-r--r--drivers/slimbus/messaging.c176
-rw-r--r--drivers/slimbus/qcom-ngd-ctrl.c1489
-rw-r--r--drivers/slimbus/slimbus.h124
-rw-r--r--drivers/slimbus/stream.c357
-rw-r--r--drivers/soc/qcom/Kconfig10
-rw-r--r--drivers/soc/qcom/Makefile5
-rw-r--r--drivers/soc/qcom/kryo-l2-accessors.c64
-rw-r--r--drivers/soc/qcom/rmtfs_mem.c5
-rw-r--r--drivers/soc/qcom/rpmh-internal.h114
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c682
-rw-r--r--drivers/soc/qcom/rpmh.c512
-rw-r--r--drivers/soc/qcom/smem.c10
-rw-r--r--drivers/soc/qcom/trace-rpmh.h82
-rw-r--r--include/dt-bindings/clock/qcom,gcc-msm8996.h9
-rw-r--r--include/dt-bindings/interconnect/qcom.h440
-rw-r--r--include/dt-bindings/regulator/qcom,rpmh-regulator.h36
-rw-r--r--include/dt-bindings/reset/qcom,sdm845-aoss.h17
-rw-r--r--include/dt-bindings/soc/qcom,rpmh-rsc.h14
-rw-r--r--include/linux/device.h2
-rw-r--r--include/linux/interconnect-provider.h130
-rw-r--r--include/linux/interconnect.h49
-rw-r--r--include/linux/pm_opp.h12
-rw-r--r--include/linux/regulator/qcom_smd-regulator.h30
-rw-r--r--include/linux/slimbus.h61
-rw-r--r--include/soc/qcom/kryo-l2-accessors.h22
-rw-r--r--include/soc/qcom/rpmh.h51
-rw-r--r--include/soc/qcom/tcs.h56
-rw-r--r--include/sound/soc-dai.h9
-rw-r--r--kernel/configs/debug.config13
-rw-r--r--kernel/configs/distro.config456
-rw-r--r--sound/soc/codecs/Kconfig7
-rw-r--r--sound/soc/codecs/Makefile5
-rw-r--r--sound/soc/codecs/wcd-clsh.c870
-rw-r--r--sound/soc/codecs/wcd-clsh.h224
-rw-r--r--sound/soc/codecs/wcd-slim.h82
-rw-r--r--sound/soc/codecs/wcd9335-regmap.c2913
-rw-r--r--sound/soc/codecs/wcd9335-slim.c498
-rw-r--r--sound/soc/codecs/wcd9335.c4448
-rw-r--r--sound/soc/codecs/wcd9335.h228
-rw-r--r--sound/soc/codecs/wcd9335_registers.h1350
-rw-r--r--sound/soc/qcom/apq8096.c78
-rw-r--r--sound/soc/qcom/qdsp6/q6routing.c2
-rw-r--r--sound/soc/soc-core.c26
131 files changed, 27186 insertions, 253 deletions
diff --git a/Documentation/devicetree/bindings/clock/qcom,kryocc.txt b/Documentation/devicetree/bindings/clock/qcom,kryocc.txt
new file mode 100644
index 000000000000..e7cf15a4ce64
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,kryocc.txt
@@ -0,0 +1,17 @@
+Qualcomm CPUSS clock controller for Kryo CPUs
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+ "qcom-msm8996-apcc"
+
+- reg : shall contain base register location and length
+- #clock-cells : shall contain 1
+
+Example:
+ kryocc: clock-controller@6400000 {
+ compatible = "qcom-msm8996-apcc";
+ reg = <0x6400000 0x90000>;
+ #clock-cells = <1>;
+ };
diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.txt b/Documentation/devicetree/bindings/firmware/qcom,scm.txt
index fcf6979c0b6d..b07843f05e7d 100644
--- a/Documentation/devicetree/bindings/firmware/qcom,scm.txt
+++ b/Documentation/devicetree/bindings/firmware/qcom,scm.txt
@@ -12,9 +12,10 @@ Required properties:
* "qcom,scm-msm8690" for MSM8690 platforms
* "qcom,scm-msm8996" for MSM8996 platforms
* "qcom,scm-ipq4019" for IPQ4019 platforms
+ * "qcom,scm-sdm845" for SDM845 platforms
* "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc)
- clocks: One to three clocks may be required based on compatible.
- * No clock required for "qcom,scm-msm8996", "qcom,scm-ipq4019"
+ * No clock required for "qcom,scm-msm8996", "qcom,scm-ipq4019", "qcom,scm-sdm845"
* Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960"
* Core, iface, and bus clocks required for "qcom,scm"
- clock-names: Must contain "core" for the core clock, "iface" for the interface
diff --git a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt
index 07bf55f6e0b9..f3ae70b50b1e 100644
--- a/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt
+++ b/Documentation/devicetree/bindings/input/qcom,pm8941-pwrkey.txt
@@ -32,6 +32,17 @@ PROPERTIES
Definition: presence of this property indicates that the KPDPWR_N pin
should be configured for pull up.
+- resin-pull-up:
+ Usage: optional
+ Value type: <empty>
+ Definition: presence of this property indicates that the RESIN_N pin
+ should be configured for pull up.
+
+- linux,code:
+ Usage: optional
+ Value type: <empty>
+ Definition: Keycode to emit when RESIN_N input change its state.
+
EXAMPLE
pwrkey@800 {
diff --git a/Documentation/devicetree/bindings/interconnect/interconnect.txt b/Documentation/devicetree/bindings/interconnect/interconnect.txt
new file mode 100644
index 000000000000..0ad65dccbe8b
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/interconnect.txt
@@ -0,0 +1,60 @@
+Interconnect Provider Device Tree Bindings
+=========================================
+
+The purpose of this document is to define a common set of generic interconnect
+providers/consumers properties.
+
+
+= interconnect providers =
+
+The interconnect provider binding is intended to represent the interconnect
+controllers in the system. Each provider registers a set of interconnect
+nodes, which expose the interconnect related capabilities of the interconnect
+to consumer drivers. These capabilities can be throughput, latency, priority
+etc. The consumer drivers set constraints on interconnect path (or endpoints)
+depending on the use case. Interconnect providers can also be interconnect
+consumers, such as in the case where two network-on-chip fabrics interface
+directly
+
+Required properties:
+- compatible : contains the interconnect provider compatible string
+- #interconnect-cells : number of cells in a interconnect specifier needed to
+ encode the interconnect node id
+
+Example:
+
+ snoc: snoc@580000 {
+ compatible = "qcom,msm8916-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x14000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ };
+
+
+= interconnect consumers =
+
+The interconnect consumers are device nodes which consume the interconnect
+path(s) provided by the interconnect provider. There can be multiple
+interconnect providers on a SoC and the consumer may consume multiple paths
+from different providers depending on use case and the components it has to
+interact with.
+
+Required properties:
+interconnects : Pairs of phandles and interconnect provider specifier to denote
+ the edge source and destination ports of the interconnect path.
+
+Optional properties:
+interconnect-names : List of interconnect path name strings sorted in the same
+ order as the interconnects property. Consumers drivers will use
+ interconnect-names to match interconnect paths with interconnect
+ specifiers.
+
+Example:
+
+ sdhci@7864000 {
+ ...
+ interconnects = <&pnoc MASTER_SDCC_1 &bimc SLAVE_EBI_CH0>;
+ interconnect-names = "ddr";
+ };
diff --git a/Documentation/devicetree/bindings/interconnect/qcom-msm8916.txt b/Documentation/devicetree/bindings/interconnect/qcom-msm8916.txt
new file mode 100644
index 000000000000..f309eaed3d19
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom-msm8916.txt
@@ -0,0 +1,39 @@
+Qualcomm MSM8916 Network-On-Chip interconnect driver binding
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,msm8916-bimc"
+ "qcom,msm8916-pnoc"
+ "qcom,msm8916-snoc"
+- #interconnect-cells : should contain 1
+- reg : shall contain base register location and length
+
+Optional properties :
+clocks : list of phandles and specifiers to all interconnect bus clocks
+clock-names : clock names should include both "bus_clk" and "bus_a_clk"
+
+Examples:
+
+ snoc: snoc@580000 {
+ compatible = "qcom,msm8916-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x14000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>, <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ };
+ bimc: bimc@400000 {
+ compatible = "qcom,msm8916-bimc";
+ #interconnect-cells = <1>;
+ reg = <0x400000 0x62000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>, <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ };
+ pnoc: pnoc@500000 {
+ compatible = "qcom,msm8916-pnoc";
+ #interconnect-cells = <1>;
+ reg = <0x500000 0x11000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>, <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ };
+
diff --git a/Documentation/devicetree/bindings/interconnect/qcom-msm8996.txt b/Documentation/devicetree/bindings/interconnect/qcom-msm8996.txt
new file mode 100644
index 000000000000..26bbc564cd60
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom-msm8996.txt
@@ -0,0 +1,95 @@
+Qualcomm MSM8996 Network-On-Chip interconnect driver binding
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,msm8996-a0noc"
+ "qcom,msm8996-a1noc"
+ "qcom,msm8996-a2noc"
+ "qcom,msm8996-bimc"
+ "qcom,msm8996-cnoc"
+ "qcom,msm8996-mmnoc"
+ "qcom,msm8996-snoc"
+ "qcom,msm8996-pnoc"
+- #interconnect-cells : should contain 1
+- reg : shall contain base register location and length
+
+Optional properties :
+clocks : list of phandles and specifiers to all interconnect bus clocks
+clock-names : clock names should include both "bus_clk" and "bus_a_clk"
+
+Examples:
+
+ bimc: bimc@400000 {
+ compatible = "qcom,msm8996-bimc";
+ #interconnect-cells = <1>;
+ reg = <0x400000 0x62000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+ <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ };
+
+ cnoc: cnoc@500000 {
+ compatible = "qcom,msm8996-cnoc";
+ #interconnect-cells = <1>;
+ reg = <0x500000 0x80>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
+ <&rpmcc RPM_SMD_CNOC_A_CLK>;
+ };
+
+ snoc: snoc@520000 {
+ compatible = "qcom,msm8996-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x520000 0xa100>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ };
+
+ a0noc: a0noc@540000 {
+ compatible = "qcom,msm8996-a0noc";
+ #interconnect-cells = <1>;
+ reg = <0x540000 0x5100>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&gcc GCC_AGGRE0_SNOC_AXI_CLK>,
+ <&gcc GCC_AGGRE0_SNOC_AXI_CLK>;
+ power-domains = <&gcc AGGRE0_NOC_GDSC>;
+ };
+
+ a1noc: a1noc@560000 {
+ compatible = "qcom,msm8996-a1noc";
+ #interconnect-cells = <1>;
+ reg = <0x560000 0x3100>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>,
+ <&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>;
+ };
+
+ a2noc: a2noc@580000 {
+ compatible = "qcom,msm8996-a2noc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x8100>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
+ <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>;
+ };
+
+ mmnoc: mmnoc@5a0000 {
+ compatible = "qcom,msm8996-mmnoc";
+ #interconnect-cells = <1>;
+ reg = <0x5a0000 0xb080>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_MMAXI_CLK>,
+ <&rpmcc RPM_SMD_MMAXI_A_CLK>;
+ power-domains = <&mmcc MMAGIC_BIMC_GDSC>;
+ };
+
+ pnoc: pnoc@5c0000 {
+ compatible = "qcom,msm8996-pnoc";
+ #interconnect-cells = <1>;
+ reg = <0x5c0000 0x2480>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
+ <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ };
diff --git a/Documentation/devicetree/bindings/interconnect/qcom-smd.txt b/Documentation/devicetree/bindings/interconnect/qcom-smd.txt
new file mode 100644
index 000000000000..88a5aeb50935
--- /dev/null
+++ b/Documentation/devicetree/bindings/interconnect/qcom-smd.txt
@@ -0,0 +1,32 @@
+Qualcomm SMD-RPM interconnect driver binding
+------------------------------------------------
+The RPM (Resource Power Manager) is a dedicated hardware engine
+for managing the shared SoC resources in order to keep the lowest
+power profile. It communicates with other hardware subsystems via
+the shared memory driver (SMD) back-end and accepts requests for
+various resources.
+
+Required properties :
+- compatible : shall contain only one of the following:
+ "qcom,interconnect-smd-rpm"
+
+Example:
+ smd {
+ compatible = "qcom,smd";
+
+ rpm {
+ interrupts = <0 168 1>;
+ qcom,ipc = <&apcs 8 0>;
+ qcom,smd-edge = <15>;
+
+ rpm_requests {
+ compatible = "qcom,rpm-msm8916";
+ qcom,smd-channels = "rpm_requests";
+
+ interconnect-smd-rpm {
+ compatible = "qcom,interconnect-smd-rpm";
+ };
+
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
index 8a6ffce12af5..7c71a6ed465a 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
@@ -17,10 +17,19 @@ conditions.
"arm,mmu-401"
"arm,mmu-500"
"cavium,smmu-v2"
+ "qcom,<soc>-smmu-v2", "qcom,smmu-v2"
depending on the particular implementation and/or the
version of the architecture implemented.
+ A number of Qcom SoCs use qcom,smmu-v2 version of the IP.
+ "qcom,<soc>-smmu-v2" represents a soc specific compatible
+ string that should be present along with the "qcom,smmu-v2"
+ to facilitate SoC specific clocks/power connections and to
+ address specific bug fixes.
+ An example string would be -
+ "qcom,msm8996-smmu-v2", "qcom,smmu-v2".
+
- reg : Base address and size of the SMMU.
- #global-interrupts : The number of global interrupts exposed by the
@@ -71,6 +80,22 @@ conditions.
or using stream matching with #iommu-cells = <2>, and
may be ignored if present in such cases.
+- clock-names: List of the names of clocks input to the device. The
+ required list depends on particular implementation and
+ is as follows:
+ - for "qcom,smmu-v2":
+ - "bus": clock required for downstream bus access and
+ for the smmu ptw,
+ - "iface": clock required to access smmu's registers
+ through the TCU's programming interface.
+ - unspecified for other implementations.
+
+- clocks: Specifiers for all clocks listed in the clock-names property,
+ as per generic clock bindings.
+
+- power-domains: Specifiers for power domains required to be powered on for
+ the SMMU to operate, as per generic power domain bindings.
+
** Deprecated properties:
- mmu-masters (deprecated in favour of the generic "iommus" binding) :
@@ -137,3 +162,20 @@ conditions.
iommu-map = <0 &smmu3 0 0x400>;
...
};
+
+ /* Qcom's arm,smmu-v2 implementation */
+ smmu4: iommu {
+ compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+ reg = <0xd00000 0x10000>;
+
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+ power-domains = <&mmcc MDSS_GDSC>;
+
+ clocks = <&mmcc SMMU_MDP_AXI_CLK>,
+ <&mmcc SMMU_MDP_AHB_CLK>;
+ clock-names = "bus", "iface";
+ };
diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
index 266a1bb8bb6e..5ab216f9ece8 100644
--- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
+++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
@@ -11,6 +11,7 @@ Required properties:
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845.
+ "qcom,sdm845-qmp-ufs-phy" for UFS PHY on SDM845
- reg: offset and length of register set for PHY's common serdes block.
diff --git a/Documentation/devicetree/bindings/power/avs/qcom,cpr.txt b/Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
new file mode 100644
index 000000000000..873128c66644
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
@@ -0,0 +1,125 @@
+QCOM CPR (Core Power Reduction)
+
+CPR (Core Power Reduction) is a technology to reduce core power on a CPU
+or other device. Each OPP of a device corresponds to a "corner" that has
+a range of valid voltages for a particular frequency. While the device is
+running at a particular frequency, CPR monitors dynamic factors such as
+temperature, etc. and suggests adjustments to the voltage to save power
+and meet silicon characteristic requirements.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qcom,cpr"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: base address and size of the rbcpr register region
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: list of three interrupts in order of irq0, irq1, irq2
+
+- acc-syscon:
+ Usage: optional
+ Value type: <phandle>
+ Definition: phandle to syscon for writing ACC settings
+
+- nvmem:
+ Usage: required
+ Value type: <phandle>
+ Definition: phandle to nvmem provider containing efuse settings
+
+- nvmem-names:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qfprom"
+
+vdd-mx-supply = <&pm8916_l3>;
+
+- qcom,cpr-ref-clk:
+ Usage: required
+ Value type: <u32>
+ Definition: rate of reference clock in kHz
+
+- qcom,cpr-timer-delay-us:
+ Usage: required
+ Value type: <u32>
+ Definition: delay in uS for the timer interval
+
+- qcom,cpr-timer-cons-up:
+ Usage: required
+ Value type: <u32>
+ Definition: Consecutive number of timer intervals, or units of
+ qcom,cpr-timer-delay-us, that occur before issuing an up
+ interrupt
+
+- qcom,cpr-timer-cons-down:
+ Usage: required
+ Value type: <u32>
+ Definition: Consecutive number of timer intervals, or units of
+ qcom,cpr-timer-delay-us, that occur before issuing a down
+ interrupt
+
+- qcom,cpr-up-threshold:
+ Usage: optional
+ Value type: <u32>
+ Definition: The threshold for CPR to issue interrupt when error_steps
+ is greater than it when stepping up
+
+- qcom,cpr-down-threshold:
+ Usage: optional
+ Value type: <u32>
+ Definition: The threshold for CPR to issue interrdownt when error_steps
+ is greater than it when stepping down
+
+- qcom,cpr-down-threshold:
+ Usage: optional
+ Value type: <u32>
+ Definition: Idle clock cycles ring oscillator can be in
+
+- qcom,cpr-gcnt-us:
+ Usage: required
+ Value type: <u32>
+ Definition: The time for gate count in uS
+
+- qcom,vdd-apc-step-up-limit:
+ Usage: required
+ Value type: <u32>
+ Definition: Limit of vdd-apc-supply steps for scaling up
+
+- qcom,vdd-apc-step-down-limit:
+ Usage: required
+ Value type: <u32>
+ Definition: Limit of vdd-apc-supply steps for scaling down
+
+- qcom,cpr-cpus:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: List of CPUs that are being monitored
+
+Example:
+
+ avs@b018000 {
+ compatible = "qcom,cpr";
+ reg = <0xb018000 0x1000>;
+ interrupts = <0 15 1>, <0 16 1>, <0 17 1>;
+ vdd-mx-supply = <&pm8916_l3>;
+ acc-syscon = <&tcsr>;
+ nvmem = <&qfprom>;
+ nvmem-names = "qfprom";
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay-us = <5000>;
+ qcom,cpr-timer-cons-up = <0>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-up-threshold = <0>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <15>;
+ qcom,cpr-gcnt-us = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-cpus = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ };
diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
new file mode 100644
index 000000000000..7ef2dbe48e8a
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.txt
@@ -0,0 +1,160 @@
+Qualcomm Technologies, Inc. RPMh Regulators
+
+rpmh-regulator devices support PMIC regulator management via the Voltage
+Regulator Manager (VRM) and Oscillator Buffer (XOB) RPMh accelerators. The APPS
+processor communicates with these hardware blocks via a Resource State
+Coordinator (RSC) using command packets. The VRM allows changing three
+parameters for a given regulator: enable state, output voltage, and operating
+mode. The XOB allows changing only a single parameter for a given regulator:
+its enable state. Despite its name, the XOB is capable of controlling the
+enable state of any PMIC peripheral. It is used for clock buffers, low-voltage
+switches, and LDO/SMPS regulators which have a fixed voltage and mode.
+
+=======================
+Required Node Structure
+=======================
+
+RPMh regulators must be described in two levels of device nodes. The first
+level describes the PMIC containing the regulators and must reside within an
+RPMh device node. The second level describes each regulator within the PMIC
+which is to be used on the board. Each of these regulators maps to a single
+RPMh resource.
+
+The names used for regulator nodes must match those supported by a given PMIC.
+Supported regulator node names:
+ PM8998: smps1 - smps13, ldo1 - ldo28, lvs1 - lvs2
+ PMI8998: bob
+ PM8005: smps1 - smps4
+
+========================
+First Level Nodes - PMIC
+========================
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must be one of: "qcom,pm8998-rpmh-regulators",
+ "qcom,pmi8998-rpmh-regulators" or
+ "qcom,pm8005-rpmh-regulators".
+
+- qcom,pmic-id
+ Usage: required
+ Value type: <string>
+ Definition: RPMh resource name suffix used for the regulators found on
+ this PMIC. Typical values: "a", "b", "c", "d", "e", "f".
+
+- vdd-s1-supply
+- vdd-s2-supply
+- vdd-s3-supply
+- vdd-s4-supply
+ Usage: optional (PM8998 and PM8005 only)
+ Value type: <phandle>
+ Definition: phandle of the parent supply regulator of one or more of the
+ regulators for this PMIC.
+
+- vdd-s5-supply
+- vdd-s6-supply
+- vdd-s7-supply
+- vdd-s8-supply
+- vdd-s9-supply
+- vdd-s10-supply
+- vdd-s11-supply
+- vdd-s12-supply
+- vdd-s13-supply
+- vdd-l1-l27-supply
+- vdd-l2-l8-l17-supply
+- vdd-l3-l11-supply
+- vdd-l4-l5-supply
+- vdd-l6-supply
+- vdd-l7-l12-l14-l15-supply
+- vdd-l9-supply
+- vdd-l10-l23-l25-supply
+- vdd-l13-l19-l21-supply
+- vdd-l16-l28-supply
+- vdd-l18-l22-supply
+- vdd-l20-l24-supply
+- vdd-l26-supply
+- vin-lvs-1-2-supply
+ Usage: optional (PM8998 only)
+ Value type: <phandle>
+ Definition: phandle of the parent supply regulator of one or more of the
+ regulators for this PMIC.
+
+- vdd-bob-supply
+ Usage: optional (PMI8998 only)
+ Value type: <phandle>
+ Definition: BOB regulator parent supply phandle
+
+===============================
+Second Level Nodes - Regulators
+===============================
+
+- qcom,always-wait-for-ack
+ Usage: optional
+ Value type: <empty>
+ Definition: Boolean flag which indicates that the application processor
+ must wait for an ACK or a NACK from RPMh for every request
+ sent for this regulator including those which are for a
+ strictly lower power state.
+
+Other properties defined in Documentation/devicetree/bindings/regulator.txt
+may also be used. regulator-initial-mode and regulator-allowed-modes may be
+specified for VRM regulators using mode values from
+include/dt-bindings/regulator/qcom,rpmh-regulator.h. regulator-allow-bypass
+may be specified for BOB type regulators managed via VRM.
+regulator-allow-set-load may be specified for LDO type regulators managed via
+VRM.
+
+========
+Examples
+========
+
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+&apps_rsc {
+ pm8998-rpmh-regulators {
+ compatible = "qcom,pm8998-rpmh-regulators";
+ qcom,pmic-id = "a";
+
+ vdd-l7-l12-l14-l15-supply = <&pm8998_s5>;
+
+ smps2 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ };
+
+ pm8998_s5: smps5 {
+ regulator-min-microvolt = <1904000>;
+ regulator-max-microvolt = <2040000>;
+ };
+
+ ldo7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
+ regulator-allowed-modes =
+ <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ };
+
+ lvs1 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+
+ pmi8998-rpmh-regulators {
+ compatible = "qcom,pmi8998-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ bob {
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3600000>;
+ regulator-allowed-modes =
+ <RPMH_REGULATOR_MODE_AUTO
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_AUTO>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt
index 728e4193f7a6..b7d058228185 100644
--- a/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt
+++ b/Documentation/devicetree/bindings/remoteproc/qcom,adsp.txt
@@ -10,6 +10,8 @@ on the Qualcomm ADSP Hexagon core.
"qcom,msm8974-adsp-pil"
"qcom,msm8996-adsp-pil"
"qcom,msm8996-slpi-pil"
+ "qcom,sdm845-adsp-pas"
+ "qcom,sdm845-cdsp-pas"
- interrupts-extended:
Usage: required
diff --git a/Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt
new file mode 100644
index 000000000000..cd5dcafb4ed7
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/qcom,aoss-reset.txt
@@ -0,0 +1,52 @@
+Qualcomm AOSS Reset Controller
+======================================
+
+This binding describes a reset-controller found on AOSS (always on subsystem)
+for Qualcomm SDM845 SoCs.
+
+Required properties:
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be:
+ "qcom,sdm845-aoss-reset"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: must specify the base address and size of the register
+ space.
+
+- #reset-cells:
+ Usage: required
+ Value type: <uint>
+ Definition: must be 1; cell entry represents the reset index.
+
+Example:
+
+aoss_reset: reset-controller@c2b0000 {
+ compatible = "qcom,sdm845-aoss-reset";
+ reg = <0xc2b0000 0x21000>;
+ #reset-cells = <1>;
+};
+
+Specifying reset lines connected to IP modules
+==============================================
+
+Device nodes that need access to reset lines should
+specify them as a reset phandle in their corresponding node as
+specified in reset.txt.
+
+For list of all valid reset indicies see
+<dt-bindings/reset/qcom,sdm845-aoss.h>
+
+Example:
+
+modem-pil@4080000 {
+ ...
+
+ resets = <&aoss_reset AOSS_CC_MSS_RESTART>;
+ reset-names = "mss_restart";
+
+ ...
+};
diff --git a/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt b/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt
new file mode 100644
index 000000000000..e94a2ad3a710
--- /dev/null
+++ b/Documentation/devicetree/bindings/slimbus/slim-ngd-qcom-ctrl.txt
@@ -0,0 +1,84 @@
+Qualcomm SLIMBus Non Generic Device (NGD) Controller binding
+
+SLIMBus NGD controller is a light-weight driver responsible for communicating
+with SLIMBus slaves directly over the bus using messaging interface and
+communicating with master component residing on ADSP for bandwidth and
+data-channel management
+
+Please refer to slimbus/bus.txt for details of the common SLIMBus bindings.
+
+- compatible:
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be "qcom,slim-ngd-v<MAJOR>.<MINOR>.<STEP>"
+ must be one of the following.
+ "qcom,slim-ngd-v1.5.0" for MSM8996
+ "qcom,slim-ngd-v2.1.0" for SDM845
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: must specify the base address and size of the controller
+ register space.
+- dmas
+ Usage: required
+ Value type: <array of phandles>
+ Definition: List of rx and tx dma channels
+
+- dma-names
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be "rx" and "tx".
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: must list controller IRQ.
+
+#address-cells
+ Usage: required
+ Value type: <u32>
+ Definition: Should be 1, reflecting the instance id of ngd.
+
+#size-cells
+ Usage: required
+ Value type: <u32>
+ Definition: Should be 0
+
+= NGD Devices
+Each subnode represents an instance of NGD, must contain the following
+properties:
+
+- reg:
+ Usage: required
+ Value type: <u32>
+ Definition: Should be instance id of ngd.
+
+#address-cells
+ Usage: required
+ Refer to slimbus/bus.txt for details of the common SLIMBus bindings.
+
+#size-cells
+ Usage: required
+ Refer to slimbus/bus.txt for details of the common SLIMBus bindings.
+
+= EXAMPLE
+
+slim@91c0000 {
+ compatible = "qcom,slim-ngd-v1.5.0";
+ reg = <0x91c0000 0x2c000>;
+ interrupts = <0 163 0>;
+ dmas = <&slimbam 3>, <&slimbam 4>;
+ dma-names = "rx", "tx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ngd@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ codec@1 {
+ compatible = "slim217,1a0";
+ reg = <1 0>;
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt b/Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt
new file mode 100644
index 000000000000..e15c100f5c92
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/rpmh-rsc.txt
@@ -0,0 +1,137 @@
+RPMH RSC:
+------------
+
+Resource Power Manager Hardened (RPMH) is the mechanism for communicating with
+the hardened resource accelerators on Qualcomm SoCs. Requests to the resources
+can be written to the Trigger Command Set (TCS) registers and using a (addr,
+val) pair and triggered. Messages in the TCS are then sent in sequence over an
+internal bus.
+
+The hardware block (Direct Resource Voter or DRV) is a part of the h/w entity
+(Resource State Coordinator a.k.a RSC) that can handle multiple sleep and
+active/wake resource requests. Multiple such DRVs can exist in a SoC and can
+be written to from Linux. The structure of each DRV follows the same template
+with a few variations that are captured by the properties here.
+
+A TCS may be triggered from Linux or triggered by the F/W after all the CPUs
+have powered off to facilitate idle power saving. TCS could be classified as -
+
+ SLEEP /* Triggered by F/W */
+ WAKE /* Triggered by F/W */
+ ACTIVE /* Triggered by Linux */
+ CONTROL /* Triggered by F/W */
+
+The order in which they are described in the DT, should match the hardware
+configuration.
+
+Requests can be made for the state of a resource, when the subsystem is active
+or idle. When all subsystems like Modem, GPU, CPU are idle, the resource state
+will be an aggregate of the sleep votes from each of those subsystems. Clients
+may request a sleep value for their shared resources in addition to the active
+mode requests.
+
+Properties:
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,rpmh-rsc".
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: The first register specifies the base address of the
+ DRV(s). The number of DRVs in the dependent on the RSC.
+ The tcs-offset specifies the start address of the
+ TCS in the DRVs.
+
+- reg-names:
+ Usage: required
+ Value type: <string>
+ Definition: Maps the register specified in the reg property. Must be
+ "drv-0", "drv-1", "drv-2" etc and "tcs-offset". The
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-interrupt>
+ Definition: The interrupt that trips when a message complete/response
+ is received for this DRV from the accelerators.
+
+- qcom,drv-id:
+ Usage: required
+ Value type: <u32>
+ Definition: The id of the DRV in the RSC block that will be used by
+ this controller.
+
+- qcom,tcs-config:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: The tuple defining the configuration of TCS.
+ Must have 2 cells which describe each TCS type.
+ <type number_of_tcs>.
+ The order of the TCS must match the hardware
+ configuration.
+ - Cell #1 (TCS Type): TCS types to be specified -
+ SLEEP_TCS
+ WAKE_TCS
+ ACTIVE_TCS
+ CONTROL_TCS
+ - Cell #2 (Number of TCS): <u32>
+
+- label:
+ Usage: optional
+ Value type: <string>
+ Definition: Name for the RSC. The name would be used in trace logs.
+
+Drivers that want to use the RSC to communicate with RPMH must specify their
+bindings as child nodes of the RSC controllers they wish to communicate with.
+
+Example 1:
+
+For a TCS whose RSC base address is is 0x179C0000 and is at a DRV id of 2, the
+register offsets for DRV2 start at 0D00, the register calculations are like
+this -
+DRV0: 0x179C0000
+DRV2: 0x179C0000 + 0x10000 = 0x179D0000
+DRV2: 0x179C0000 + 0x10000 * 2 = 0x179E0000
+TCS-OFFSET: 0xD00
+
+ apps_rsc: rsc@179c0000 {
+ label = "apps_rsc";
+ compatible = "qcom,rpmh-rsc";
+ reg = <0x179c0000 0x10000>,
+ <0x179d0000 0x10000>,
+ <0x179e0000 0x10000>;
+ reg-names = "drv-0", "drv-1", "drv-2";
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,tcs-offset = <0xd00>;
+ qcom,drv-id = <2>;
+ qcom,tcs-config = <SLEEP_TCS 3>,
+ <WAKE_TCS 3>,
+ <ACTIVE_TCS 2>,
+ <CONTROL_TCS 1>;
+ };
+
+Example 2:
+
+For a TCS whose RSC base address is 0xAF20000 and is at DRV id of 0, the
+register offsets for DRV0 start at 01C00, the register calculations are like
+this -
+DRV0: 0xAF20000
+TCS-OFFSET: 0x1C00
+
+ disp_rsc: rsc@af20000 {
+ label = "disp_rsc";
+ compatible = "qcom,rpmh-rsc";
+ reg = <0xaf20000 0x10000>;
+ reg-names = "drv-0";
+ interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,tcs-offset = <0x1c00>;
+ qcom,drv-id = <0>;
+ qcom,tcs-config = <SLEEP_TCS 1>,
+ <WAKE_TCS 1>,
+ <ACTIVE_TCS 0>,
+ <CONTROL_TCS 0>;
+ };
diff --git a/Documentation/interconnect/interconnect.rst b/Documentation/interconnect/interconnect.rst
new file mode 100644
index 000000000000..a1ebd83ad0a1
--- /dev/null
+++ b/Documentation/interconnect/interconnect.rst
@@ -0,0 +1,96 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=====================================
+GENERIC SYSTEM INTERCONNECT SUBSYSTEM
+=====================================
+
+Introduction
+------------
+
+This framework is designed to provide a standard kernel interface to control
+the settings of the interconnects on a SoC. These settings can be throughput,
+latency and priority between multiple interconnected devices or functional
+blocks. This can be controlled dynamically in order to save power or provide
+maximum performance.
+
+The interconnect bus is a hardware with configurable parameters, which can be
+set on a data path according to the requests received from various drivers.
+An example of interconnect buses are the interconnects between various
+components or functional blocks in chipsets. There can be multiple interconnects
+on a SoC that can be multi-tiered.
+
+Below is a simplified diagram of a real-world SoC interconnect bus topology.
+
+::
+
+ +----------------+ +----------------+
+ | HW Accelerator |--->| M NoC |<---------------+
+ +----------------+ +----------------+ |
+ | | +------------+
+ +-----+ +-------------+ V +------+ | |
+ | DDR | | +--------+ | PCIe | | |
+ +-----+ | | Slaves | +------+ | |
+ ^ ^ | +--------+ | | C NoC |
+ | | V V | |
+ +------------------+ +------------------------+ | | +-----+
+ | |-->| |-->| |-->| CPU |
+ | |-->| |<--| | +-----+
+ | Mem NoC | | S NoC | +------------+
+ | |<--| |---------+ |
+ | |<--| |<------+ | | +--------+
+ +------------------+ +------------------------+ | | +-->| Slaves |
+ ^ ^ ^ ^ ^ | | +--------+
+ | | | | | | V
+ +------+ | +-----+ +-----+ +---------+ +----------------+ +--------+
+ | CPUs | | | GPU | | DSP | | Masters |-->| P NoC |-->| Slaves |
+ +------+ | +-----+ +-----+ +---------+ +----------------+ +--------+
+ |
+ +-------+
+ | Modem |
+ +-------+
+
+Terminology
+-----------
+
+Interconnect provider is the software definition of the interconnect hardware.
+The interconnect providers on the above diagram are M NoC, S NoC, C NoC, P NoC
+and Mem NoC.
+
+Interconnect node is the software definition of the interconnect hardware
+port. Each interconnect provider consists of multiple interconnect nodes,
+which are connected to other SoC components including other interconnect
+providers. The point on the diagram where the CPUs connects to the memory is
+called an interconnect node, which belongs to the Mem NoC interconnect provider.
+
+Interconnect endpoints are the first or the last element of the path. Every
+endpoint is a node, but not every node is an endpoint.
+
+Interconnect path is everything between two endpoints including all the nodes
+that have to be traversed to reach from a source to destination node. It may
+include multiple master-slave pairs across several interconnect providers.
+
+Interconnect consumers are the entities which make use of the data paths exposed
+by the providers. The consumers send requests to providers requesting various
+throughput, latency and priority. Usually the consumers are device drivers, that
+send request based on their needs. An example for a consumer is a video decoder
+that supports various formats and image sizes.
+
+Interconnect providers
+----------------------
+
+Interconnect provider is an entity that implements methods to initialize and
+configure a interconnect bus hardware. The interconnect provider drivers should
+be registered with the interconnect provider core.
+
+The interconnect framework provider API functions are documented in
+.. kernel-doc:: include/linux/interconnect-provider.h
+
+Interconnect consumers
+----------------------
+
+Interconnect consumers are the clients which use the interconnect APIs to
+get paths between endpoints and set their bandwidth/latency/QoS requirements
+for these interconnect paths.
+
+The interconnect framework consumer API functions are documented in
+.. kernel-doc:: include/linux/interconnect.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 96e98e206b0d..72477747699a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7419,6 +7419,16 @@ L: linux-gpio@vger.kernel.org
S: Maintained
F: drivers/gpio/gpio-intel-mid.c
+INTERCONNECT API
+M: Georgi Djakov <georgi.djakov@linaro.org>
+S: Maintained
+F: Documentation/interconnect/
+F: Documentation/devicetree/bindings/interconnect/
+F: drivers/interconnect/
+F: include/linux/dt-bindings/interconnect/
+F: include/linux/interconnect-provider.h
+F: include/linux/interconnect.h
+
INVENSENSE MPU-3050 GYROSCOPE DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-iio@vger.kernel.org
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index d5aeac351fc3..d69d383e962b 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -145,6 +145,13 @@ config ARCH_REALTEK
This enables support for the ARMv8 based Realtek chipsets,
like the RTD1295.
+config ARCH_MSM8996
+ bool "Enable Support for Qualcomm Technologies, Inc. MSM8996"
+ depends on ARCH_QCOM
+ help
+ This enables support for the MSM8996 chipset. If you do not
+ wish to build a kernel that runs on this chipset, say 'N' here.
+
config ARCH_ROCKCHIP
bool "Rockchip Platforms"
select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
index 9ff848792712..e3996857857f 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
@@ -499,6 +499,10 @@
};
};
+ hexagon@4080000 {
+ status = "okay";
+ };
+
wcnss@a21b000 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
index 6a573875d45a..1c0d06f59d00 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c-pins.dtsi
@@ -62,4 +62,56 @@
bias-disable;
};
};
+
+ hdmi_hpd_active: hdmi_hpd_active {
+ mux {
+ pins = "gpio34";
+ function = "hdmi_hot";
+ };
+
+ config {
+ pins = "gpio34";
+ bias-pull-down;
+ drive-strength = <16>;
+ };
+ };
+
+ hdmi_hpd_suspend: hdmi_hpd_suspend {
+ mux {
+ pins = "gpio34";
+ function = "hdmi_hot";
+ };
+
+ config {
+ pins = "gpio34";
+ bias-pull-down;
+ drive-strength = <2>;
+ };
+ };
+
+ hdmi_ddc_active: hdmi_ddc_active {
+ mux {
+ pins = "gpio32", "gpio33";
+ function = "hdmi_ddc";
+ };
+
+ config {
+ pins = "gpio32", "gpio33";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+ };
+
+ hdmi_ddc_suspend: hdmi_ddc_suspend {
+ mux {
+ pins = "gpio32", "gpio33";
+ function = "hdmi_ddc";
+ };
+
+ config {
+ pins = "gpio32", "gpio33";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi
index a6ad3d7fe655..7c5045949c01 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c-pmic-pins.dtsi
@@ -36,6 +36,15 @@
};
};
+
+ audio_mclk: clk_div1 {
+ pinconf {
+ pins = "gpio15";
+ function = "func1";
+ power-source = <PM8994_GPIO_S4>; // 1.8V
+ };
+ };
+
volume_up_gpio: pm8996_gpio2 {
pinconf {
pins = "gpio2";
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dts b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
index 230e9c8484ac..632cb42bdec5 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016,2018 The Linux Foundation. All rights reserved.
*
* This 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,5 +17,5 @@
/ {
model = "Qualcomm Technologies, Inc. DB820c";
- compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc";
+ compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc", "qcom,apq8096";
};
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
index 4d5ef01f43a3..d720455c7fb8 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014-2016,2018 The Linux Foundation. All rights reserved.
*
* This 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,7 +18,8 @@
#include "apq8096-db820c-pmic-pins.dtsi"
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
-
+#include <dt-bindings/sound/qcom,q6afe.h>
+#include <dt-bindings/sound/qcom,q6asm.h>
/ {
aliases {
serial0 = &blsp2_uart1;
@@ -211,6 +212,47 @@
perst-gpio = <&msmgpio 114 GPIO_ACTIVE_LOW>;
};
};
+
+ slim_msm: slim@91c0000 {
+ ngd@1 {
+ tasha_codec: tas {
+ pinctrl-0 = <&cdc_reset_active &wcd_intr_default &audio_mclk>;
+ pinctrl-names = "default";
+ qcom,clk1-gpio = <&pm8994_gpios 15 0>;
+ };
+ };
+ };
+
+ mdss@900000 {
+ status = "okay";
+
+ mdp@901000 {
+ status = "okay";
+ };
+
+ hdmi-phy@9a0600 {
+ status = "okay";
+
+ vddio-supply = <&pm8994_l12>;
+ vcca-supply = <&pm8994_l28>;
+ #phy-cells = <0>;
+ };
+
+ hdmi-tx@9a0000 {
+ status = "okay";
+
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&hdmi_hpd_active &hdmi_ddc_active>;
+ pinctrl-1 = <&hdmi_hpd_suspend &hdmi_ddc_suspend>;
+
+ core-vdda-supply = <&pm8994_l12>;
+ core-vcc-supply = <&pm8994_s4>;
+ };
+ };
+
+ remoteproc@2080000 {
+ status = "okay";
+ };
};
@@ -384,3 +426,52 @@
};
};
};
+&sound {
+ compatible = "qcom,apq8096-sndcard";
+ qcom,model = "DB820c";
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK";
+ mm1-dai-link {
+ link-name = "MultiMedia1";
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
+ };
+ };
+
+ mm2-dai-link {
+ link-name = "MultiMedia2";
+ cpu {
+ sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA2>;
+ };
+ };
+
+ hdmi-dai-link {
+ link-name = "HDMI";
+ cpu {
+ sound-dai = <&q6afedai HDMI_RX>;
+ };
+
+ platform {
+ sound-dai = <&q6routing>;
+ };
+
+ codec {
+ sound-dai = <&hdmi 0>;
+ };
+ };
+
+ slim-dai-link {
+ link-name = "SLIM";
+ cpu {
+ sound-dai = <&q6afedai SLIMBUS_6_RX>;
+ };
+
+ platform {
+ sound-dai = <&q6routing>;
+ };
+
+ codec {
+ sound-dai = <&wcd9335 3>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index cacb7a140db7..cc1040eacdf5 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/interconnect/qcom.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8916.h>
#include <dt-bindings/reset/qcom,gcc-msm8916.h>
@@ -115,6 +116,7 @@
enable-method = "psci";
cpu-idle-states = <&CPU_SPC>;
clocks = <&apcs 0>;
+ cpu-supply = <&pm8916_spmi_s2>;
operating-points-v2 = <&cpu_opp_table>;
#cooling-cells = <2>;
};
@@ -127,6 +129,7 @@
enable-method = "psci";
cpu-idle-states = <&CPU_SPC>;
clocks = <&apcs 0>;
+ cpu-supply = <&pm8916_spmi_s2>;
operating-points-v2 = <&cpu_opp_table>;
#cooling-cells = <2>;
};
@@ -139,6 +142,7 @@
enable-method = "psci";
cpu-idle-states = <&CPU_SPC>;
clocks = <&apcs 0>;
+ cpu-supply = <&pm8916_spmi_s2>;
operating-points-v2 = <&cpu_opp_table>;
#cooling-cells = <2>;
};
@@ -151,6 +155,7 @@
enable-method = "psci";
cpu-idle-states = <&CPU_SPC>;
clocks = <&apcs 0>;
+ cpu-supply = <&pm8916_spmi_s2>;
operating-points-v2 = <&cpu_opp_table>;
#cooling-cells = <2>;
};
@@ -1402,6 +1407,68 @@
compatible = "venus-encoder";
};
};
+
+ uqfprom: eeprom@58000 {
+ compatible = "qcom,qfprom-msm8916";
+ reg = <0x58000 0x7000>;
+ };
+
+ cpr@b018000 {
+ compatible = "qcom,cpr";
+ reg = <0xb018000 0x1000>;
+ interrupts = <0 15 1>, <0 16 1>, <0 17 1>;
+ vdd-mx-supply = <&pm8916_l3>;
+ acc-syscon = <&tcsr>;
+ eeprom = <&uqfprom>;
+
+ qcom,cpr-ref-clk = <19200>;
+ qcom,cpr-timer-delay-us = <5000>;
+ qcom,cpr-timer-cons-up = <0>;
+ qcom,cpr-timer-cons-down = <2>;
+ qcom,cpr-up-threshold = <0>;
+ qcom,cpr-down-threshold = <2>;
+ qcom,cpr-idle-clocks = <15>;
+ qcom,cpr-gcnt-us = <1>;
+ qcom,vdd-apc-step-up-limit = <1>;
+ qcom,vdd-apc-step-down-limit = <1>;
+ qcom,cpr-cpus = <&CPU0 &CPU1 &CPU2 &CPU3>;
+ };
+
+ bimc: bimc@400000 {
+ compatible = "qcom,msm8916-bimc";
+ #interconnect-cells = <1>;
+ reg = <0x400000 0x62000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+ <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ base-offset = <0>;
+ qos-offset = <0>;
+ status = "okay";
+ };
+
+ pnoc: pnoc@500000 {
+ compatible = "qcom,msm8916-pnoc";
+ #interconnect-cells = <1>;
+ reg = <0x500000 0x11000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
+ <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ base-offset = <0x7000>;
+ qos-offset = <0x1000>;
+ status = "okay";
+ };
+
+ snoc: snoc@580000 {
+ compatible = "qcom,msm8916-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x14000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ base-offset = <0x7000>;
+ qos-offset = <0x1000>;
+ status = "okay";
+ };
};
smd {
@@ -1421,6 +1488,10 @@
#clock-cells = <1>;
};
+ interconnect-smd-rpm {
+ compatible = "qcom,interconnect-smd-rpm";
+ };
+
smd_rpm_regulators: pm8916-regulators {
compatible = "qcom,rpm-pm8916-regulators";
diff --git a/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi
index c5c42e94f387..ba2ed5978920 100644
--- a/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996-pins.dtsi
@@ -13,6 +13,52 @@
&msmgpio {
+ wcd9xxx_intr {
+ wcd_intr_default: wcd_intr_default{
+ mux {
+ pins = "gpio54";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio54";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ input-enable;
+ };
+ };
+ };
+
+
+ cdc_reset_ctrl {
+ cdc_reset_sleep: cdc_reset_sleep {
+ mux {
+ pins = "gpio64";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio64";
+ drive-strength = <16>;
+ bias-disable;
+ output-low;
+ };
+ };
+ cdc_reset_active:cdc_reset_active {
+ mux {
+ pins = "gpio64";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio64";
+ drive-strength = <16>;
+ bias-pull-down;
+ output-high;
+ };
+ };
+ };
+
+
+
blsp1_spi0_default: blsp1_spi0_default {
pinmux {
function = "blsp_spi1";
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 4f9072ea982e..b4d8e7253c35 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2015,2018 The Linux Foundation. All rights reserved.
*
* This 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,10 +10,13 @@
* GNU General Public License for more details.
*/
+#include <dt-bindings/interconnect/qcom.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/qcom,gcc-msm8996.h>
#include <dt-bindings/clock/qcom,mmcc-msm8996.h>
#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/soc/qcom,apr.h>
/ {
model = "Qualcomm Technologies, Inc. MSM8996";
@@ -41,11 +44,6 @@
no-map;
};
- slpi_region: slpi@90b00000 {
- reg = <0x0 0x90b00000 0x0 0xa00000>;
- no-map;
- };
-
venus_region: venus@90400000 {
reg = <0x0 0x90400000 0x0 0x700000>;
no-map;
@@ -86,6 +84,12 @@
qcom,client-id = <1>;
qcom,vmid = <15>;
};
+
+ zap_shader_region: gpu@8f200000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0x90b00000 0x0 0xa00000>;
+ no-map;
+ };
};
cpus {
@@ -97,6 +101,12 @@
compatible = "qcom,kryo";
reg = <0x0 0x0>;
enable-method = "psci";
+ clocks = <&kryocc 0>;
+ operating-points-v2 = <&cluster0_opp>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <15>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
compatible = "cache";
@@ -109,6 +119,12 @@
compatible = "qcom,kryo";
reg = <0x0 0x1>;
enable-method = "psci";
+ clocks = <&kryocc 0>;
+ operating-points-v2 = <&cluster0_opp>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <15>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_0>;
};
@@ -117,6 +133,12 @@
compatible = "qcom,kryo";
reg = <0x0 0x100>;
enable-method = "psci";
+ clocks = <&kryocc 1>;
+ operating-points-v2 = <&cluster1_opp>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <15>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
compatible = "cache";
@@ -129,6 +151,12 @@
compatible = "qcom,kryo";
reg = <0x0 0x101>;
enable-method = "psci";
+ clocks = <&kryocc 1>;
+ operating-points-v2 = <&cluster1_opp>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <15>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_1>;
};
@@ -155,6 +183,182 @@
};
};
+ cluster0_opp: opp_table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp@307200000 {
+ opp-hz = /bits/ 64 < 307200000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@422400000 {
+ opp-hz = /bits/ 64 < 422400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@480000000 {
+ opp-hz = /bits/ 64 < 480000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@556800000 {
+ opp-hz = /bits/ 64 < 556800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@652800000 {
+ opp-hz = /bits/ 64 < 652800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@729600000 {
+ opp-hz = /bits/ 64 < 729600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@844800000 {
+ opp-hz = /bits/ 64 < 844800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@960000000 {
+ opp-hz = /bits/ 64 < 960000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1036800000 {
+ opp-hz = /bits/ 64 < 1036800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1113600000 {
+ opp-hz = /bits/ 64 < 1113600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1190400000 {
+ opp-hz = /bits/ 64 < 1190400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1228800000 {
+ opp-hz = /bits/ 64 < 1228800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1324800000 {
+ opp-hz = /bits/ 64 < 1324800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1401600000 {
+ opp-hz = /bits/ 64 < 1401600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1478400000 {
+ opp-hz = /bits/ 64 < 1478400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1593600000 {
+ opp-hz = /bits/ 64 < 1593600000 >;
+ clock-latency-ns = <200000>;
+ };
+ };
+
+ cluster1_opp: opp_table1 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp@307200000 {
+ opp-hz = /bits/ 64 < 307200000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@403200000 {
+ opp-hz = /bits/ 64 < 403200000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@480000000 {
+ opp-hz = /bits/ 64 < 480000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@556800000 {
+ opp-hz = /bits/ 64 < 556800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@652800000 {
+ opp-hz = /bits/ 64 < 652800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@729600000 {
+ opp-hz = /bits/ 64 < 729600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@806400000 {
+ opp-hz = /bits/ 64 < 806400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@883200000 {
+ opp-hz = /bits/ 64 < 883200000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@940800000 {
+ opp-hz = /bits/ 64 < 940800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1036800000 {
+ opp-hz = /bits/ 64 < 1036800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1113600000 {
+ opp-hz = /bits/ 64 < 1113600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1190400000 {
+ opp-hz = /bits/ 64 < 1190400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1248000000 {
+ opp-hz = /bits/ 64 < 1248000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1324800000 {
+ opp-hz = /bits/ 64 < 1324800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1401600000 {
+ opp-hz = /bits/ 64 < 1401600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1478400000 {
+ opp-hz = /bits/ 64 < 1478400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1552000000 {
+ opp-hz = /bits/ 64 < 1552000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1632000000 {
+ opp-hz = /bits/ 64 < 1632000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1708800000 {
+ opp-hz = /bits/ 64 < 1708800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1785600000 {
+ opp-hz = /bits/ 64 < 1785600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1824000000 {
+ opp-hz = /bits/ 64 < 1824000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1920000000 {
+ opp-hz = /bits/ 64 < 1920000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@1996800000 {
+ opp-hz = /bits/ 64 < 1996800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@2073600000 {
+ opp-hz = /bits/ 64 < 2073600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp@2150400000 {
+ opp-hz = /bits/ 64 < 2150400000 >;
+ clock-latency-ns = <200000>;
+ };
+
+ };
thermal-zones {
cpu-thermal0 {
polling-delay-passive = <250>;
@@ -163,18 +367,33 @@
thermal-sensors = <&tsens0 3>;
trips {
- cpu_alert0: trip0 {
+ cpu_alert0: cpu_alert0 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn0: cpu_warn0 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
-
- cpu_crit0: trip1 {
+ cpu_crit0: cpu_crit0 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn0>;
+ cooling-device = <&CPU0 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal1 {
@@ -184,18 +403,33 @@
thermal-sensors = <&tsens0 5>;
trips {
- cpu_alert1: trip0 {
+ cpu_alert1: cpu_alert1 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn1: cpu_warn1 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
-
- cpu_crit1: trip1 {
+ cpu_crit1: cpu_crit1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn1>;
+ cooling-device = <&CPU0 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal2 {
@@ -205,18 +439,32 @@
thermal-sensors = <&tsens0 8>;
trips {
- cpu_alert2: trip0 {
+ cpu_alert2: cpu_alert2 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn2: cpu_warn2 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
-
- cpu_crit2: trip1 {
+ cpu_crit2: cpu_crit2 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert2>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn2>;
+ cooling-device = <&CPU2 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal3 {
@@ -226,18 +474,33 @@
thermal-sensors = <&tsens0 10>;
trips {
- cpu_alert3: trip0 {
+ cpu_alert3: cpu_alert3 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn3: cpu_warn3 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
-
cpu_crit3: trip1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert3>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn3>;
+ cooling-device = <&CPU2 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
};
@@ -308,6 +571,10 @@
#clock-cells = <1>;
};
+ interconnect-smd-rpm {
+ compatible = "qcom,interconnect-smd-rpm";
+ };
+
pm8994-regulators {
compatible = "qcom,rpm-pm8994-regulators";
@@ -357,7 +624,6 @@
pm8994_l31: l31 {};
pm8994_l32: l32 {};
};
-
};
};
@@ -374,7 +640,7 @@
tcsr_mutex_regs: syscon@740000 {
compatible = "syscon";
- reg = <0x740000 0x20000>;
+ reg = <0x740000 0x40000>;
};
tcsr: syscon@7a0000 {
@@ -393,11 +659,6 @@
interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
};
- apcs: syscon@9820000 {
- compatible = "syscon";
- reg = <0x9820000 0x1000>;
- };
-
apcs_glb: mailbox@9820000 {
compatible = "qcom,msm8996-apcs-hmss-global";
reg = <0x9820000 0x1000>;
@@ -414,7 +675,7 @@
};
kryocc: clock-controller@6400000 {
- compatible = "qcom,apcc-msm8996";
+ compatible = "qcom-msm8996-apcc";
reg = <0x6400000 0x90000>;
#clock-cells = <1>;
};
@@ -1129,6 +1390,489 @@
interconnect-names = "ddr";
};
};
+
+ slimbam:dma@9184000
+ {
+ compatible = "qcom,bam-v1.7.0";
+ qcom,controlled-remotely;
+ reg = <0x9184000 0x32000>;
+ num-channels = <31>;
+ interrupts = <0 164 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+ qcom,ee = <1>;
+ qcom,num-ees = <2>;
+ };
+
+ slim_msm: slim@91c0000 {
+ compatible = "qcom,slim-ngd-v1.5.0";
+ reg = <0x91c0000 0x2C000>;
+ reg-names = "ctrl";
+ interrupts = <0 163 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,apps-ch-pipes = <0x60000000>;
+ qcom,ea-pc = <0x160>;
+ dmas = <&slimbam 3>, <&slimbam 4>,
+ <&slimbam 5>, <&slimbam 6>;
+ dma-names = "rx", "tx", "tx2", "rx2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ngd@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ tasha_ifd: tas-ifd {
+ compatible = "slim217,1a0";
+ reg = <0 0>;
+ };
+
+ tasha_codec: tas {
+ pinctrl-0 = <&cdc_reset_active &wcd_intr_default>;
+ pinctrl-1 = <&cdc_reset_sleep>;
+ pinctrl-names = "default", "sleep";
+
+ compatible = "slim217,1a0";
+ reg = <1 0>;
+ qcom,gpio-int2 = <&msmgpio 54 0>;
+ qcom,cdc-reset-gpio = <&msmgpio 64 0>;
+ ifd = <&tasha_ifd>;
+ clock-names = "mclk", "native";
+ clocks = <&rpmcc RPM_SMD_DIV_CLK1>,
+ <&rpmcc RPM_SMD_BB_CLK1>;
+
+ vdd-buck-supply = <&pm8994_s4>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ buck-sido-supply = <&pm8994_s4>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <250000>;
+
+ vdd-tx-h-supply = <&pm8994_s4>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ vdd-rx-h-supply = <&pm8994_s4>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ vddpx-1-supply = <&pm8994_s4>;
+ qcom,cdc-vddpx-1-voltage = <1800000 1800000>;
+ qcom,cdc-vddpx-1-current = <10000>;
+
+ qcom,cdc-micbias1-mv = <1800>;
+ qcom,cdc-micbias2-mv = <1800>;
+ qcom,cdc-micbias3-mv = <1800>;
+ qcom,cdc-micbias4-mv = <1800>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ qcom,cdc-dmic-sample-rate = <4800000>;
+ qcom,cdc-mad-dmic-rate = <600000>;
+
+ wcd9335:wcd {
+ compatible = "qcom,wcd9335";
+ #sound-dai-cells = <1>;
+ };
+ };
+ };
+ };
+
+ adreno_smmu: arm,smmu@b40000 {
+ compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+ reg = <0xb40000 0x10000>;
+
+ #global-interrupts = <1>;
+ interrupts = <0 334 IRQ_TYPE_LEVEL_HIGH>,
+ <0 329 IRQ_TYPE_LEVEL_HIGH>,
+ <0 330 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+
+ clocks = <&mmcc GPU_AHB_CLK>,
+ <&gcc GCC_MMSS_BIMC_GFX_CLK>;
+ clock-names = "bus", "iface";
+
+ power-domains = <&mmcc GPU_GDSC>;
+
+ status = "okay";
+ };
+
+ gpu@b00000 {
+ compatible = "qcom,adreno-530.2", "qcom,adreno";
+ #stream-id-cells = <16>;
+
+ reg = <0xb00000 0x3f000>;
+ reg-names = "kgsl_3d0_reg_memory";
+
+ interrupts = <0 300 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "kgsl_3d0_irq";
+
+ clocks = <&mmcc GPU_GX_GFX3D_CLK>,
+ <&mmcc GPU_AHB_CLK>,
+ <&mmcc GPU_GX_RBBMTIMER_CLK>,
+ <&gcc GCC_BIMC_GFX_CLK>,
+ <&gcc GCC_MMSS_BIMC_GFX_CLK>;
+
+ clock-names = "core",
+ "iface",
+ "rbbmtimer",
+ "mem",
+ "mem_iface";
+
+ power-domains = <&mmcc GPU_GDSC>;
+ iommus = <&adreno_smmu 0>;
+
+ qcom,gpu-quirk-two-pass-use-wfi;
+ qcom,gpu-quirk-fault-detect-mask;
+
+ /* This is a safe speed for bring up in all bin levels.
+ * This isn't the fastest the chip can go, but we can
+ * get there eventually */
+ qcom,gpu-pwrlevels {
+ compatible = "qcom,gpu-pwrlevels";
+ qcom,gpu-pwrlevel@0 {
+ qcom,gpu-freq = <510000000>;
+ };
+ qcom,gpu-pwrlevel@1 {
+ qcom,gpu-freq = <27000000>;
+ };
+ };
+
+ zap-shader {
+ memory-region = <&zap_shader_region>;
+ };
+ };
+
+ mdp_smmu: arm,smmu@d00000 {
+ compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+ reg = <0xd00000 0x10000>;
+
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 320 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 321 IRQ_TYPE_LEVEL_HIGH>;
+ #iommu-cells = <1>;
+
+ power-domains = <&mmcc MDSS_GDSC>;
+
+ clocks = <&mmcc SMMU_MDP_AHB_CLK>,
+ <&mmcc SMMU_MDP_AXI_CLK>;
+ clock-names = "iface", "bus";
+
+ status = "okay";
+ };
+
+ mdss: mdss@900000 {
+ compatible = "qcom,mdss";
+
+ reg = <0x900000 0x1000>,
+ <0x9b0000 0x1040>,
+ <0x9b8000 0x1040>;
+ reg-names = "mdss_phys",
+ "vbif_phys",
+ "vbif_nrt_phys";
+
+ power-domains = <&mmcc MDSS_GDSC>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ clocks = <&mmcc MDSS_AHB_CLK>;
+ clock-names = "iface_clk";
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ mdp: mdp@901000 {
+ compatible = "qcom,mdp5";
+ reg = <0x901000 0x90000>;
+ reg-names = "mdp_phys";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_AXI_CLK>,
+ <&mmcc MDSS_MDP_CLK>,
+ <&mmcc SMMU_MDP_AXI_CLK>,
+ <&mmcc MDSS_VSYNC_CLK>;
+ clock-names = "iface_clk",
+ "bus_clk",
+ "core_clk",
+ "iommu_clk",
+ "vsync_clk";
+
+ iommus = <&mdp_smmu 0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ mdp5_intf3_out: endpoint {
+ remote-endpoint = <&hdmi_in>;
+ };
+ };
+ };
+ };
+
+ hdmi: hdmi-tx@9a0000 {
+ compatible = "qcom,hdmi-tx-8996";
+ reg = <0x009a0000 0x50c>,
+ <0x00070000 0x6158>,
+ <0x009e0000 0xfff>;
+ reg-names = "core_physical",
+ "qfprom_physical",
+ "hdcp_physical";
+
+ interrupt-parent = <&mdss>;
+ interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&mmcc MDSS_MDP_CLK>,
+ <&mmcc MDSS_AHB_CLK>,
+ <&mmcc MDSS_HDMI_CLK>,
+ <&mmcc MDSS_HDMI_AHB_CLK>,
+ <&mmcc MDSS_EXTPCLK_CLK>;
+ clock-names =
+ "mdp_core_clk",
+ "iface_clk",
+ "core_clk",
+ "alt_iface_clk",
+ "extp_clk";
+
+ phys = <&hdmi_phy>;
+ phy-names = "hdmi_phy";
+ #sound-dai-cells = <1>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ hdmi_in: endpoint {
+ remote-endpoint = <&mdp5_intf3_out>;
+ };
+ };
+ };
+ };
+
+ hdmi_phy: hdmi-phy@9a0600 {
+ compatible = "qcom,hdmi-phy-8996";
+ reg = <0x9a0600 0x1c4>,
+ <0x9a0a00 0x124>,
+ <0x9a0c00 0x124>,
+ <0x9a0e00 0x124>,
+ <0x9a1000 0x124>,
+ <0x9a1200 0x0c8>;
+ reg-names = "hdmi_pll",
+ "hdmi_tx_l0",
+ "hdmi_tx_l1",
+ "hdmi_tx_l2",
+ "hdmi_tx_l3",
+ "hdmi_phy";
+
+ clocks = <&mmcc MDSS_AHB_CLK>,
+ <&gcc GCC_HDMI_CLKREF_CLK>;
+ clock-names = "iface_clk",
+ "ref_clk";
+ };
+ };
+
+ lpass_q6_smmu: arm,smmu-lpass_q6@1600000 {
+ compatible = "qcom,msm8996-smmu-v2", "qcom,smmu-v2";
+ reg = <0x1600000 0x20000>;
+ #iommu-cells = <1>;
+ power-domains = <&gcc HLOS1_VOTE_LPASS_CORE_GDSC>;
+
+ #global-interrupts = <1>;
+ interrupts = <GIC_SPI 404 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 393 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 394 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 397 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 398 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 399 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 401 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 402 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 403 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&gcc GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK>,
+ <&gcc GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK>;
+ clock-names = "iface", "bus";
+ status = "okay";
+ };
+
+ remoteproc@2080000 {
+ compatible = "qcom,msm8996-mss-pil";
+
+ reg = <0x2080000 0x100>,
+ <0x2180000 0x040>;
+ reg-names = "qdsp6", "rmb";
+
+ interrupts-extended = <&intc 0 448 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&modem_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog", "fatal", "ready",
+ "handover", "stop-ack";
+
+ clocks = <&xo_board>,
+ <&gcc GCC_MSS_CFG_AHB_CLK>,
+ <&rpmcc RPM_SMD_PCNOC_CLK>,
+ <&gcc GCC_MSS_Q6_BIMC_AXI_CLK>,
+ <&gcc GCC_BOOT_ROM_AHB_CLK>,
+ <&gcc GCC_MSS_GPLL0_DIV_CLK>,
+ <&gcc GCC_MSS_SNOC_AXI_CLK>,
+ <&gcc GCC_MSS_MNOC_BIMC_AXI_CLK>,
+ <&rpmcc RPM_SMD_QDSS_CLK>;
+
+ clock-names = "xo", "iface", "pnoc", "bus",
+ "mem", "gpll0_mss_clk", "snoc_axi_clk",
+ "mnoc_axi_clk", "qdss";
+
+ mx-supply = <&pm8994_s2>;
+ cx-supply = <&pm8994_s1>;
+ pll-supply = <&pm8994_l12>;
+
+ resets = <&gcc GCC_MSS_RESTART>;
+ reset-names = "mss_restart";
+
+ qcom,halt-regs = <&tcsr_mutex_regs 0x23000 0x25000 0x24000>;
+
+ qcom,smem-states = <&modem_smp2p_out 0>;
+ qcom,smem-state-names = "stop";
+
+ status = "disabled";
+
+ mba {
+ memory-region = <&mba_region>;
+ };
+
+ mpss {
+ memory-region = <&mpss_region>;
+ };
+
+ smd-edge {
+ interrupts = <0 449 IRQ_TYPE_EDGE_RISING>;
+
+ label = "modem";
+ mboxes = <&apcs_glb 12>;
+ qcom,smd-edge = <0>;
+ qcom,remote-pid = <1>;
+ };
+ };
+
+ bimc: bimc@400000 {
+ compatible = "qcom,msm8996-bimc";
+ #interconnect-cells = <1>;
+ reg = <0x400000 0x62000>;
+ type = <2>;
+ base-offset = <0x8000>;
+ qos-offset = <0x4000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
+ <&rpmcc RPM_SMD_BIMC_A_CLK>;
+ status = "okay";
+ };
+
+ cnoc: cnoc@500000 {
+ compatible = "qcom,msm8996-cnoc";
+ #interconnect-cells = <1>;
+ reg = <0x500000 0x80>;
+ type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_CNOC_CLK>,
+ <&rpmcc RPM_SMD_CNOC_A_CLK>;
+ status = "okay";
+ };
+
+ snoc: snoc@520000 {
+ compatible = "qcom,msm8996-snoc";
+ #interconnect-cells = <1>;
+ reg = <0x520000 0xa100>;
+ type = <1>;
+ base-offset = <0x4000>;
+ qos-offset = <0x1000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
+ <&rpmcc RPM_SMD_SNOC_A_CLK>;
+ status = "okay";
+ };
+
+ a0noc: a0noc@540000 {
+ compatible = "qcom,msm8996-a0noc";
+ #interconnect-cells = <1>;
+ reg = <0x540000 0x5100>;
+ type = <1>;
+ qcom,base-offset = <0x3000>;
+ qos-offset = <0x1000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&gcc GCC_AGGRE0_SNOC_AXI_CLK>,
+ <&gcc GCC_AGGRE0_SNOC_AXI_CLK>;
+ power-domains = <&gcc AGGRE0_NOC_GDSC>;
+ status = "okay";
+ };
+
+ a1noc: a1noc@560000 {
+ compatible = "qcom,msm8996-a1noc";
+ #interconnect-cells = <1>;
+ reg = <0x560000 0x3100>;
+ type = <1>;
+ base-offset = <0x2000>;
+ qos-offset = <0x1000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_AGGR1_NOC_CLK>,
+ <&rpmcc RPM_SMD_AGGR1_NOC_A_CLK>;
+ status = "okay";
+ };
+
+ a2noc: a2noc@580000 {
+ compatible = "qcom,msm8996-a2noc";
+ #interconnect-cells = <1>;
+ reg = <0x580000 0x8100>;
+ base-offset = <0x3000>;
+ qos-offset = <0x1000>;
+ type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_AGGR2_NOC_CLK>,
+ <&rpmcc RPM_SMD_AGGR2_NOC_A_CLK>;
+ status = "okay";
+ };
+
+ mmnoc: mmnoc@5a0000 {
+ compatible = "qcom,msm8996-mmnoc";
+ #interconnect-cells = <1>;
+ reg = <0x5a0000 0xb080>;
+ type = <1>;
+ base-offset = <0x4000>;
+ qos-offset = <0x1000>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_MMAXI_CLK>,
+ <&rpmcc RPM_SMD_MMAXI_A_CLK>;
+ power-domains = <&mmcc MMAGIC_BIMC_GDSC>;
+ status = "okay";
+ };
+
+ pnoc: pnoc@5c0000 {
+ compatible = "qcom,msm8996-pnoc";
+ #interconnect-cells = <1>;
+ reg = <0x5c0000 0x2480>;
+ type = <1>;
+ clock-names = "bus_clk", "bus_a_clk";
+ clocks = <&rpmcc RPM_SMD_PCNOC_CLK>,
+ <&rpmcc RPM_SMD_PCNOC_A_CLK>;
+ status = "okay";
+ };
+ };
+
+ sound: sound {
};
adsp-pil {
@@ -1154,9 +1898,56 @@
interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
label = "lpass";
- qcom,ipc = <&apcs 16 8>;
+ mboxes = <&apcs_glb 8>;
qcom,smd-edge = <1>;
qcom,remote-pid = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ apr {
+ power-domains = <&gcc HLOS1_VOTE_LPASS_ADSP_GDSC>;
+ compatible = "qcom,apr-v2";
+ qcom,smd-channels = "apr_audio_svc";
+ reg = <APR_DOMAIN_ADSP>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ q6core {
+ reg = <APR_SVC_ADSP_CORE>;
+ compatible = "qcom,q6core";
+ };
+
+ q6afe: q6afe {
+ compatible = "qcom,q6afe";
+ reg = <APR_SVC_AFE>;
+ q6afedai: dais {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #sound-dai-cells = <1>;
+ hdmi@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ q6asm: q6asm {
+ compatible = "qcom,q6asm";
+ reg = <APR_SVC_ASM>;
+ q6asmdai: dais {
+ #sound-dai-cells = <1>;
+ iommus = <&lpass_q6_smmu 1>;
+ };
+ };
+
+ q6adm: q6adm {
+ compatible = "qcom,q6adm";
+ reg = <APR_SVC_ADM>;
+ q6routing: routing {
+ #sound-dai-cells = <0>;
+ };
+ };
+
+ };
};
};
@@ -1166,7 +1957,7 @@
interrupts = <0 158 IRQ_TYPE_EDGE_RISING>;
- qcom,ipc = <&apcs 16 10>;
+ mboxes = <&apcs_glb 10>;
qcom,local-pid = <0>;
qcom,remote-pid = <2>;
@@ -1190,7 +1981,7 @@
interrupts = <GIC_SPI 451 IRQ_TYPE_EDGE_RISING>;
- qcom,ipc = <&apcs 16 14>;
+ mboxes = <&apcs_glb 14>;
qcom,local-pid = <0>;
qcom,remote-pid = <1>;
@@ -1214,7 +2005,7 @@
interrupts = <GIC_SPI 178 IRQ_TYPE_EDGE_RISING>;
- qcom,ipc = <&apcs 16 26>;
+ mboxes = <&apcs_glb 26>;
qcom,local-pid = <0>;
qcom,remote-pid = <3>;
@@ -1233,3 +2024,5 @@
};
#include "msm8996-pins.dtsi"
+#include "pm8994.dtsi"
+#include "pmi8994.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi
index 196b1c0ceb9b..803ce2979ba3 100644
--- a/arch/arm64/boot/dts/qcom/pm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi
@@ -137,5 +137,124 @@
vdd-micbias-supply = <&pm8916_l13>;
#sound-dai-cells = <1>;
};
+
+ regulators {
+ compatible = "qcom,pm8916-regulators";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ s1@1400 {
+ reg = <0x1400 0x300>;
+ status = "disabled";
+ };
+
+ pm8916_spmi_s2: s2@1700 {
+ reg = <0x1700 0x300>;
+ status = "ok";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ };
+
+ s3@1a00 {
+ reg = <0x1a00 0x300>;
+ status = "disabled";
+ };
+
+ s4@1d00 {
+ reg = <0x1d00 0x300>;
+ status = "disabled";
+ };
+
+ l1@4000 {
+ reg = <0x4000 0x100>;
+ status = "disabled";
+ };
+
+ l2@4100 {
+ reg = <0x4100 0x100>;
+ status = "disabled";
+ };
+
+ l3@4200 {
+ reg = <0x4200 0x100>;
+ status = "disabled";
+ };
+
+ l4@4300 {
+ reg = <0x4300 0x100>;
+ status = "disabled";
+ };
+
+ l5@4400 {
+ reg = <0x4400 0x100>;
+ status = "disabled";
+ };
+
+ l6@4500 {
+ reg = <0x4500 0x100>;
+ status = "disabled";
+ };
+
+ l7@4600 {
+ reg = <0x4600 0x100>;
+ status = "disabled";
+ };
+
+ l8@4700 {
+ reg = <0x4700 0x100>;
+ status = "disabled";
+ };
+
+ l9@4800 {
+ reg = <0x4800 0x100>;
+ status = "disabled";
+ };
+
+ l10@4900 {
+ reg = <0x4900 0x100>;
+ status = "disabled";
+ };
+
+ l11@4a00 {
+ reg = <0x4a00 0x100>;
+ status = "disabled";
+ };
+
+ l12@4b00 {
+ reg = <0x4b00 0x100>;
+ status = "disabled";
+ };
+
+ l13@4c00 {
+ reg = <0x4c00 0x100>;
+ status = "disabled";
+ };
+
+ l14@4d00 {
+ reg = <0x4d00 0x100>;
+ status = "disabled";
+ };
+
+ l15@4e00 {
+ reg = <0x4e00 0x100>;
+ status = "disabled";
+ };
+
+ l16@4f00 {
+ reg = <0x4f00 0x100>;
+ status = "disabled";
+ };
+
+ l17@5000 {
+ reg = <0x5000 0x100>;
+ status = "disabled";
+ };
+
+ l18@5100 {
+ reg = <0x5100 0x100>;
+ status = "disabled";
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/pmi8994.dtsi b/arch/arm64/boot/dts/qcom/pmi8994.dtsi
index dae1cdc23f54..b7df8c58f70d 100644
--- a/arch/arm64/boot/dts/qcom/pmi8994.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8994.dtsi
@@ -33,5 +33,19 @@
reg = <0x3 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
+
+ regulators {
+ compatible = "qcom,pmi8994-regulators";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pmi8994_s2: s2@1700 {
+ reg = <0x1700 0x100>;
+ status = "ok";
+ regulator-min-microvolt = <400000>;
+ regulator-max-microvolt = <1015000>;
+ regulator-always-on;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
index 979ab49913f1..af945aaddb55 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
@@ -7,9 +7,191 @@
/dts-v1/;
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
#include "sdm845.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM845 MTP";
compatible = "qcom,sdm845-mtp";
+
+ aliases {
+ serial0 = &uart9;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&apps_rsc {
+ pm8998-rpmh-regulators {
+ compatible = "qcom,pm8998-rpmh-regulators";
+ qcom,pmic-id = "a";
+
+ vdd_l7_l12_l14_l15-supply = <&pm8998_s5>;
+
+ smps2 {
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ qcom,regulator-initial-voltage = <1100000>;
+ };
+
+ pm8998_s5: smps5 {
+ regulator-min-microvolt = <1904000>;
+ regulator-max-microvolt = <2040000>;
+ qcom,regulator-initial-voltage = <1904000>;
+ };
+
+ pm8998_l1: ldo1 {
+ regulator-min-microvolt = <880000>;
+ regulator-max-microvolt = <880000>;
+ qcom,regulator-initial-voltage = <880000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>;
+ qcom,allowed-modes =
+ <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ qcom,mode-threshold-currents = <0 1>;
+ };
+
+ pm8998_l2: ldo2 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,regulator-initial-voltage = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>;
+ qcom,allowed-modes =
+ <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ qcom,mode-threshold-currents = <0 30000>;
+ };
+
+
+ ldo7 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,regulator-initial-voltage = <1800000>;
+ qcom,headroom-voltage = <56000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>;
+ regulator-allow-set-load;
+ qcom,allowed-modes =
+ <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ qcom,mode-threshold-currents = <0 10000>;
+ };
+
+ pm8998_l20: ldo20 {
+ regulator-min-microvolt = <2704000>;
+ regulator-max-microvolt = <2960000>;
+ qcom,regulator-initial-voltage = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>;
+ qcom,allowed-modes =
+ <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ qcom,mode-threshold-currents = <0 10000>;
+ };
+
+ pm8998_l26: ldo26 {
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ qcom,regulator-initial-voltage = <1200000>;
+ regulator-initial-mode = <RPMH_REGULATOR_MODE_LPM>;
+ qcom,allowed-modes =
+ <RPMH_REGULATOR_MODE_LPM
+ RPMH_REGULATOR_MODE_HPM>;
+ regulator-allow-set-load;
+ qcom,mode-threshold-currents = <0 1>;
+ };
+
+ lvs1 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+ };
+
+ pmi8998-rpmh-regulators {
+ compatible = "qcom,pmi8998-rpmh-regulators";
+ qcom,pmic-id = "b";
+
+ bob {
+ regulator-min-microvolt = <3312000>;
+ regulator-max-microvolt = <3600000>;
+ qcom,regulator-initial-voltage = <3312000>;
+ };
+ };
+};
+
+&i2c10 {
+ status = "okay";
+ clock-frequency = <400000>;
+};
+
+&qupv3_id_1 {
+ status = "okay";
+};
+
+&uart9 {
+ status = "okay";
+};
+
+&ufshc {
+ status = "ok";
+
+ vcc-supply = <&pm8998_l20>;
+ vcc-voltage-level = <2950000 2960000>;
+ vcc-max-microamp = <600000>;
+ vccq2-max-microamp = <600000>;
+
+ qcom,vddp-ref-clk-supply = <&pm8998_l2>;
+ qcom,vddp-ref-clk-max-microamp = <100>;
+
+};
+
+&ufsphy {
+ status = "ok";
+
+ vdda-phy-supply = <&pm8998_l1>; /* 0.88v */
+ vdda-pll-supply = <&pm8998_l26>; /* 1.2v */
+ vdda-phy-max-microamp = <62900>;
+ vdda-pll-max-microamp = <18300>;
+};
+
+/* PINCTRL - additions to nodes defined in sdm845.dtsi */
+
+&qup_i2c10_default {
+ pinconf {
+ pins = "gpio55", "gpio56";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&qup_uart9_default {
+ pinconf-tx {
+ pins = "gpio4";
+ drive-strength = <2>;
+ bias-disable;
+ };
+
+ pinconf-rx {
+ pins = "gpio5";
+ drive-strength = <2>;
+ bias-pull-up;
+ };
+};
+
+&qup_uart9_sleep {
+ pinconf {
+ pins = "gpio4", "gpio5";
+ bias-pull-down;
+ };
+};
+
+&adsp_pil {
+ status = "okay";
+};
+
+&cdsp_pil {
+ status = "okay";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
index cdaabeb3c995..1097c7ef31b9 100644
--- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
@@ -5,7 +5,12 @@
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/reset/qcom,sdm845-aoss.h>
+#include <dt-bindings/soc/qcom,rpmh-rsc.h>
+#include <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
/ {
interrupt-parent = <&intc>;
@@ -13,6 +18,41 @@
#address-cells = <2>;
#size-cells = <2>;
+ aliases {
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ i2c6 = &i2c6;
+ i2c7 = &i2c7;
+ i2c8 = &i2c8;
+ i2c9 = &i2c9;
+ i2c10 = &i2c10;
+ i2c11 = &i2c11;
+ i2c12 = &i2c12;
+ i2c13 = &i2c13;
+ i2c14 = &i2c14;
+ i2c15 = &i2c15;
+ spi0 = &spi0;
+ spi1 = &spi1;
+ spi2 = &spi2;
+ spi3 = &spi3;
+ spi4 = &spi4;
+ spi5 = &spi5;
+ spi6 = &spi6;
+ spi7 = &spi7;
+ spi8 = &spi8;
+ spi9 = &spi9;
+ spi10 = &spi10;
+ spi11 = &spi11;
+ spi12 = &spi12;
+ spi13 = &spi13;
+ spi14 = &spi14;
+ spi15 = &spi15;
+ };
+
chosen { };
memory@80000000 {
@@ -46,6 +86,37 @@
reg = <0 0x86200000 0 0x2d00000>;
no-map;
};
+
+ adsp_mem: memory@8b100000 {
+ reg = <0 0x8b100000 0 0x1a00000>;
+ no-map;
+ };
+
+ cdsp_mem: memory@94700000 {
+ reg = <0 0x94700000 0 0x800000>;
+ no-map;
+ };
+
+ mpss_mem: memory@8cc00000 {
+ reg = <0 0x8cc00000 0 0x7600000>;
+ no-map;
+ };
+
+ mba_mem: memory@94f00000 {
+ reg = <0 0x94f00000 0 0x200000>;
+ no-map;
+ };
+
+ rmtfs {
+ compatible = "qcom,rmtfs-mem";
+
+ size = <0x0 0x200000>;
+ alloc-ranges = <0x0 0xa0000000 0x0 0x2000000>;
+ no-map;
+
+ qcom,client-id = <1>;
+ qcom,vmid = <15>;
+ };
};
cpus {
@@ -160,6 +231,64 @@
<GIC_PPI 0 IRQ_TYPE_LEVEL_LOW>;
};
+ adsp_pil: adsp-pil {
+ compatible = "qcom,sdm845-adsp-pas";
+
+ interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>,
+ <&adsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&adsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&adsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&adsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog", "fatal", "ready",
+ "handover", "stop-ack";
+
+ clocks = <&xo_board>;
+ clock-names = "xo";
+
+ memory-region = <&adsp_mem>;
+
+ qcom,smem-states = <&adsp_smp2p_out 0>;
+ qcom,smem-state-names = "stop";
+
+ status = "disabled";
+
+ glink-edge {
+ interrupts = <GIC_SPI 156 IRQ_TYPE_EDGE_RISING>;
+ label = "lpass";
+ qcom,remote-pid = <2>;
+ mboxes = <&apss_shared 8>;
+ };
+ };
+
+ cdsp_pil: cdsp-pil {
+ compatible = "qcom,sdm845-cdsp-pas";
+
+ interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>,
+ <&cdsp_smp2p_in 0 IRQ_TYPE_EDGE_RISING>,
+ <&cdsp_smp2p_in 1 IRQ_TYPE_EDGE_RISING>,
+ <&cdsp_smp2p_in 2 IRQ_TYPE_EDGE_RISING>,
+ <&cdsp_smp2p_in 3 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog", "fatal", "ready",
+ "handover", "stop-ack";
+
+ clocks = <&xo_board>;
+ clock-names = "xo";
+
+ memory-region = <&cdsp_mem>;
+
+ qcom,smem-states = <&cdsp_smp2p_out 0>;
+ qcom,smem-state-names = "stop";
+
+ status = "disabled";
+
+ glink-edge {
+ interrupts = <GIC_SPI 574 IRQ_TYPE_EDGE_RISING>;
+ label = "turing";
+ qcom,remote-pid = <5>;
+ mboxes = <&apss_shared 4>;
+ };
+ };
+
clocks {
xo_board: xo-board {
compatible = "fixed-clock";
@@ -175,6 +304,12 @@
};
};
+ firmware {
+ scm {
+ compatible = "qcom,scm-sdm845";
+ };
+ };
+
tcsr_mutex: hwlock {
compatible = "qcom,tcsr-mutex";
syscon = <&tcsr_mutex_regs 0 0x1000>;
@@ -187,6 +322,94 @@
hwlocks = <&tcsr_mutex 3>;
};
+ smp2p-cdsp {
+ compatible = "qcom,smp2p";
+ qcom,smem = <94>, <432>;
+
+ interrupts = <GIC_SPI 576 IRQ_TYPE_EDGE_RISING>;
+
+ mboxes = <&apss_shared 6>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <5>;
+
+ cdsp_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+ #qcom,smem-state-cells = <1>;
+ };
+
+ cdsp_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ smp2p-lpass {
+ compatible = "qcom,smp2p";
+ qcom,smem = <443>, <429>;
+
+ interrupts = <GIC_SPI 158 IRQ_TYPE_EDGE_RISING>;
+
+ mboxes = <&apss_shared 10>;
+
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <2>;
+
+ adsp_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+ #qcom,smem-state-cells = <1>;
+ };
+
+ adsp_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ smp2p-mpss {
+ compatible = "qcom,smp2p";
+ qcom,smem = <435>, <428>;
+ interrupts = <GIC_SPI 451 IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&apss_shared 14>;
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <1>;
+
+ modem_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+ #qcom,smem-state-cells = <1>;
+ };
+
+ modem_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
+ smp2p-slpi {
+ compatible = "qcom,smp2p";
+ qcom,smem = <481>, <430>;
+ interrupts = <GIC_SPI 172 IRQ_TYPE_EDGE_RISING>;
+ mboxes = <&apss_shared 26>;
+ qcom,local-pid = <0>;
+ qcom,remote-pid = <3>;
+
+ slpi_smp2p_out: master-kernel {
+ qcom,entry-name = "master-kernel";
+ #qcom,smem-state-cells = <1>;
+ };
+
+ slpi_smp2p_in: slave-kernel {
+ qcom,entry-name = "slave-kernel";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+
psci {
compatible = "arm,psci-1.0";
method = "smc";
@@ -206,6 +429,489 @@
#power-domain-cells = <1>;
};
+ qupv3_id_0: geniqup@8c0000 {
+ compatible = "qcom,geni-se-qup";
+ reg = <0x8c0000 0x6000>;
+ clock-names = "m-ahb", "s-ahb";
+ clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>,
+ <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ i2c0: i2c@880000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x880000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c0_default>;
+ pinctrl-1 = <&qup_i2c0_sleep>;
+ interrupts = <GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi0: spi@880000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x880000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi0_default>;
+ pinctrl-1 = <&qup_spi0_sleep>;
+ interrupts = <GIC_SPI 601 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@884000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x884000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c1_default>;
+ pinctrl-1 = <&qup_i2c1_sleep>;
+ interrupts = <GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi1: spi@884000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x884000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi1_default>;
+ pinctrl-1 = <&qup_spi1_sleep>;
+ interrupts = <GIC_SPI 602 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@888000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x888000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c2_default>;
+ pinctrl-1 = <&qup_i2c2_sleep>;
+ interrupts = <GIC_SPI 603 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi2: spi@888000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x888000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi2_default>;
+ pinctrl-1 = <&qup_spi2_sleep>;
+ interrupts = <GIC_SPI 603 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@88c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x88c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c3_default>;
+ pinctrl-1 = <&qup_i2c3_sleep>;
+ interrupts = <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi3: spi@88c000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x88c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi3_default>;
+ pinctrl-1 = <&qup_spi3_sleep>;
+ interrupts = <GIC_SPI 604 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@890000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x890000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c4_default>;
+ pinctrl-1 = <&qup_i2c4_sleep>;
+ interrupts = <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi4: spi@890000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x890000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi4_default>;
+ pinctrl-1 = <&qup_spi4_sleep>;
+ interrupts = <GIC_SPI 605 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@894000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x894000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c5_default>;
+ pinctrl-1 = <&qup_i2c5_sleep>;
+ interrupts = <GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi5: spi@894000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x894000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi5_default>;
+ pinctrl-1 = <&qup_spi5_sleep>;
+ interrupts = <GIC_SPI 606 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c6: i2c@898000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x898000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c6_default>;
+ pinctrl-1 = <&qup_i2c6_sleep>;
+ interrupts = <GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi6: spi@898000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x898000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi6_default>;
+ pinctrl-1 = <&qup_spi6_sleep>;
+ interrupts = <GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c7: i2c@89c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0x89c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c7_default>;
+ pinctrl-1 = <&qup_i2c7_sleep>;
+ interrupts = <GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi7: spi@89c000 {
+ compatible = "qcom,geni-spi";
+ reg = <0x89c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi7_default>;
+ pinctrl-1 = <&qup_spi7_sleep>;
+ interrupts = <GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
+ qupv3_id_1: geniqup@ac0000 {
+ compatible = "qcom,geni-se-qup";
+ reg = <0xac0000 0x6000>;
+ clock-names = "m-ahb", "s-ahb";
+ clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>,
+ <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ status = "disabled";
+
+ i2c8: i2c@a80000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0xa80000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c8_default>;
+ pinctrl-1 = <&qup_i2c8_sleep>;
+ interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi8: spi@a80000 {
+ compatible = "qcom,geni-spi";
+ reg = <0xa80000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi8_default>;
+ pinctrl-1 = <&qup_spi8_sleep>;
+ interrupts = <GIC_SPI 353 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c9: i2c@a84000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0xa84000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c9_default>;
+ pinctrl-1 = <&qup_i2c9_sleep>;
+ interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi9: spi@a84000 {
+ compatible = "qcom,geni-spi";
+ reg = <0xa84000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi9_default>;
+ pinctrl-1 = <&qup_spi9_sleep>;
+ interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ uart9: serial@a84000 {
+ compatible = "qcom,geni-debug-uart";
+ reg = <0xa84000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_uart9_default>;
+ pinctrl-1 = <&qup_uart9_sleep>;
+ interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ i2c10: i2c@a88000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0xa88000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c10_default>;
+ pinctrl-1 = <&qup_i2c10_sleep>;
+ interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi10: spi@a88000 {
+ compatible = "qcom,geni-spi";
+ reg = <0xa88000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi10_default>;
+ pinctrl-1 = <&qup_spi10_sleep>;
+ interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c11: i2c@a8c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0xa8c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c11_default>;
+ pinctrl-1 = <&qup_i2c11_sleep>;
+ interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi11: spi@a8c000 {
+ compatible = "qcom,geni-spi";
+ reg = <0xa8c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi11_default>;
+ pinctrl-1 = <&qup_spi11_sleep>;
+ interrupts = <GIC_SPI 356 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c12: i2c@a90000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0xa90000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c12_default>;
+ pinctrl-1 = <&qup_i2c12_sleep>;
+ interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi12: spi@a90000 {
+ compatible = "qcom,geni-spi";
+ reg = <0xa90000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi12_default>;
+ pinctrl-1 = <&qup_spi12_sleep>;
+ interrupts = <GIC_SPI 357 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c13: i2c@a94000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0xa94000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c13_default>;
+ pinctrl-1 = <&qup_i2c13_sleep>;
+ interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi13: spi@a94000 {
+ compatible = "qcom,geni-spi";
+ reg = <0xa94000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi13_default>;
+ pinctrl-1 = <&qup_spi13_sleep>;
+ interrupts = <GIC_SPI 358 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c14: i2c@a98000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0xa98000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c14_default>;
+ pinctrl-1 = <&qup_i2c14_sleep>;
+ interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi14: spi@a98000 {
+ compatible = "qcom,geni-spi";
+ reg = <0xa98000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi14_default>;
+ pinctrl-1 = <&qup_spi14_sleep>;
+ interrupts = <GIC_SPI 359 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c15: i2c@a9c000 {
+ compatible = "qcom,geni-i2c";
+ reg = <0xa9c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_i2c15_default>;
+ pinctrl-1 = <&qup_i2c15_sleep>;
+ interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ spi15: spi@a9c000 {
+ compatible = "qcom,geni-spi";
+ reg = <0xa9c000 0x4000>;
+ clock-names = "se";
+ clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&qup_spi15_default>;
+ pinctrl-1 = <&qup_spi15_sleep>;
+ interrupts = <GIC_SPI 360 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+ };
+
tcsr_mutex_regs: syscon@1f40000 {
compatible = "syscon";
reg = <0x1f40000 0x40000>;
@@ -219,6 +925,606 @@
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
+
+ qup_i2c0_default: qup-i2c0-default {
+ pinmux {
+ pins = "gpio0", "gpio1";
+ function = "qup0";
+ };
+ };
+
+ qup_i2c0_sleep: qup-i2c0-sleep {
+ pinmux {
+ pins = "gpio0", "gpio1";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c1_default: qup-i2c1-default {
+ pinmux {
+ pins = "gpio17", "gpio18";
+ function = "qup1";
+ };
+ };
+
+ qup_i2c1_sleep: qup-i2c1-sleep {
+ pinmux {
+ pins = "gpio17", "gpio18";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c2_default: qup-i2c2-default {
+ pinmux {
+ pins = "gpio27", "gpio28";
+ function = "qup2";
+ };
+ };
+
+ qup_i2c2_sleep: qup-i2c2-sleep {
+ pinmux {
+ pins = "gpio27", "gpio28";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c3_default: qup-i2c3-default {
+ pinmux {
+ pins = "gpio41", "gpio42";
+ function = "qup3";
+ };
+ };
+
+ qup_i2c3_sleep: qup-i2c3-sleep {
+ pinmux {
+ pins = "gpio41", "gpio42";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c4_default: qup-i2c4-default {
+ pinmux {
+ pins = "gpio89", "gpio90";
+ function = "qup4";
+ };
+ };
+
+ qup_i2c4_sleep: qup-i2c4-sleep {
+ pinmux {
+ pins = "gpio89", "gpio90";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c5_default: qup-i2c5-default {
+ pinmux {
+ pins = "gpio85", "gpio86";
+ function = "qup5";
+ };
+ };
+
+ qup_i2c5_sleep: qup-i2c5-sleep {
+ pinmux {
+ pins = "gpio85", "gpio86";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c6_default: qup-i2c6-default {
+ pinmux {
+ pins = "gpio45", "gpio46";
+ function = "qup6";
+ };
+ };
+
+ qup_i2c6_sleep: qup-i2c6-sleep {
+ pinmux {
+ pins = "gpio45", "gpio46";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c7_default: qup-i2c7-default {
+ pinmux {
+ pins = "gpio93", "gpio94";
+ function = "qup7";
+ };
+ };
+
+ qup_i2c7_sleep: qup-i2c7-sleep {
+ pinmux {
+ pins = "gpio93", "gpio94";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c8_default: qup-i2c8-default {
+ pinmux {
+ pins = "gpio65", "gpio66";
+ function = "qup8";
+ };
+ };
+
+ qup_i2c8_sleep: qup-i2c8-sleep {
+ pinmux {
+ pins = "gpio65", "gpio66";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c9_default: qup-i2c9-default {
+ pinmux {
+ pins = "gpio6", "gpio7";
+ function = "qup9";
+ };
+ };
+
+ qup_i2c9_sleep: qup-i2c9-sleep {
+ pinmux {
+ pins = "gpio6", "gpio7";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c10_default: qup-i2c10-default {
+ pinmux {
+ pins = "gpio55", "gpio56";
+ function = "qup10";
+ };
+ };
+
+ qup_i2c10_sleep: qup-i2c10-sleep {
+ pinmux {
+ pins = "gpio55", "gpio56";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c11_default: qup-i2c11-default {
+ pinmux {
+ pins = "gpio31", "gpio32";
+ function = "qup11";
+ };
+ };
+
+ qup_i2c11_sleep: qup-i2c11-sleep {
+ pinmux {
+ pins = "gpio31", "gpio32";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c12_default: qup-i2c12-default {
+ pinmux {
+ pins = "gpio49", "gpio50";
+ function = "qup12";
+ };
+ };
+
+ qup_i2c12_sleep: qup-i2c12-sleep {
+ pinmux {
+ pins = "gpio49", "gpio50";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c13_default: qup-i2c13-default {
+ pinmux {
+ pins = "gpio105", "gpio106";
+ function = "qup13";
+ };
+ };
+
+ qup_i2c13_sleep: qup-i2c13-sleep {
+ pinmux {
+ pins = "gpio105", "gpio106";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c14_default: qup-i2c14-default {
+ pinmux {
+ pins = "gpio33", "gpio34";
+ function = "qup14";
+ };
+ };
+
+ qup_i2c14_sleep: qup-i2c14-sleep {
+ pinmux {
+ pins = "gpio33", "gpio34";
+ function = "gpio";
+ };
+ };
+
+ qup_i2c15_default: qup-i2c15-default {
+ pinmux {
+ pins = "gpio81", "gpio82";
+ function = "qup15";
+ };
+ };
+
+ qup_i2c15_sleep: qup-i2c15-sleep {
+ pinmux {
+ pins = "gpio81", "gpio82";
+ function = "gpio";
+ };
+ };
+
+ qup_spi0_default: qup-spi0-default {
+ pinmux {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ function = "qup0";
+ };
+ };
+
+ qup_spi0_sleep: qup-spi0-sleep {
+ pinmux {
+ pins = "gpio0", "gpio1",
+ "gpio2", "gpio3";
+ function = "gpio";
+ };
+ };
+
+ qup_spi1_default: qup-spi1-default {
+ pinmux {
+ pins = "gpio17", "gpio18",
+ "gpio19", "gpio20";
+ function = "qup1";
+ };
+ };
+
+ qup_spi1_sleep: qup-spi1-sleep {
+ pinmux {
+ pins = "gpio17", "gpio18",
+ "gpio19", "gpio20";
+ function = "gpio";
+ };
+ };
+
+ qup_spi2_default: qup-spi2-default {
+ pinmux {
+ pins = "gpio27", "gpio28",
+ "gpio29", "gpio30";
+ function = "qup2";
+ };
+ };
+
+ qup_spi2_sleep: qup-spi2-sleep {
+ pinmux {
+ pins = "gpio27", "gpio28",
+ "gpio29", "gpio30";
+ function = "gpio";
+ };
+ };
+
+ qup_spi3_default: qup-spi3-default {
+ pinmux {
+ pins = "gpio41", "gpio42",
+ "gpio43", "gpio44";
+ function = "qup3";
+ };
+ };
+
+ qup_spi3_sleep: qup-spi3-sleep {
+ pinmux {
+ pins = "gpio41", "gpio42",
+ "gpio43", "gpio44";
+ function = "gpio";
+ };
+ };
+
+ qup_spi4_default: qup-spi4-default {
+ pinmux {
+ pins = "gpio89", "gpio90",
+ "gpio91", "gpio92";
+ function = "qup4";
+ };
+ };
+
+ qup_spi4_sleep: qup-spi4-sleep {
+ pinmux {
+ pins = "gpio89", "gpio90",
+ "gpio91", "gpio92";
+ function = "gpio";
+ };
+ };
+
+ qup_spi5_default: qup-spi5-default {
+ pinmux {
+ pins = "gpio85", "gpio86",
+ "gpio87", "gpio88";
+ function = "qup5";
+ };
+ };
+
+ qup_spi5_sleep: qup-spi5-sleep {
+ pinmux {
+ pins = "gpio85", "gpio86",
+ "gpio87", "gpio88";
+ function = "gpio";
+ };
+ };
+
+ qup_spi6_default: qup-spi6-default {
+ pinmux {
+ pins = "gpio45", "gpio46",
+ "gpio47", "gpio48";
+ function = "qup6";
+ };
+ };
+
+ qup_spi6_sleep: qup-spi6-sleep {
+ pinmux {
+ pins = "gpio45", "gpio46",
+ "gpio47", "gpio48";
+ function = "gpio";
+ };
+ };
+
+ qup_spi7_default: qup-spi7-default {
+ pinmux {
+ pins = "gpio93", "gpio94",
+ "gpio95", "gpio96";
+ function = "qup7";
+ };
+ };
+
+ qup_spi7_sleep: qup-spi7-sleep {
+ pinmux {
+ pins = "gpio93", "gpio94",
+ "gpio95", "gpio96";
+ function = "gpio";
+ };
+ };
+
+ qup_spi8_default: qup-spi8-default {
+ pinmux {
+ pins = "gpio65", "gpio66",
+ "gpio67", "gpio68";
+ function = "qup8";
+ };
+ };
+
+ qup_spi8_sleep: qup-spi8-sleep {
+ pinmux {
+ pins = "gpio65", "gpio66",
+ "gpio67", "gpio68";
+ function = "gpio";
+ };
+ };
+
+ qup_spi9_default: qup-spi9-default {
+ pinmux {
+ pins = "gpio6", "gpio7",
+ "gpio4", "gpio5";
+ function = "qup9";
+ };
+ };
+
+ qup_spi9_sleep: qup-spi9-sleep {
+ pinmux {
+ pins = "gpio6", "gpio7",
+ "gpio4", "gpio5";
+ function = "gpio";
+ };
+ };
+
+ qup_spi10_default: qup-spi10-default {
+ pinmux {
+ pins = "gpio55", "gpio56",
+ "gpio53", "gpio54";
+ function = "qup10";
+ };
+ };
+
+ qup_spi10_sleep: qup-spi10-sleep {
+ pinmux {
+ pins = "gpio55", "gpio56",
+ "gpio53", "gpio54";
+ function = "gpio";
+ };
+ };
+
+ qup_spi11_default: qup-spi11-default {
+ pinmux {
+ pins = "gpio31", "gpio32",
+ "gpio33", "gpio34";
+ function = "qup11";
+ };
+ };
+
+ qup_spi11_sleep: qup-spi11-sleep {
+ pinmux {
+ pins = "gpio31", "gpio32",
+ "gpio33", "gpio34";
+ function = "gpio";
+ };
+ };
+
+ qup_spi12_default: qup-spi12-default {
+ pinmux {
+ pins = "gpio49", "gpio50",
+ "gpio51", "gpio52";
+ function = "qup12";
+ };
+ };
+
+ qup_spi12_sleep: qup-spi12-sleep {
+ pinmux {
+ pins = "gpio49", "gpio50",
+ "gpio51", "gpio52";
+ function = "gpio";
+ };
+ };
+
+ qup_spi13_default: qup-spi13-default {
+ pinmux {
+ pins = "gpio105", "gpio106",
+ "gpio107", "gpio108";
+ function = "qup13";
+ };
+ };
+
+ qup_spi13_sleep: qup-spi13-sleep {
+ pinmux {
+ pins = "gpio105", "gpio106",
+ "gpio107", "gpio108";
+ function = "gpio";
+ };
+ };
+
+ qup_spi14_default: qup-spi14-default {
+ pinmux {
+ pins = "gpio33", "gpio34",
+ "gpio31", "gpio32";
+ function = "qup14";
+ };
+ };
+
+ qup_spi14_sleep: qup-spi14-sleep {
+ pinmux {
+ pins = "gpio33", "gpio34",
+ "gpio31", "gpio32";
+ function = "gpio";
+ };
+ };
+
+ qup_spi15_default: qup-spi15-default {
+ pinmux {
+ pins = "gpio81", "gpio82",
+ "gpio83", "gpio84";
+ function = "qup15";
+ };
+ };
+
+ qup_spi15_sleep: qup-spi15-sleep {
+ pinmux {
+ pins = "gpio81", "gpio82",
+ "gpio83", "gpio84";
+ function = "gpio";
+ };
+ };
+
+ qup_uart9_default: qup-uart9-default {
+ pinmux {
+ pins = "gpio4", "gpio5";
+ function = "qup9";
+ };
+ };
+
+ qup_uart9_sleep: qup-uart9-sleep {
+ pinmux {
+ pins = "gpio4", "gpio5";
+ function = "gpio";
+ };
+ };
+
+ ufs_dev_reset_assert: ufs_dev_reset_assert {
+ 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 {
+ 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 */
+ };
+ };
+
+ aoss_reset: qcom,reset-controller@c2b0000 {
+ compatible = "qcom,sdm845-aoss-reset";
+ reg = <0xc2b0000 0x21000>;
+ #reset-cells = <1>;
+ };
+
+ remoteproc@4080000 {
+ compatible = "qcom,sdm845-mss-pil";
+ reg = <0x04080000 0x408>, <0x04180000 0x48>;
+
+ reg-names = "qdsp6", "rmb";
+
+ interrupts-extended = <&intc 0 266 1>,
+ <&modem_smp2p_in 0 0>,
+ <&modem_smp2p_in 1 0>,
+ <&modem_smp2p_in 2 0>,
+ <&modem_smp2p_in 3 0>;
+
+ interrupt-names = "wdog", "fatal", "ready",
+ "handover", "stop-ack";
+
+ clocks = <&gcc GCC_MSS_CFG_AHB_CLK>,
+ <&gcc GCC_MSS_Q6_MEMNOC_AXI_CLK>,
+ <&gcc GCC_BOOT_ROM_AHB_CLK>,
+ <&gcc GCC_MSS_GPLL0_DIV_CLK_SRC>,
+ <&gcc GCC_MSS_SNOC_AXI_CLK>,
+ <&gcc GCC_MSS_AXIS2_CLK>,
+ <&gcc GCC_MSS_MFAB_AXIS_CLK>,
+ <&gcc GCC_PRNG_AHB_CLK>,
+ <&xo_board>;
+
+ clock-names = "iface", "bus", "mem", "gpll0_mss",
+ "snoc_axi", "axis2", "mnoc_axi",
+ "prng", "xo";
+
+ qcom,smem-states = <&modem_smp2p_out 0>;
+ qcom,smem-state-names = "stop";
+
+ resets = <&aoss_reset AOSS_CC_MSS_RESTART>;
+ reset-names = "mss_restart";
+
+ /* cx-supply = <&pm8998_s9>; */
+ /* mx-supply = <&pm8998_s6>; */
+ /* mss-supply = <&pm8005_s2_level>; */
+
+ qcom,halt-regs = <&tcsr_mutex_regs 0x23000 0x25000 0x24000>;
+
+ mba {
+ memory-region = <&mba_mem>;
+ };
+
+ mpss {
+ memory-region = <&mpss_mem>;
+ };
+
+ glink-edge {
+ interrupts = <0 449 IRQ_TYPE_EDGE_RISING>;
+ label = "modem";
+ qcom,remote-pid = <1>;
+ mboxes = <&apss_shared 12>;
+ mbox-names = "mpss_smem";
+ };
};
spmi_bus: spmi@c440000 {
@@ -323,5 +1629,111 @@
status = "disabled";
};
};
+
+ apps_rsc: rsc@179c0000 {
+ label = "apps_rsc";
+ compatible = "qcom,rpmh-rsc";
+ reg = <0x179c0000 0x10000>,
+ <0x179d0000 0x10000>,
+ <0x179e0000 0x10000>;
+ reg-names = "drv-0", "drv-1", "drv-2";
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>;
+ qcom,tcs-offset = <0xd00>;
+ qcom,drv-id = <2>;
+ qcom,tcs-config = <SLEEP_TCS 3>,
+ <WAKE_TCS 3>,
+ <ACTIVE_TCS 2>,
+ <CONTROL_TCS 1>;
+
+ rpmhcc: clock-controller {
+ compatible = "qcom,sdm845-rpmh-clk";
+ #clock-cells = <1>;
+ };
+ };
+
+ ufsphy: phy@1d87000 {
+ compatible = "qcom,sdm845-qmp-ufs-phy";
+ reg = <0x1d87000 0x18c>;
+ #clock-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ clock-names = "ref_clk_src",
+ "ref_clk",
+ "ref_aux_clk";
+ clocks = <&rpmhcc RPMH_CXO_CLK>,
+ <&gcc GCC_UFS_MEM_CLKREF_CLK>,
+ <&gcc GCC_UFS_PHY_PHY_AUX_CLK>;
+
+ status = "disabled";
+
+ ufsphy_0: lane@0x1d87400 {
+ reg = <0x1d87400 0x108>,
+ <0x1d87600 0x1e0>,
+ <0x1d87c00 0x1dc>;
+ #phy-cells = <0>;
+ };
+
+ ufsphy_1: lane@0x1d87800 {
+ reg = <0x1d87800 0x108>,
+ <0x1d87a00 0x1e0>,
+ <0x1d87c00 0x1dc>;
+ #phy-cells = <0>;
+ };
+ };
+
+ ufshc: ufshc@1d84000 {
+ compatible = "qcom,ufshc";
+ reg = <0x1d84000 0x2500>;
+ interrupts = <0 265 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&ufsphy_0>, <&ufsphy_1>;
+ phy-names = "ufsphy_0", "ufsphy_1";
+
+ lanes-per-direction = <2>;
+ dev-ref-clk-freq = <0>; /* 19.2 MHz */
+
+ power-domains = <&gcc UFS_PHY_GDSC>;
+
+ clock-names =
+ "core_clk",
+ "bus_aggr_clk",
+ "iface_clk",
+ "core_clk_unipro",
+ "ref_clk",
+ "tx_lane0_sync_clk",
+ "rx_lane0_sync_clk",
+ "rx_lane1_sync_clk";
+ clocks =
+ <&gcc GCC_UFS_PHY_AXI_CLK>,
+ <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>,
+ <&gcc GCC_UFS_PHY_AHB_CLK>,
+ <&gcc GCC_UFS_PHY_UNIPRO_CORE_CLK>,
+ <&rpmhcc RPMH_CXO_CLK>,
+ <&gcc GCC_UFS_PHY_TX_SYMBOL_0_CLK>,
+ <&gcc GCC_UFS_PHY_RX_SYMBOL_0_CLK>,
+ <&gcc GCC_UFS_PHY_RX_SYMBOL_1_CLK>;
+ freq-table-hz =
+ <50000000 200000000>,
+ <0 0>,
+ <0 0>,
+ <37500000 150000000>,
+ <0 0>,
+ <0 0>,
+ <0 0>,
+ <0 0>;
+
+ non-removable;
+ pinctrl-names = "dev-reset-assert", "dev-reset-deassert";
+ pinctrl-0 = <&ufs_dev_reset_assert>;
+ pinctrl-1 = <&ufs_dev_reset_deassert>;
+
+ resets = <&gcc GCC_UFS_PHY_BCR>;
+ reset-names = "core_reset";
+
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index f9a186f6af8a..9aeb36ab651e 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -15,7 +15,6 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_NUMA_BALANCING=y
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
-CONFIG_BLK_CGROUP=y
CONFIG_CGROUP_PIDS=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CPUSETS=y
@@ -45,6 +44,7 @@ CONFIG_ARCH_MEDIATEK=y
CONFIG_ARCH_MESON=y
CONFIG_ARCH_MVEBU=y
CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8996=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_ARCH_SEATTLE=y
CONFIG_ARCH_SYNQUACER=y
@@ -108,6 +108,7 @@ CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPUFREQ_DT=y
CONFIG_ACPI_CPPC_CPUFREQ=m
CONFIG_ARM_ARMADA_37XX_CPUFREQ=y
@@ -149,29 +150,41 @@ CONFIG_BRIDGE_VLAN_FILTERING=y
CONFIG_VLAN_8021Q=m
CONFIG_VLAN_8021Q_GVRP=y
CONFIG_VLAN_8021Q_MVRP=y
+CONFIG_QRTR=y
+CONFIG_QRTR_SMD=y
+CONFIG_QRTR_TUN=y
CONFIG_BPF_JIT=y
CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=m
# CONFIG_BT_HS is not set
# CONFIG_BT_LE is not set
CONFIG_BT_LEDS=y
# CONFIG_BT_DEBUGFS is not set
CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
CONFIG_BT_HCIUART_LL=y
+CONFIG_BT_HCIUART_3WIRE=y
CONFIG_BT_HCIUART_BCM=y
-CONFIG_CFG80211=m
-CONFIG_MAC80211=m
+CONFIG_CFG80211=y
+CONFIG_CFG80211_WEXT=y
+CONFIG_MAC80211=y
CONFIG_MAC80211_LEDS=y
-CONFIG_RFKILL=m
+CONFIG_RFKILL=y
+CONFIG_WCN36XX=m
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DMA_CMA=y
-CONFIG_CMA_SIZE_MBYTES=32
-CONFIG_HISILICON_LPC=y
CONFIG_SIMPLE_PM_BUS=y
CONFIG_MTD=y
CONFIG_MTD_BLOCK=y
@@ -184,6 +197,7 @@ CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=m
CONFIG_VIRTIO_BLK=y
CONFIG_BLK_DEV_NVME=m
+CONFIG_QCOM_COINCELL=m
CONFIG_SRAM=y
CONFIG_EEPROM_AT25=m
# CONFIG_SCSI_PROC_FS is not set
@@ -191,9 +205,9 @@ CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_SAS_ATA=y
CONFIG_SCSI_HISI_SAS=y
CONFIG_SCSI_HISI_SAS_PCI=y
-CONFIG_SCSI_UFSHCD=m
-CONFIG_SCSI_UFSHCD_PLATFORM=m
-CONFIG_SCSI_UFS_QCOM=m
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
CONFIG_ATA=y
CONFIG_SATA_AHCI=y
CONFIG_SATA_AHCI_PLATFORM=y
@@ -213,7 +227,7 @@ CONFIG_VETH=m
CONFIG_VIRTIO_NET=y
CONFIG_AMD_XGBE=y
CONFIG_NET_XGENE=y
-CONFIG_ATL1C=m
+CONFIG_ATL1C=y
CONFIG_MACB=y
CONFIG_THUNDER_NIC_PF=y
CONFIG_HIX5HD2_GMAC=y
@@ -251,8 +265,8 @@ CONFIG_USB_NET_SMSC75XX=m
CONFIG_USB_NET_SMSC95XX=m
CONFIG_USB_NET_PLUSB=m
CONFIG_USB_NET_MCS7830=m
-CONFIG_ATH10K=m
-CONFIG_ATH10K_PCI=m
+CONFIG_ATH10K=y
+CONFIG_ATH10K_PCI=y
CONFIG_BRCMFMAC=m
CONFIG_MWIFIEX=m
CONFIG_MWIFIEX_PCIE=m
@@ -288,6 +302,8 @@ CONFIG_SERIAL_SAMSUNG_CONSOLE=y
CONFIG_SERIAL_TEGRA=y
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_MSM=y
+CONFIG_SERIAL_QCOM_GENI=y
+CONFIG_SERIAL_QCOM_GENI_CONSOLE=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_XILINX_PS_UART=y
CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
@@ -329,6 +345,7 @@ CONFIG_PINCTRL_IPQ8074=y
CONFIG_PINCTRL_MSM8916=y
CONFIG_PINCTRL_MSM8994=y
CONFIG_PINCTRL_MSM8996=y
+CONFIG_PINCTRL_SDM845=y
CONFIG_PINCTRL_QDF2XXX=y
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_PINCTRL_MT7622=y
@@ -344,6 +361,7 @@ CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_GPIO_MAX77620=y
CONFIG_POWER_AVS=y
CONFIG_ROCKCHIP_IODOMAIN=y
+CONFIG_QCOM_CPR=y
CONFIG_POWER_RESET_MSM=y
CONFIG_POWER_RESET_XGENE=y
CONFIG_POWER_RESET_SYSCON=y
@@ -362,9 +380,11 @@ CONFIG_BRCMSTB_THERMAL=m
CONFIG_EXYNOS_THERMAL=y
CONFIG_TEGRA_BPMP_THERMAL=m
CONFIG_QCOM_TSENS=y
+CONFIG_QCOM_SPMI_TEMP_ALARM=m
CONFIG_UNIPHIER_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_S3C2410_WATCHDOG=y
+CONFIG_QCOM_WDT=m
CONFIG_MESON_GXBB_WATCHDOG=m
CONFIG_MESON_WATCHDOG=m
CONFIG_RENESAS_WDT=y
@@ -390,6 +410,7 @@ CONFIG_REGULATOR_HI6421V530=y
CONFIG_REGULATOR_HI655X=y
CONFIG_REGULATOR_MAX77620=y
CONFIG_REGULATOR_PWM=y
+CONFIG_REGULATOR_QCOM_RPMH=y
CONFIG_REGULATOR_QCOM_SMD_RPM=y
CONFIG_REGULATOR_QCOM_SPMI=y
CONFIG_REGULATOR_RK808=y
@@ -411,7 +432,7 @@ CONFIG_VIDEO_SAMSUNG_S5P_MFC=m
CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC=m
CONFIG_VIDEO_RENESAS_FCP=m
CONFIG_VIDEO_RENESAS_VSP1=m
-CONFIG_DRM=m
+CONFIG_DRM=y
CONFIG_DRM_NOUVEAU=m
CONFIG_DRM_EXYNOS=m
CONFIG_DRM_EXYNOS5433_DECON=y
@@ -431,6 +452,7 @@ CONFIG_DRM_RCAR_LVDS=m
CONFIG_DRM_TEGRA=m
CONFIG_DRM_PANEL_SIMPLE=m
CONFIG_DRM_I2C_ADV7511=m
+CONFIG_DRM_I2C_ADV7511_AUDIO=y
CONFIG_DRM_VC4=m
CONFIG_DRM_HISI_HIBMC=m
CONFIG_DRM_HISI_KIRIN=m
@@ -447,12 +469,18 @@ CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_BCM2835_SOC_I2S=m
+CONFIG_SND_SOC_QCOM=y
+CONFIG_SND_SOC_APQ8016_SBC=y
+CONFIG_SND_SOC_QDSP6=y
+CONFIG_SND_SOC_MSM8996=y
CONFIG_SND_SOC_SAMSUNG=y
CONFIG_SND_SOC_RCAR=m
CONFIG_SND_SOC_AK4613=m
-CONFIG_SND_SIMPLE_CARD=m
+CONFIG_SND_SIMPLE_CARD=y
CONFIG_SND_AUDIO_GRAPH_CARD=m
CONFIG_I2C_HID=m
+CONFIG_SND_SOC_MSM8916_WCD_ANALOG=y
+CONFIG_SND_SOC_MSM8916_WCD_DIGITAL=y
CONFIG_USB=y
CONFIG_USB_OTG=y
CONFIG_USB_XHCI_HCD=y
@@ -527,6 +555,7 @@ CONFIG_RTC_DRV_S3C=y
CONFIG_RTC_DRV_PL031=y
CONFIG_RTC_DRV_SUN6I=y
CONFIG_RTC_DRV_ARMADA38X=y
+CONFIG_RTC_DRV_PM8XXX=m
CONFIG_RTC_DRV_TEGRA=y
CONFIG_RTC_DRV_XGENE=y
CONFIG_DMADEVICES=y
@@ -555,11 +584,15 @@ CONFIG_CLK_QORIQ=y
CONFIG_COMMON_CLK_PWM=y
CONFIG_COMMON_CLK_QCOM=y
CONFIG_QCOM_CLK_SMD_RPM=y
+CONFIG_QCOM_CLK_RPMH=y
CONFIG_IPQ_GCC_8074=y
+CONFIG_MSM_CLK_RPMH=y
CONFIG_MSM_GCC_8916=y
CONFIG_MSM_GCC_8994=y
CONFIG_MSM_MMCC_8996=y
+CONFIG_MSM_APCC_8996=y
CONFIG_HWSPINLOCK=y
+CONFIG_SDM_GCC_845=y
CONFIG_HWSPINLOCK_QCOM=y
CONFIG_ARM_MHU=y
CONFIG_PLATFORM_MHU=y
@@ -570,13 +603,22 @@ CONFIG_TEGRA_IOMMU_SMMU=y
CONFIG_ARM_SMMU=y
CONFIG_ARM_SMMU_V3=y
CONFIG_QCOM_IOMMU=y
+CONFIG_REMOTEPROC=y
+CONFIG_QCOM_ADSP_PIL=y
+CONFIG_QCOM_Q6V5_PIL=y
+CONFIG_QCOM_SYSMON=y
+CONFIG_QCOM_WCNSS_PIL=y
CONFIG_RPMSG_QCOM_GLINK_RPM=y
+CONFIG_RPMSG_QCOM_GLINK_SMEM=y
CONFIG_RPMSG_QCOM_SMD=y
CONFIG_RASPBERRYPI_POWER=y
+CONFIG_QCOM_RPMH=y
CONFIG_QCOM_SMEM=y
CONFIG_QCOM_SMD_RPM=y
CONFIG_QCOM_SMP2P=y
CONFIG_QCOM_SMSM=y
+CONFIG_QCOM_WCNSS_CTRL=y
+CONFIG_QCOM_APR=y
CONFIG_ROCKCHIP_PM_DOMAINS=y
CONFIG_ARCH_TEGRA_132_SOC=y
CONFIG_ARCH_TEGRA_210_SOC=y
@@ -606,6 +648,9 @@ CONFIG_PHY_SUN4I_USB=y
CONFIG_PHY_HI6220_USB=y
CONFIG_PHY_HISTB_COMBPHY=y
CONFIG_PHY_HISI_INNO_USB2=y
+CONFIG_PHY_QCOM_QMP=y
+CONFIG_PHY_QCOM_USB_HS=y
+CONFIG_PHY_SUN4I_USB=y
CONFIG_PHY_MVEBU_CP110_COMPHY=y
CONFIG_PHY_QCOM_QMP=m
CONFIG_PHY_QCOM_USB_HS=y
@@ -624,6 +669,10 @@ CONFIG_UNIPHIER_EFUSE=y
CONFIG_MESON_EFUSE=m
CONFIG_TEE=y
CONFIG_OPTEE=y
+CONFIG_INTERCONNECT=y
+CONFIG_INTERCONNECT_QCOM=y
+CONFIG_INTERCONNECT_QCOM_MSM8916=y
+CONFIG_INTERCONNECT_QCOM_MSM8996=y
CONFIG_ARM_SCPI_PROTOCOL=y
CONFIG_RASPBERRYPI_FIRMWARE=y
CONFIG_EFI_CAPSULE_LOADER=y
@@ -649,6 +698,8 @@ CONFIG_HUGETLBFS=y
CONFIG_CONFIGFS_FS=y
CONFIG_EFIVAR_FS=y
CONFIG_SQUASHFS=y
+CONFIG_UFS_FS=y
+CONFIG_UFS_FS_WRITE=y
CONFIG_NFS_FS=y
CONFIG_NFS_V4=y
CONFIG_NFS_V4_1=y
@@ -684,3 +735,14 @@ CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
CONFIG_CRYPTO_CHACHA20_NEON=m
CONFIG_CRYPTO_AES_ARM64_BS=m
+CONFIG_CRYPTO_SHA512_ARM64_CE=m
+CONFIG_CRYPTO_SHA3_ARM64=m
+CONFIG_CRYPTO_SM3_ARM64_CE=m
+CONFIG_QTI_RPMH_MBOX=y
+CONFIG_QTI_RPMH_API=y
+CONFIG_QCOM_COMMAND_DB=y
+CONFIG_REGULATOR_RPMH=y
+CONFIG_QCOM_GENI_SE=y
+CONFIG_QCOM_GLINK_SSR=y
+CONFIG_QCOM_RMTFS_MEM=y
+CONFIG_RESET_QCOM_AOSS=y
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 35b2e50f17fb..3be829780fad 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -39,25 +39,25 @@
#define __raw_writeb __raw_writeb
static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
- asm volatile("strb %w0, [%1]" : : "rZ" (val), "r" (addr));
+ asm volatile("strb %w0, [%1]" : : "r" (val), "r" (addr));
}
#define __raw_writew __raw_writew
static inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
- asm volatile("strh %w0, [%1]" : : "rZ" (val), "r" (addr));
+ asm volatile("strh %w0, [%1]" : : "r" (val), "r" (addr));
}
#define __raw_writel __raw_writel
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
- asm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr));
+ asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr));
}
#define __raw_writeq __raw_writeq
static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
{
- asm volatile("str %x0, [%1]" : : "rZ" (val), "r" (addr));
+ asm volatile("str %0, [%1]" : : "r" (val), "r" (addr));
}
#define __raw_readb __raw_readb
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 95b9ccc08165..3ed6ede9d021 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -217,4 +217,6 @@ source "drivers/siox/Kconfig"
source "drivers/slimbus/Kconfig"
+source "drivers/interconnect/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 24cd47014657..0cca95740d9b 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -185,3 +185,4 @@ obj-$(CONFIG_TEE) += tee/
obj-$(CONFIG_MULTIPLEXER) += mux/
obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/
obj-$(CONFIG_SIOX) += siox/
+obj-$(CONFIG_INTERCONNECT) += interconnect/
diff --git a/drivers/base/core.c b/drivers/base/core.c
index df3e1a44707a..135acf0cee96 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -517,6 +517,16 @@ void device_links_driver_cleanup(struct device *dev)
WARN_ON(link->flags & DL_FLAG_AUTOREMOVE);
WARN_ON(link->status != DL_STATE_SUPPLIER_UNBIND);
+
+ /*
+ * autoremove the links between this @dev and its consumer
+ * devices that are not active, i.e. where the link state
+ * has moved to DL_STATE_SUPPLIER_UNBIND.
+ */
+ if (link->status == DL_STATE_SUPPLIER_UNBIND &&
+ link->flags & DL_FLAG_AUTOREMOVE_S)
+ kref_put(&link->kref, __device_link_del);
+
WRITE_ONCE(link->status, DL_STATE_DORMANT);
}
diff --git a/drivers/base/regmap/regmap-slimbus.c b/drivers/base/regmap/regmap-slimbus.c
index 91d501eda8a9..321f3c029250 100644
--- a/drivers/base/regmap/regmap-slimbus.c
+++ b/drivers/base/regmap/regmap-slimbus.c
@@ -31,9 +31,32 @@ static int regmap_slimbus_byte_reg_write(void *context, unsigned int reg,
return slim_writeb(sdev, reg, val);
}
+#define REG_BYTES 2
+
+static int regmap_slimbus_write(void *context, const void *data, size_t count)
+{
+ struct slim_device *sdev = context;
+ unsigned short reg;
+
+ reg = *(u16 *)data + 0x800;
+
+ return slim_write(sdev, reg, count - REG_BYTES, data + REG_BYTES);
+}
+
+static int regmap_slimbus_read(void *context, const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ struct slim_device *sdev = context;
+
+ return slim_read(sdev, *(u16 *)reg + 0x800, val_size, val);
+
+}
+
static struct regmap_bus regmap_slimbus_bus = {
- .reg_write = regmap_slimbus_byte_reg_write,
- .reg_read = regmap_slimbus_byte_reg_read,
+ //.reg_write = regmap_slimbus_byte_reg_write,
+ //.reg_read = regmap_slimbus_byte_reg_read,
+ .write = regmap_slimbus_write,
+ .read = regmap_slimbus_read,
.reg_format_endian_default = REGMAP_ENDIAN_LITTLE,
.val_format_endian_default = REGMAP_ENDIAN_LITTLE,
};
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 9c3480dcc38a..be3e78c1bd75 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -59,6 +59,15 @@ config QCOM_CLK_SMD_RPM
Say Y if you want to support the clocks exposed by the RPM on
platforms such as apq8016, apq8084, msm8974 etc.
+config QCOM_CLK_RPMH
+ tristate "RPMh Clock Driver"
+ depends on COMMON_CLK_QCOM && QCOM_RPMH
+ help
+ RPMh manages shared resources on some Qualcomm Technologies, Inc.
+ SoCs. It accepts requests from other hardware subsystems via RSC.
+ Say Y if you want to support the clocks exposed by RPMh on
+ platforms such as SDM845.
+
config APQ_GCC_8084
tristate "APQ8084 Global Clock Controller"
select QCOM_GDSC
@@ -253,3 +262,11 @@ config SPMI_PMIC_CLKDIV
Technologies, Inc. SPMI PMIC. It configures the frequency of
clkdiv outputs of the PMIC. These clocks are typically wired
through alternate functions on GPIO pins.
+
+config MSM_APCC_8996
+ tristate "MSM8996 CPU Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the CPU clock controller on msm8996 devices.
+ Say Y if you want to support CPU clock scaling using CPUfreq
+ drivers for dyanmic power management.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 762c01137c2f..c051525e9db7 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -34,9 +34,11 @@ obj-$(CONFIG_MSM_GCC_8998) += gcc-msm8998.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_MSM_APCC_8996) += clk-cpu-8996.o
obj-$(CONFIG_QCOM_A53PLL) += a53-pll.o
obj-$(CONFIG_QCOM_CLK_APCS_MSM8916) += apcs-msm8916.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
+obj-$(CONFIG_QCOM_CLK_RPMH) += clk-rpmh.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
obj-$(CONFIG_SDM_GCC_845) += gcc-sdm845.o
obj-$(CONFIG_SDM_VIDEOCC_845) += videocc-sdm845.o
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index 3c49a60072f1..a43f80ac94a4 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -228,6 +228,7 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
if (pll->flags & SUPPORTS_FSM_MODE)
qcom_pll_set_fsm_mode(regmap, PLL_MODE(pll), 6, 0);
}
+EXPORT_SYMBOL_GPL(clk_alpha_pll_configure);
static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)
{
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
new file mode 100644
index 000000000000..155279186c32
--- /dev/null
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/clk-provider.h>
+#include "clk-alpha-pll.h"
+#include <soc/qcom/kryo-l2-accessors.h>
+
+#define VCO(a, b, c) { \
+ .val = a,\
+ .min_freq = b,\
+ .max_freq = c,\
+}
+
+#define DIV_2_INDEX 0
+#define PLL_INDEX 1
+#define ACD_INDEX 2
+#define ALT_INDEX 3
+#define DIV_2_THRESHOLD 600000000
+#define PWRCL_REG_OFFSET 0x0
+#define PERFCL_REG_OFFSET 0x80000
+#define MUX_OFFSET 0x40
+#define ALT_PLL_OFFSET 0x100
+#define SSSCTL_OFFSET 0x160
+/*
+APCy_QLL_SSSCTL value:
+SACDRCLEN=1
+SSWEN=1
+SSTRTEN=1
+SSTPAPMSWEN=1
+*/
+#define SSSCTL_VAL 0xF
+
+enum {
+ APC_BASE,
+ EFUSE_BASE,
+ NUM_BASES
+};
+
+static void __iomem *vbases[NUM_BASES];
+
+static const u8 prim_pll_regs[PLL_OFF_MAX_REGS] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_USER_CTL] = 0x10,
+ [PLL_OFF_CONFIG_CTL] = 0x18,
+ [PLL_OFF_CONFIG_CTL_U] = 0x1C,
+ [PLL_OFF_TEST_CTL] = 0x20,
+ [PLL_OFF_TEST_CTL_U] = 0x24,
+ [PLL_OFF_STATUS] = 0x28,
+};
+
+static const u8 alt_pll_regs[PLL_OFF_MAX_REGS] = {
+ [PLL_OFF_L_VAL] = 0x04,
+ [PLL_OFF_ALPHA_VAL] = 0x08,
+ [PLL_OFF_ALPHA_VAL_U] = 0x0c,
+ [PLL_OFF_USER_CTL] = 0x10,
+ [PLL_OFF_USER_CTL_U] = 0x14,
+ [PLL_OFF_CONFIG_CTL] = 0x18,
+ [PLL_OFF_TEST_CTL] = 0x20,
+ [PLL_OFF_TEST_CTL_U] = 0x24,
+ [PLL_OFF_STATUS] = 0x28,
+};
+
+/* PLLs */
+
+static const struct alpha_pll_config hfpll_config = {
+ .l = 60,
+ .config_ctl_val = 0x200D4AA8,
+ .config_ctl_hi_val = 0x006,
+ .pre_div_mask = BIT(12),
+ .post_div_mask = 0x3 << 8,
+ .post_div_val = 0x1 << 8,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_pll = {
+ .offset = PERFCL_REG_OFFSET,
+ .regs = prim_pll_regs,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "perfcl_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_huayra_ops,
+ },
+};
+
+static struct clk_alpha_pll pwrcl_pll = {
+ .offset = PWRCL_REG_OFFSET,
+ .regs = prim_pll_regs,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pwrcl_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_huayra_ops,
+ },
+};
+
+static const struct pll_vco alt_pll_vco_modes[] = {
+ VCO(3, 250000000, 500000000),
+ VCO(2, 500000000, 750000000),
+ VCO(1, 750000000, 1000000000),
+ VCO(0, 1000000000, 2150400000),
+};
+
+static const struct alpha_pll_config altpll_config = {
+ .l = 16,
+ .vco_val = 0x3 << 20,
+ .vco_mask = 0x3 << 20,
+ .config_ctl_val = 0x4001051b,
+ .post_div_mask = 0x3 << 8,
+ .post_div_val = 0x1 << 8,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_alt_pll = {
+ .offset = PERFCL_REG_OFFSET + ALT_PLL_OFFSET,
+ .regs = alt_pll_regs,
+ .vco_table = alt_pll_vco_modes,
+ .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+ .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_alt_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+static struct clk_alpha_pll pwrcl_alt_pll = {
+ .offset = PWRCL_REG_OFFSET + ALT_PLL_OFFSET,
+ .regs = alt_pll_regs,
+ .vco_table = alt_pll_vco_modes,
+ .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+ .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_alt_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+static void qcom_cpu_clk_msm8996_acd_init(void);
+
+/* Mux'es */
+
+struct clk_cpu_8996_mux {
+ u32 reg;
+ u32 shift;
+ u32 width;
+ struct notifier_block nb;
+ struct clk_hw *pll;
+ struct clk_hw *pll_div_2;
+ struct clk_regmap clkr;
+};
+
+#define to_clk_cpu_8996_mux_nb(_nb) \
+ container_of(_nb, struct clk_cpu_8996_mux, nb)
+
+static inline
+struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_cpu_8996_mux, clkr);
+}
+
+static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw)
+{
+ unsigned int val;
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ unsigned int mask = GENMASK(cpuclk->width - 1, 0);
+
+ regmap_read(clkr->regmap, cpuclk->reg, &val);
+
+ val >>= cpuclk->shift;
+ val &= mask;
+
+ return val;
+}
+
+static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ unsigned int val;
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ unsigned int mask = GENMASK(cpuclk->width + cpuclk->shift - 1,
+ cpuclk->shift);
+
+ val = index;
+ val <<= cpuclk->shift;
+
+ return regmap_update_bits(clkr->regmap, cpuclk->reg, mask, val);
+}
+
+static int
+clk_cpu_8996_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ struct clk_hw *parent = cpuclk->pll;
+
+ if (!cpuclk->pll)
+ return -EINVAL;
+
+ if (cpuclk->pll_div_2 && req->rate < DIV_2_THRESHOLD) {
+ if (req->rate < (DIV_2_THRESHOLD / 2))
+ return -EINVAL;
+
+ parent = cpuclk->pll_div_2;
+ }
+
+ req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+ req->best_parent_hw = parent;
+
+ return 0;
+}
+
+int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ int ret;
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
+ struct clk_notifier_data *cnd = data;
+
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
+ qcom_cpu_clk_msm8996_acd_init();
+ break;
+ case POST_RATE_CHANGE:
+ if (cnd->new_rate < DIV_2_THRESHOLD)
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
+ DIV_2_INDEX);
+ else
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
+ ACD_INDEX);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return notifier_from_errno(ret);
+};
+
+const struct clk_ops clk_cpu_8996_mux_ops = {
+ .set_parent = clk_cpu_8996_mux_set_parent,
+ .get_parent = clk_cpu_8996_mux_get_parent,
+ .determine_rate = clk_cpu_8996_mux_determine_rate,
+};
+
+static struct clk_cpu_8996_mux pwrcl_smux = {
+ .reg = PWRCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 2,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_smux",
+ .parent_names = (const char *[]){
+ "xo",
+ "pwrcl_pll_main",
+ },
+ .num_parents = 2,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux perfcl_smux = {
+ .reg = PERFCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 2,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_smux",
+ .parent_names = (const char *[]){
+ "xo",
+ "perfcl_pll_main",
+ },
+ .num_parents = 2,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux pwrcl_pmux = {
+ .reg = PWRCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 0,
+ .width = 2,
+ .pll = &pwrcl_pll.clkr.hw,
+ .pll_div_2 = &pwrcl_smux.clkr.hw,
+ .nb.notifier_call = cpu_clk_notifier_cb,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_pmux",
+ .parent_names = (const char *[]){
+ "pwrcl_smux",
+ "pwrcl_pll",
+ "pwrcl_pll_acd",
+ "pwrcl_alt_pll",
+ },
+ .num_parents = 4,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+ },
+};
+
+static struct clk_cpu_8996_mux perfcl_pmux = {
+ .reg = PERFCL_REG_OFFSET + MUX_OFFSET,
+ .shift = 0,
+ .width = 2,
+ .pll = &perfcl_pll.clkr.hw,
+ .pll_div_2 = &perfcl_smux.clkr.hw,
+ .nb.notifier_call = cpu_clk_notifier_cb,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_pmux",
+ .parent_names = (const char *[]){
+ "perfcl_smux",
+ "perfcl_pll",
+ "perfcl_pll_acd",
+ "perfcl_alt_pll",
+ },
+ .num_parents = 4,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+ },
+};
+
+static const struct regmap_config cpu_msm8996_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x80210,
+ .fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static const struct of_device_id match_table[] = {
+ { .compatible = "qcom-msm8996-apcc" },
+ {}
+};
+
+struct clk_regmap *clks[] = {
+ /* PLLs */
+ &perfcl_pll.clkr,
+ &pwrcl_pll.clkr,
+ &perfcl_alt_pll.clkr,
+ &pwrcl_alt_pll.clkr,
+ /* MUXs */
+ &perfcl_smux.clkr,
+ &pwrcl_smux.clkr,
+ &perfcl_pmux.clkr,
+ &pwrcl_pmux.clkr,
+};
+
+struct clk_hw_clks {
+ unsigned int num;
+ struct clk_hw *hws[];
+};
+
+static int
+qcom_cpu_clk_msm8996_register_clks(struct device *dev, struct clk_hw_clks *hws,
+ struct regmap *regmap)
+{
+ int i, ret;
+
+ hws->hws[0] = clk_hw_register_fixed_factor(dev, "perfcl_pll_main",
+ "perfcl_pll",
+ CLK_SET_RATE_PARENT, 1, 2);
+ perfcl_smux.pll = hws->hws[0];
+
+ hws->hws[1] = clk_hw_register_fixed_factor(dev, "pwrcl_pll_main",
+ "pwrcl_pll",
+ CLK_SET_RATE_PARENT, 1, 2);
+ pwrcl_smux.pll = hws->hws[1];
+
+ hws->num = 2;
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++) {
+ ret = devm_clk_register_regmap(dev, clks[i]);
+ if (ret)
+ return ret;
+ }
+
+ clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
+ clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
+ clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
+ clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
+
+ /* Enable all PLLs and alt PLLs */
+ clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
+ clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
+ clk_prepare_enable(pwrcl_pll.clkr.hw.clk);
+ clk_prepare_enable(perfcl_pll.clkr.hw.clk);
+
+ /* Set initial boot frequencies for power/perf PLLs */
+ clk_set_rate(pwrcl_alt_pll.clkr.hw.clk, 652800000);
+ clk_set_rate(perfcl_alt_pll.clkr.hw.clk, 652800000);
+ clk_set_rate(pwrcl_pll.clkr.hw.clk, 652800000);
+ clk_set_rate(perfcl_pll.clkr.hw.clk, 652800000);
+
+ ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
+ if (ret)
+ return ret;
+
+ ret = clk_notifier_register(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+#define CPU_AFINITY_MASK 0xFFF
+#define PWRCL_CPU_REG_MASK 0x3
+#define PERFCL_CPU_REG_MASK 0x103
+
+/* ACD static settings (HMSS HPG 7.2.2) */
+#define L2ACDCR_REG 0x580ULL
+#define L2ACDTD_REG 0x581ULL
+#define L2ACDDVMRC_REG 0x584ULL
+#define L2ACDSSCR_REG 0x589ULL
+#define ACDTD_VAL 0x00006A11
+#define ACDCR_VAL 0x002C5FFD
+#define ACDSSCR_VAL 0x00000601
+#define ACDDVMRC_VAL 0x000E0F0F
+
+static DEFINE_SPINLOCK(acd_lock);
+
+static void qcom_cpu_clk_msm8996_acd_init(void)
+{
+ u64 hwid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&acd_lock, flags);
+
+ hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK;
+
+ /* Program ACD Tunable-Length Delay (TLD) */
+ set_l2_indirect_reg(L2ACDTD_REG, ACDTD_VAL);
+ /* Initial ACD for *this* cluster */
+ set_l2_indirect_reg(L2ACDDVMRC_REG, ACDDVMRC_VAL);
+ /* Program ACD soft start control bits. */
+ set_l2_indirect_reg(L2ACDSSCR_REG, ACDSSCR_VAL);
+
+ if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
+ /* Enable Soft Stop/Start */
+ if (vbases[APC_BASE])
+ writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+ PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+ /* Ensure SSSCTL config goes through before enabling ACD. */
+ mb();
+ /* Program ACD control bits */
+ set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+ }
+ if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) { //else {
+ /* Program ACD control bits */
+ set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+ /* Enable Soft Stop/Start */
+ if (vbases[APC_BASE])
+ writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+ PERFCL_REG_OFFSET + SSSCTL_OFFSET);
+ /* Ensure SSSCTL config goes through before enabling ACD. */
+ mb();
+ }
+
+ spin_unlock_irqrestore(&acd_lock, flags);
+}
+static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+ struct regmap *regmap_cpu;
+ struct clk_hw_clks *hws;
+ struct clk_hw_onecell_data *data;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+
+ data = devm_kzalloc(dev, sizeof(*data) + 2 * sizeof(struct clk_hw *),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ hws = devm_kzalloc(dev, sizeof(*hws) + 4 * sizeof(struct clk_hw *),
+ GFP_KERNEL);
+ if (!hws)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ vbases[APC_BASE] = devm_ioremap_resource(dev, res);
+ if (IS_ERR(vbases[APC_BASE]))
+ return PTR_ERR(vbases[APC_BASE]);
+
+ regmap_cpu = devm_regmap_init_mmio(dev, vbases[APC_BASE],
+ &cpu_msm8996_regmap_config);
+ if (IS_ERR(regmap_cpu))
+ return PTR_ERR(regmap_cpu);
+
+ ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
+ if (ret)
+ return ret;
+ qcom_cpu_clk_msm8996_acd_init();
+
+ data->hws[0] = &pwrcl_pmux.clkr.hw;
+ data->hws[1] = &perfcl_pmux.clkr.hw;
+
+ data->num = 2;
+
+ platform_set_drvdata(pdev, hws);
+
+ return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data);
+}
+
+static int qcom_cpu_clk_msm8996_driver_remove(struct platform_device *pdev)
+{
+ int i;
+ struct device *dev = &pdev->dev;
+ struct clk_hw_clks *hws = platform_get_drvdata(pdev);
+
+ for (i = 0; i < hws->num; i++)
+ clk_hw_unregister_fixed_rate(hws->hws[i]);
+
+ of_clk_del_provider(dev->of_node);
+
+ return 0;
+}
+
+static struct platform_driver qcom_cpu_clk_msm8996_driver = {
+ .probe = qcom_cpu_clk_msm8996_driver_probe,
+ .remove = qcom_cpu_clk_msm8996_driver_remove,
+ .driver = {
+ .name = "qcom-msm8996-apcc",
+ .of_match_table = match_table,
+ },
+};
+
+module_platform_driver(qcom_cpu_clk_msm8996_driver);
+
+MODULE_ALIAS("platform:msm8996-apcc");
+MODULE_DESCRIPTION("QCOM MSM8996 CPU clock Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c
new file mode 100644
index 000000000000..64b371cd4dca
--- /dev/null
+++ b/drivers/clk/qcom/clk-rpmh.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <soc/qcom/cmd-db.h>
+#include <soc/qcom/rpmh.h>
+
+#include <dt-bindings/clock/qcom,rpmh.h>
+
+#define CLK_RPMH_ARC_EN_OFFSET 0
+#define CLK_RPMH_VRM_EN_OFFSET 4
+
+/**
+ * struct clk_rpmh - individual rpmh clock data structure
+ * @hw: handle between common and hardware-specific interfaces
+ * @res_name: resource name for the rpmh clock
+ * @div: clock divider to compute the clock rate
+ * @res_addr: base address of the rpmh resource within the RPMh
+ * @res_on_val: rpmh clock enable value
+ * @state: rpmh clock requested state
+ * @aggr_state: rpmh clock aggregated state
+ * @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh
+ * @valid_state_mask: mask to determine the state of the rpmh clock
+ * @dev: device to which it is attached
+ * @peer: pointer to the clock rpmh sibling
+ */
+struct clk_rpmh {
+ struct clk_hw hw;
+ const char *res_name;
+ u8 div;
+ u32 res_addr;
+ u32 res_on_val;
+ u32 state;
+ u32 aggr_state;
+ u32 last_sent_aggr_state;
+ u32 valid_state_mask;
+ struct device *dev;
+ struct clk_rpmh *peer;
+};
+
+struct clk_rpmh_desc {
+ struct clk_hw **clks;
+ size_t num_clks;
+};
+
+static DEFINE_MUTEX(rpmh_clk_lock);
+
+#define __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \
+ _res_en_offset, _res_on, _div) \
+ static struct clk_rpmh _platform##_##_name_active; \
+ static struct clk_rpmh _platform##_##_name = { \
+ .res_name = _res_name, \
+ .res_addr = _res_en_offset, \
+ .res_on_val = _res_on, \
+ .div = _div, \
+ .peer = &_platform##_##_name_active, \
+ .valid_state_mask = (BIT(RPMH_WAKE_ONLY_STATE) | \
+ BIT(RPMH_ACTIVE_ONLY_STATE) | \
+ BIT(RPMH_SLEEP_STATE)), \
+ .hw.init = &(struct clk_init_data){ \
+ .ops = &clk_rpmh_ops, \
+ .name = #_name, \
+ .parent_names = (const char *[]){ "xo_board" }, \
+ .num_parents = 1, \
+ }, \
+ }; \
+ static struct clk_rpmh _platform##_##_name_active = { \
+ .res_name = _res_name, \
+ .res_addr = _res_en_offset, \
+ .res_on_val = _res_on, \
+ .div = _div, \
+ .peer = &_platform##_##_name, \
+ .valid_state_mask = (BIT(RPMH_WAKE_ONLY_STATE) | \
+ BIT(RPMH_ACTIVE_ONLY_STATE)), \
+ .hw.init = &(struct clk_init_data){ \
+ .ops = &clk_rpmh_ops, \
+ .name = #_name_active, \
+ .parent_names = (const char *[]){ "xo_board" }, \
+ .num_parents = 1, \
+ }, \
+ }
+
+#define DEFINE_CLK_RPMH_ARC(_platform, _name, _name_active, _res_name, \
+ _res_on, _div) \
+ __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \
+ CLK_RPMH_ARC_EN_OFFSET, _res_on, _div)
+
+#define DEFINE_CLK_RPMH_VRM(_platform, _name, _name_active, _res_name, \
+ _div) \
+ __DEFINE_CLK_RPMH(_platform, _name, _name_active, _res_name, \
+ CLK_RPMH_VRM_EN_OFFSET, 1, _div)
+
+static inline struct clk_rpmh *to_clk_rpmh(struct clk_hw *_hw)
+{
+ return container_of(_hw, struct clk_rpmh, hw);
+}
+
+static inline bool has_state_changed(struct clk_rpmh *c, u32 state)
+{
+ return (c->last_sent_aggr_state & BIT(state))
+ != (c->aggr_state & BIT(state));
+}
+
+static int clk_rpmh_send_aggregate_command(struct clk_rpmh *c)
+{
+ struct tcs_cmd cmd = { 0 };
+ u32 cmd_state, on_val;
+ enum rpmh_state state = RPMH_SLEEP_STATE;
+ int ret;
+
+ cmd.addr = c->res_addr;
+ cmd_state = c->aggr_state;
+ on_val = c->res_on_val;
+
+ for (; state <= RPMH_ACTIVE_ONLY_STATE; state++) {
+ if (has_state_changed(c, state)) {
+ if (cmd_state & BIT(state))
+ cmd.data = on_val;
+
+ ret = rpmh_write_async(c->dev, state, &cmd, 1);
+ if (ret) {
+ dev_err(c->dev, "set %s state of %s failed: (%d)\n",
+ !state ? "sleep" :
+ state == RPMH_WAKE_ONLY_STATE ?
+ "wake" : "active", c->res_name, ret);
+ return ret;
+ }
+ }
+ }
+
+ c->last_sent_aggr_state = c->aggr_state;
+ c->peer->last_sent_aggr_state = c->last_sent_aggr_state;
+
+ return 0;
+}
+
+/*
+ * Update state and aggregate state values based on enable value.
+ */
+static int clk_rpmh_aggregate_state_send_command(struct clk_rpmh *c,
+ bool enable)
+{
+ int ret;
+
+ /* Nothing required to be done if already off or on */
+ if (enable == c->state)
+ return 0;
+
+ c->state = enable ? c->valid_state_mask : 0;
+ c->aggr_state = c->state | c->peer->state;
+ c->peer->aggr_state = c->aggr_state;
+
+ ret = clk_rpmh_send_aggregate_command(c);
+ if (!ret)
+ return 0;
+ if (ret && enable)
+ c->state = 0;
+ else if (ret)
+ c->state = c->valid_state_mask;
+
+ WARN(1, "clk: %s failed to %s\n", c->res_name,
+ enable ? "enable" : "disable");
+ return ret;
+}
+
+static int clk_rpmh_prepare(struct clk_hw *hw)
+{
+ struct clk_rpmh *c = to_clk_rpmh(hw);
+ int ret = 0;
+
+ mutex_lock(&rpmh_clk_lock);
+ ret = clk_rpmh_aggregate_state_send_command(c, true);
+ mutex_unlock(&rpmh_clk_lock);
+
+ return ret;
+};
+
+static void clk_rpmh_unprepare(struct clk_hw *hw)
+{
+ struct clk_rpmh *c = to_clk_rpmh(hw);
+
+ mutex_lock(&rpmh_clk_lock);
+ clk_rpmh_aggregate_state_send_command(c, false);
+ mutex_unlock(&rpmh_clk_lock);
+};
+
+static unsigned long clk_rpmh_recalc_rate(struct clk_hw *hw,
+ unsigned long prate)
+{
+ struct clk_rpmh *r = to_clk_rpmh(hw);
+
+ /*
+ * RPMh clocks have a fixed rate. Return static rate.
+ */
+ return prate / r->div;
+}
+
+static const struct clk_ops clk_rpmh_ops = {
+ .prepare = clk_rpmh_prepare,
+ .unprepare = clk_rpmh_unprepare,
+ .recalc_rate = clk_rpmh_recalc_rate,
+};
+
+/* Resource name must match resource id present in cmd-db. */
+DEFINE_CLK_RPMH_ARC(sdm845, bi_tcxo, bi_tcxo_ao, "xo.lvl", 0x3, 2);
+DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk2, ln_bb_clk2_ao, "lnbclka2", 2);
+DEFINE_CLK_RPMH_VRM(sdm845, ln_bb_clk3, ln_bb_clk3_ao, "lnbclka3", 2);
+DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1);
+DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1);
+DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1);
+
+static struct clk_hw *sdm845_rpmh_clocks[] = {
+ [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw,
+ [RPMH_CXO_CLK_A] = &sdm845_bi_tcxo_ao.hw,
+ [RPMH_LN_BB_CLK2] = &sdm845_ln_bb_clk2.hw,
+ [RPMH_LN_BB_CLK2_A] = &sdm845_ln_bb_clk2_ao.hw,
+ [RPMH_LN_BB_CLK3] = &sdm845_ln_bb_clk3.hw,
+ [RPMH_LN_BB_CLK3_A] = &sdm845_ln_bb_clk3_ao.hw,
+ [RPMH_RF_CLK1] = &sdm845_rf_clk1.hw,
+ [RPMH_RF_CLK1_A] = &sdm845_rf_clk1_ao.hw,
+ [RPMH_RF_CLK2] = &sdm845_rf_clk2.hw,
+ [RPMH_RF_CLK2_A] = &sdm845_rf_clk2_ao.hw,
+ [RPMH_RF_CLK3] = &sdm845_rf_clk3.hw,
+ [RPMH_RF_CLK3_A] = &sdm845_rf_clk3_ao.hw,
+};
+
+static const struct clk_rpmh_desc clk_rpmh_sdm845 = {
+ .clks = sdm845_rpmh_clocks,
+ .num_clks = ARRAY_SIZE(sdm845_rpmh_clocks),
+};
+
+static struct clk_hw *of_clk_rpmh_hw_get(struct of_phandle_args *clkspec,
+ void *data)
+{
+ struct clk_rpmh_desc *rpmh = data;
+ unsigned int idx = clkspec->args[0];
+
+ if (idx >= rpmh->num_clks) {
+ pr_err("%s: invalid index %u\n", __func__, idx);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return rpmh->clks[idx];
+}
+
+static int clk_rpmh_probe(struct platform_device *pdev)
+{
+ struct clk_hw **hw_clks;
+ struct clk_rpmh *rpmh_clk;
+ const struct clk_rpmh_desc *desc;
+ int ret, i;
+
+ ret = cmd_db_ready();
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Command DB not available (%d)\n",
+ ret);
+ return ret;
+ }
+
+ desc = of_device_get_match_data(&pdev->dev);
+ hw_clks = desc->clks;
+
+ for (i = 0; i < desc->num_clks; i++) {
+ u32 res_addr;
+
+ rpmh_clk = to_clk_rpmh(hw_clks[i]);
+ res_addr = cmd_db_read_addr(rpmh_clk->res_name);
+ if (!res_addr) {
+ dev_err(&pdev->dev, "missing RPMh resource address for %s\n",
+ rpmh_clk->res_name);
+ return -ENODEV;
+ }
+ rpmh_clk->res_addr += res_addr;
+ rpmh_clk->dev = &pdev->dev;
+
+ ret = devm_clk_hw_register(&pdev->dev, hw_clks[i]);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register %s\n",
+ hw_clks[i]->init->name);
+ return ret;
+ }
+ }
+
+ /* typecast to silence compiler warning */
+ ret = devm_of_clk_add_hw_provider(&pdev->dev, of_clk_rpmh_hw_get,
+ (void *) desc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add clock provider\n");
+ return ret;
+ }
+
+ dev_dbg(&pdev->dev, "Registered RPMh clocks\n");
+
+ return 0;
+}
+
+static const struct of_device_id clk_rpmh_match_table[] = {
+ { .compatible = "qcom,sdm845-rpmh-clk", .data = &clk_rpmh_sdm845},
+ { }
+};
+MODULE_DEVICE_TABLE(of, clk_rpmh_match_table);
+
+static struct platform_driver clk_rpmh_driver = {
+ .probe = clk_rpmh_probe,
+ .driver = {
+ .name = "clk-rpmh",
+ .of_match_table = clk_rpmh_match_table,
+ },
+};
+
+static int __init clk_rpmh_init(void)
+{
+ return platform_driver_register(&clk_rpmh_driver);
+}
+subsys_initcall(clk_rpmh_init);
+
+static void __exit clk_rpmh_exit(void)
+{
+ platform_driver_unregister(&clk_rpmh_driver);
+}
+module_exit(clk_rpmh_exit);
+
+MODULE_DESCRIPTION("QCOM RPMh Clock Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/qcom/gcc-msm8996.c b/drivers/clk/qcom/gcc-msm8996.c
index 9f35b3fe1d97..7a75e3da300d 100644
--- a/drivers/clk/qcom/gcc-msm8996.c
+++ b/drivers/clk/qcom/gcc-msm8996.c
@@ -262,6 +262,36 @@ static struct clk_alpha_pll_postdiv gpll0 = {
},
};
+static struct clk_branch gcc_mmss_gpll0_div_clk = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mmss_gpll0_div_clk",
+ .parent_names = (const char *[]){ "gpll0" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_gpll0_div_clk = {
+ .halt_check = BRANCH_HALT_DELAY,
+ .clkr = {
+ .enable_reg = 0x5200c,
+ .enable_mask = BIT(2),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_gpll0_div_clk",
+ .parent_names = (const char *[]){ "gpll0" },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops
+ },
+ },
+};
+
static struct clk_alpha_pll gpll4_early = {
.offset = 0x77000,
.regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_DEFAULT],
@@ -2892,6 +2922,36 @@ static struct clk_branch gcc_ufs_tx_symbol_clk_core_clk = {
},
};
+static struct clk_branch hlos1_vote_lpass_core_smmu_clk = {
+ .halt_reg = 0x7d010,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x7d010,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "hlos1_vote_lpass_core_smmu_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch hlos1_vote_lpass_adsp_smmu_clk = {
+ .halt_reg = 0x7d014,
+ .halt_check = BRANCH_VOTED,
+ .clkr = {
+ .enable_reg = 0x7d014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "hlos1_vote_lpass_adsp_smmu_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_aggre0_snoc_axi_clk = {
.halt_reg = 0x81008,
.clkr = {
@@ -2952,6 +3012,20 @@ static struct clk_branch gcc_smmu_aggre0_ahb_clk = {
},
};
+static struct clk_branch gcc_aggre1_pnoc_ahb_clk = {
+ .halt_reg = 0x82014,
+ .clkr = {
+ .enable_reg = 0x82014,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre1_pnoc_ahb_clk",
+ .parent_names = (const char *[]){ "periph_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_aggre2_ufs_axi_clk = {
.halt_reg = 0x83014,
.clkr = {
@@ -2982,6 +3056,34 @@ static struct clk_branch gcc_aggre2_usb3_axi_clk = {
},
};
+static struct clk_branch gcc_dcc_ahb_clk = {
+ .halt_reg = 0x84004,
+ .clkr = {
+ .enable_reg = 0x84004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_dcc_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_aggre0_noc_mpu_cfg_ahb_clk = {
+ .halt_reg = 0x85000,
+ .clkr = {
+ .enable_reg = 0x85000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_aggre0_noc_mpu_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_qspi_ahb_clk = {
.halt_reg = 0x8b004,
.clkr = {
@@ -3040,6 +3142,20 @@ static struct clk_branch gcc_hdmi_clkref_clk = {
},
};
+static struct clk_branch gcc_edp_clkref_clk = {
+ .halt_reg = 0x88004,
+ .clkr = {
+ .enable_reg = 0x88004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_edp_clkref_clk",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_ufs_clkref_clk = {
.halt_reg = 0x88008,
.clkr = {
@@ -3096,6 +3212,62 @@ static struct clk_branch gcc_rx1_usb2_clkref_clk = {
},
};
+static struct clk_branch gcc_mss_cfg_ahb_clk = {
+ .halt_reg = 0x8a000,
+ .clkr = {
+ .enable_reg = 0x8a000,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_cfg_ahb_clk",
+ .parent_names = (const char *[]){ "config_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_mnoc_bimc_axi_clk = {
+ .halt_reg = 0x8a004,
+ .clkr = {
+ .enable_reg = 0x8a004,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_mnoc_bimc_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_snoc_axi_clk = {
+ .halt_reg = 0x8a024,
+ .clkr = {
+ .enable_reg = 0x8a024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_snoc_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
+static struct clk_branch gcc_mss_q6_bimc_axi_clk = {
+ .halt_reg = 0x8a028,
+ .clkr = {
+ .enable_reg = 0x8a028,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_mss_q6_bimc_axi_clk",
+ .parent_names = (const char *[]){ "system_noc_clk_src" },
+ .num_parents = 1,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_hw *gcc_msm8996_hws[] = {
&xo.hw,
&gpll0_early_div.hw,
@@ -3356,6 +3528,7 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
[GCC_AGGRE0_CNOC_AHB_CLK] = &gcc_aggre0_cnoc_ahb_clk.clkr,
[GCC_SMMU_AGGRE0_AXI_CLK] = &gcc_smmu_aggre0_axi_clk.clkr,
[GCC_SMMU_AGGRE0_AHB_CLK] = &gcc_smmu_aggre0_ahb_clk.clkr,
+ [GCC_AGGRE1_PNOC_AHB_CLK] = &gcc_aggre1_pnoc_ahb_clk.clkr,
[GCC_AGGRE2_UFS_AXI_CLK] = &gcc_aggre2_ufs_axi_clk.clkr,
[GCC_AGGRE2_USB3_AXI_CLK] = &gcc_aggre2_usb3_axi_clk.clkr,
[GCC_QSPI_AHB_CLK] = &gcc_qspi_ahb_clk.clkr,
@@ -3366,6 +3539,19 @@ static struct clk_regmap *gcc_msm8996_clocks[] = {
[GCC_PCIE_CLKREF_CLK] = &gcc_pcie_clkref_clk.clkr,
[GCC_RX2_USB2_CLKREF_CLK] = &gcc_rx2_usb2_clkref_clk.clkr,
[GCC_RX1_USB2_CLKREF_CLK] = &gcc_rx1_usb2_clkref_clk.clkr,
+ [GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK] =
+ &hlos1_vote_lpass_core_smmu_clk.clkr,
+ [GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK] =
+ &hlos1_vote_lpass_adsp_smmu_clk.clkr,
+ [GCC_EDP_CLKREF_CLK] = &gcc_edp_clkref_clk.clkr,
+ [GCC_MSS_CFG_AHB_CLK] = &gcc_mss_cfg_ahb_clk.clkr,
+ [GCC_MSS_Q6_BIMC_AXI_CLK] = &gcc_mss_q6_bimc_axi_clk.clkr,
+ [GCC_MSS_SNOC_AXI_CLK] = &gcc_mss_snoc_axi_clk.clkr,
+ [GCC_MSS_MNOC_BIMC_AXI_CLK] = &gcc_mss_mnoc_bimc_axi_clk.clkr,
+ [GCC_DCC_AHB_CLK] = &gcc_dcc_ahb_clk.clkr,
+ [GCC_AGGRE0_NOC_MPU_CFG_AHB_CLK] = &gcc_aggre0_noc_mpu_cfg_ahb_clk.clkr,
+ [GCC_MMSS_GPLL0_DIV_CLK] = &gcc_mmss_gpll0_div_clk.clkr,
+ [GCC_MSS_GPLL0_DIV_CLK] = &gcc_mss_gpll0_div_clk.clkr,
};
static struct gdsc *gcc_msm8996_gdscs[] = {
diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c
index 1a25ee4f3658..dfc5b4e431d3 100644
--- a/drivers/clk/qcom/mmcc-msm8996.c
+++ b/drivers/clk/qcom/mmcc-msm8996.c
@@ -3054,16 +3054,6 @@ static struct gdsc mdss_gdsc = {
.pwrsts = PWRSTS_OFF_ON,
};
-static struct gdsc gpu_gdsc = {
- .gdscr = 0x4034,
- .gds_hw_ctrl = 0x4038,
- .pd = {
- .name = "gpu",
- },
- .pwrsts = PWRSTS_OFF_ON,
- .flags = VOTABLE,
-};
-
static struct gdsc gpu_gx_gdsc = {
.gdscr = 0x4024,
.clamp_io_ctrl = 0x4300,
@@ -3076,6 +3066,17 @@ static struct gdsc gpu_gx_gdsc = {
.flags = CLAMP_IO,
};
+static struct gdsc gpu_gdsc = {
+ .gdscr = 0x4034,
+ .gds_hw_ctrl = 0x4038,
+ .pd = {
+ .name = "gpu",
+ },
+ .parent = &gpu_gx_gdsc.pd,
+ .pwrsts = PWRSTS_OFF_ON,
+ .flags = VOTABLE,
+};
+
static struct clk_regmap *mmcc_msm8996_clocks[] = {
[MMPLL0_EARLY] = &mmpll0_early.clkr,
[MMPLL0_PLL] = &mmpll0.clkr,
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index fe14c57de6ca..6fcbe4977f97 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -93,6 +93,9 @@ static const struct of_device_id whitelist[] __initconst = {
{ .compatible = "xlnx,zynq-7000", },
{ .compatible = "xlnx,zynqmp", },
+ { .compatible = "qcom,msm8996", },
+ { .compatible = "qcom,apq8096", },
+
{ }
};
@@ -116,6 +119,7 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "nvidia,tegra124", },
+ { .compatible = "qcom,apq8016", },
{ .compatible = "qcom,apq8096", },
{ .compatible = "qcom,msm8996", },
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 0a9ebf00be46..87e41e237743 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -32,6 +32,9 @@ struct private_data {
struct device *cpu_dev;
struct thermal_cooling_device *cdev;
const char *reg_name;
+ struct notifier_block opp_nb;
+ struct mutex lock;
+ unsigned long opp_freq;
};
static struct freq_attr *cpufreq_dt_attr[] = {
@@ -49,6 +52,9 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)
ret = dev_pm_opp_set_rate(priv->cpu_dev, freq * 1000);
if (!ret) {
+ mutex_lock(&priv->lock);
+ priv->opp_freq = freq * 1000;
+ mutex_unlock(&priv->lock);
arch_set_freq_scale(policy->related_cpus, freq,
policy->cpuinfo.max_freq);
}
@@ -94,6 +100,39 @@ node_put:
return name;
}
+static int opp_notifier(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct dev_pm_opp *opp = data;
+ struct private_data *priv = container_of(nb, struct private_data,
+ opp_nb);
+ struct device *cpu_dev = priv->cpu_dev;
+ struct regulator *cpu_reg;
+ unsigned long volt, freq;
+ int ret = 0;
+
+ if (event == OPP_EVENT_ADJUST_VOLTAGE) {
+ cpu_reg = dev_pm_opp_get_regulator(cpu_dev);
+ if (IS_ERR(cpu_reg)) {
+ ret = PTR_ERR(cpu_reg);
+ goto out;
+ }
+ volt = dev_pm_opp_get_voltage(opp);
+ freq = dev_pm_opp_get_freq(opp);
+
+ mutex_lock(&priv->lock);
+ if (freq == priv->opp_freq) {
+ ret = regulator_set_voltage_triplet(cpu_reg, volt, volt, volt);
+ }
+ mutex_unlock(&priv->lock);
+ if (ret)
+ dev_err(cpu_dev, "failed to scale voltage: %d\n", ret);
+ }
+
+out:
+ return notifier_from_errno(ret);
+}
+
static int resources_available(void)
{
struct device *cpu_dev;
@@ -246,13 +285,21 @@ static int cpufreq_init(struct cpufreq_policy *policy)
goto out_free_opp;
}
+ mutex_init(&priv->lock);
+
+ priv->opp_nb.notifier_call = opp_notifier;
+ ret = dev_pm_opp_register_notifier(cpu_dev, &priv->opp_nb);
+
+ if (ret)
+ goto out_free_priv;
+
priv->reg_name = name;
priv->opp_table = opp_table;
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) {
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
- goto out_free_priv;
+ goto out_unregister_nb;
}
priv->cpu_dev = cpu_dev;
@@ -282,6 +329,8 @@ static int cpufreq_init(struct cpufreq_policy *policy)
out_free_cpufreq_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_unregister_nb:
+ dev_pm_opp_unregister_notifier(cpu_dev, &priv->opp_nb);
out_free_priv:
kfree(priv);
out_free_opp:
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index e778af766fae..97ad56db5a5a 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -606,6 +606,9 @@ static const struct of_device_id qcom_scm_dt_match[] = {
{ .compatible = "qcom,scm-ipq4019",
.data = NULL, /* no clocks */
},
+ { .compatible = "qcom,scm-sdm845",
+ .data = NULL /* no clocks */
+ },
{ .compatible = "qcom,scm",
.data = (void *)(SCM_HAS_CORE_CLK
| SCM_HAS_IFACE_CLK
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index c79659ca5706..a12fe009f4eb 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -39,6 +39,8 @@ void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on)
}
} else {
ctrl = HDMI_CTRL_HDMI;
+ if (hdmi->config->keep_ctrl_on)
+ ctrl |= HDMI_CTRL_ENABLE;
}
hdmi_write(hdmi, REG_HDMI_CTRL, ctrl);
@@ -414,6 +416,7 @@ static struct hdmi_platform_config hdmi_tx_8996_config = {
HDMI_CFG(pwr_clk, 8x74),
HDMI_CFG(hpd_clk, 8x74),
.hpd_freq = hpd_clk_freq_8x74,
+ .keep_ctrl_on = true,
};
static const struct {
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index accc9a61611d..57795fc13468 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -121,6 +121,9 @@ struct hdmi_platform_config {
/* gpio's: */
struct hdmi_gpio_data gpios[HDMI_MAX_NUM_GPIO];
+
+ /* caps, etc. */
+ bool keep_ctrl_on;
};
void msm_hdmi_set_mode(struct hdmi *hdmi, bool power_on);
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index c0848dfedd50..ffe7e7218d39 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -223,6 +223,13 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
HDMI_HPD_CTRL_ENABLE | hpd_ctrl);
spin_unlock_irqrestore(&hdmi->reg_lock, flags);
+ /*
+ * wait for a bit so that HPD is sensed if there is a cable already
+ * connected. Returning early will result in someone calling the
+ * connnector func's detect() callback too early
+ */
+ msleep(15);
+
return 0;
fail:
@@ -465,8 +472,7 @@ struct drm_connector *msm_hdmi_connector_init(struct hdmi *hdmi)
DRM_MODE_CONNECTOR_HDMIA);
drm_connector_helper_add(connector, &msm_hdmi_connector_helper_funcs);
- connector->polled = DRM_CONNECTOR_POLL_CONNECT |
- DRM_CONNECTOR_POLL_DISCONNECT;
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 4f8df2ec87b1..d219b5abc926 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -828,6 +828,19 @@ config I2C_PXA_SLAVE
is necessary for systems where the PXA may be a target on the
I2C bus.
+config I2C_QCOM_GENI
+ tristate "Qualcomm Technologies Inc.'s GENI based I2C controller"
+ depends on ARCH_QCOM || COMPILE_TEST
+ depends on QCOM_GENI_SE
+ help
+ This driver supports GENI serial engine based I2C controller in
+ master mode on the Qualcomm Technologies Inc.'s SoCs. If you say
+ yes to this option, support will be included for the built-in I2C
+ interface on the Qualcomm Technologies Inc.'s SoCs.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-qcom-geni.
+
config I2C_QUP
tristate "Qualcomm QUP based I2C controller"
depends on ARCH_QCOM
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 5a869144a0c5..3e836cf434a2 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -83,6 +83,7 @@ obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o
+obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o
obj-$(CONFIG_I2C_QUP) += i2c-qup.o
obj-$(CONFIG_I2C_RIIC) += i2c-riic.o
obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
new file mode 100644
index 000000000000..32203744981d
--- /dev/null
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -0,0 +1,649 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/qcom-geni-se.h>
+#include <linux/spinlock.h>
+
+#define SE_I2C_TX_TRANS_LEN 0x26c
+#define SE_I2C_RX_TRANS_LEN 0x270
+#define SE_I2C_SCL_COUNTERS 0x278
+
+#define SE_I2C_ERR (M_CMD_OVERRUN_EN | M_ILLEGAL_CMD_EN | M_CMD_FAILURE_EN |\
+ M_GP_IRQ_1_EN | M_GP_IRQ_3_EN | M_GP_IRQ_4_EN)
+#define SE_I2C_ABORT BIT(1)
+
+/* M_CMD OP codes for I2C */
+#define I2C_WRITE 0x1
+#define I2C_READ 0x2
+#define I2C_WRITE_READ 0x3
+#define I2C_ADDR_ONLY 0x4
+#define I2C_BUS_CLEAR 0x6
+#define I2C_STOP_ON_BUS 0x7
+/* M_CMD params for I2C */
+#define PRE_CMD_DELAY BIT(0)
+#define TIMESTAMP_BEFORE BIT(1)
+#define STOP_STRETCH BIT(2)
+#define TIMESTAMP_AFTER BIT(3)
+#define POST_COMMAND_DELAY BIT(4)
+#define IGNORE_ADD_NACK BIT(6)
+#define READ_FINISHED_WITH_ACK BIT(7)
+#define BYPASS_ADDR_PHASE BIT(8)
+#define SLV_ADDR_MSK GENMASK(15, 9)
+#define SLV_ADDR_SHFT 9
+/* I2C SCL COUNTER fields */
+#define HIGH_COUNTER_MSK GENMASK(29, 20)
+#define HIGH_COUNTER_SHFT 20
+#define LOW_COUNTER_MSK GENMASK(19, 10)
+#define LOW_COUNTER_SHFT 10
+#define CYCLE_COUNTER_MSK GENMASK(9, 0)
+
+enum geni_i2c_err_code {
+ GP_IRQ0,
+ NACK,
+ GP_IRQ2,
+ BUS_PROTO,
+ ARB_LOST,
+ GP_IRQ5,
+ GENI_OVERRUN,
+ GENI_ILLEGAL_CMD,
+ GENI_ABORT_DONE,
+ GENI_TIMEOUT,
+};
+
+#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
+ << 5)
+
+#define I2C_AUTO_SUSPEND_DELAY 250
+#define KHZ(freq) (1000 * freq)
+#define PACKING_BYTES_PW 4
+
+#define ABORT_TIMEOUT HZ
+#define XFER_TIMEOUT HZ
+#define RST_TIMEOUT HZ
+
+struct geni_i2c_dev {
+ struct geni_se se;
+ u32 tx_wm;
+ int irq;
+ int err;
+ struct i2c_adapter adap;
+ struct completion done;
+ struct i2c_msg *cur;
+ int cur_wr;
+ int cur_rd;
+ spinlock_t lock;
+ u32 clk_freq_out;
+ const struct geni_i2c_clk_fld *clk_fld;
+};
+
+struct geni_i2c_err_log {
+ int err;
+ const char *msg;
+};
+
+static const struct geni_i2c_err_log gi2c_log[] = {
+ [GP_IRQ0] = {-EINVAL, "Unknown I2C err GP_IRQ0"},
+ [NACK] = {-ENOTCONN, "NACK: slv unresponsive, check its power/reset-ln"},
+ [GP_IRQ2] = {-EINVAL, "Unknown I2C err GP IRQ2"},
+ [BUS_PROTO] = {-EPROTO, "Bus proto err, noisy/unepxected start/stop"},
+ [ARB_LOST] = {-EBUSY, "Bus arbitration lost, clock line undriveable"},
+ [GP_IRQ5] = {-EINVAL, "Unknown I2C err GP IRQ5"},
+ [GENI_OVERRUN] = {-EIO, "Cmd overrun, check GENI cmd-state machine"},
+ [GENI_ILLEGAL_CMD] = {-EILSEQ, "Illegal cmd, check GENI cmd-state machine"},
+ [GENI_ABORT_DONE] = {-ETIMEDOUT, "Abort after timeout successful"},
+ [GENI_TIMEOUT] = {-ETIMEDOUT, "I2C TXN timed out"},
+};
+
+struct geni_i2c_clk_fld {
+ u32 clk_freq_out;
+ u8 clk_div;
+ u8 t_high_cnt;
+ u8 t_low_cnt;
+ u8 t_cycle_cnt;
+};
+
+/*
+ * Hardware uses the underlying formula to calculate time periods of
+ * SCL clock cycle. Firmware uses some additional cycles excluded from the
+ * below formula and it is confirmed that the time periods are within
+ * specification limits.
+ *
+ * time of high period of SCL: t_high = (t_high_cnt * clk_div) / source_clock
+ * time of low period of SCL: t_low = (t_low_cnt * clk_div) / source_clock
+ * time of full period of SCL: t_cycle = (t_cycle_cnt * clk_div) / source_clock
+ * clk_freq_out = t / t_cycle
+ * source_clock = 19.2 MHz
+ */
+static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = {
+ {KHZ(100), 7, 10, 11, 26},
+ {KHZ(400), 2, 5, 12, 24},
+ {KHZ(1000), 1, 3, 9, 18},
+};
+
+static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c)
+{
+ int i;
+ const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map;
+
+ for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) {
+ if (itr->clk_freq_out == gi2c->clk_freq_out) {
+ gi2c->clk_fld = itr;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static void qcom_geni_i2c_conf(struct geni_i2c_dev *gi2c)
+{
+ const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
+ u32 val;
+
+ writel_relaxed(0, gi2c->se.base + SE_GENI_CLK_SEL);
+
+ val = (itr->clk_div << CLK_DIV_SHFT) | SER_CLK_EN;
+ writel_relaxed(val, gi2c->se.base + GENI_SER_M_CLK_CFG);
+
+ val = itr->t_high_cnt << HIGH_COUNTER_SHFT;
+ val |= itr->t_low_cnt << LOW_COUNTER_SHFT;
+ val |= itr->t_cycle_cnt;
+ writel_relaxed(val, gi2c->se.base + SE_I2C_SCL_COUNTERS);
+}
+
+static void geni_i2c_err_misc(struct geni_i2c_dev *gi2c)
+{
+ u32 m_cmd = readl_relaxed(gi2c->se.base + SE_GENI_M_CMD0);
+ u32 m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
+ u32 geni_s = readl_relaxed(gi2c->se.base + SE_GENI_STATUS);
+ u32 geni_ios = readl_relaxed(gi2c->se.base + SE_GENI_IOS);
+ u32 dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN);
+ u32 rx_st, tx_st;
+
+ if (dma) {
+ rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
+ tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
+ } else {
+ rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS);
+ tx_st = readl_relaxed(gi2c->se.base + SE_GENI_TX_FIFO_STATUS);
+ }
+ dev_dbg(gi2c->se.dev, "DMA:%d tx_stat:0x%x, rx_stat:0x%x, irq-stat:0x%x\n",
+ dma, tx_st, rx_st, m_stat);
+ dev_dbg(gi2c->se.dev, "m_cmd:0x%x, geni_status:0x%x, geni_ios:0x%x\n",
+ m_cmd, geni_s, geni_ios);
+}
+
+static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
+{
+ if (!gi2c->err)
+ gi2c->err = gi2c_log[err].err;
+ if (gi2c->cur)
+ dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n",
+ gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags);
+
+ if (err != NACK && err != GENI_ABORT_DONE) {
+ dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
+ geni_i2c_err_misc(gi2c);
+ }
+}
+
+static irqreturn_t geni_i2c_irq(int irq, void *dev)
+{
+ struct geni_i2c_dev *gi2c = dev;
+ int j;
+ u32 m_stat;
+ u32 rx_st;
+ u32 dm_tx_st;
+ u32 dm_rx_st;
+ u32 dma;
+ struct i2c_msg *cur;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gi2c->lock, flags);
+ m_stat = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
+ rx_st = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFO_STATUS);
+ dm_tx_st = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
+ dm_rx_st = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
+ dma = readl_relaxed(gi2c->se.base + SE_GENI_DMA_MODE_EN);
+ cur = gi2c->cur;
+
+ if (!cur ||
+ m_stat & (M_CMD_FAILURE_EN | M_CMD_ABORT_EN) ||
+ dm_rx_st & (DM_I2C_CB_ERR)) {
+ if (m_stat & M_GP_IRQ_1_EN)
+ geni_i2c_err(gi2c, NACK);
+ if (m_stat & M_GP_IRQ_3_EN)
+ geni_i2c_err(gi2c, BUS_PROTO);
+ if (m_stat & M_GP_IRQ_4_EN)
+ geni_i2c_err(gi2c, ARB_LOST);
+ if (m_stat & M_CMD_OVERRUN_EN)
+ geni_i2c_err(gi2c, GENI_OVERRUN);
+ if (m_stat & M_ILLEGAL_CMD_EN)
+ geni_i2c_err(gi2c, GENI_ILLEGAL_CMD);
+ if (m_stat & M_CMD_ABORT_EN)
+ geni_i2c_err(gi2c, GENI_ABORT_DONE);
+ if (m_stat & M_GP_IRQ_0_EN)
+ geni_i2c_err(gi2c, GP_IRQ0);
+
+ /* Disable the TX Watermark interrupt to stop TX */
+ if (!dma)
+ writel_relaxed(0, gi2c->se.base +
+ SE_GENI_TX_WATERMARK_REG);
+ goto irqret;
+ }
+
+ if (dma) {
+ dev_dbg(gi2c->se.dev, "i2c dma tx:0x%x, dma rx:0x%x\n",
+ dm_tx_st, dm_rx_st);
+ goto irqret;
+ }
+
+ if (cur->flags & I2C_M_RD &&
+ m_stat & (M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN)) {
+ u32 rxcnt = rx_st & RX_FIFO_WC_MSK;
+
+ for (j = 0; j < rxcnt; j++) {
+ u32 val;
+ int p = 0;
+
+ val = readl_relaxed(gi2c->se.base + SE_GENI_RX_FIFOn);
+ while (gi2c->cur_rd < cur->len && p < sizeof(val)) {
+ cur->buf[gi2c->cur_rd++] = val & 0xff;
+ val >>= 8;
+ p++;
+ }
+ if (gi2c->cur_rd == cur->len)
+ break;
+ }
+ } else if (!(cur->flags & I2C_M_RD) &&
+ m_stat & M_TX_FIFO_WATERMARK_EN) {
+ for (j = 0; j < gi2c->tx_wm; j++) {
+ u32 temp;
+ u32 val = 0;
+ int p = 0;
+
+ while (gi2c->cur_wr < cur->len && p < sizeof(val)) {
+ temp = cur->buf[gi2c->cur_wr++];
+ val |= temp << (p * 8);
+ p++;
+ }
+ writel_relaxed(val, gi2c->se.base + SE_GENI_TX_FIFOn);
+ /* TX Complete, Disable the TX Watermark interrupt */
+ if (gi2c->cur_wr == cur->len) {
+ writel_relaxed(0, gi2c->se.base +
+ SE_GENI_TX_WATERMARK_REG);
+ break;
+ }
+ }
+ }
+irqret:
+ if (m_stat)
+ writel_relaxed(m_stat, gi2c->se.base + SE_GENI_M_IRQ_CLEAR);
+
+ if (dma) {
+ if (dm_tx_st)
+ writel_relaxed(dm_tx_st, gi2c->se.base +
+ SE_DMA_TX_IRQ_CLR);
+ if (dm_rx_st)
+ writel_relaxed(dm_rx_st, gi2c->se.base +
+ SE_DMA_RX_IRQ_CLR);
+ }
+ /* if this is err with done-bit not set, handle that through timeout. */
+ if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN)
+ complete(&gi2c->done);
+ else if (dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE)
+ complete(&gi2c->done);
+ else if (dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
+ complete(&gi2c->done);
+
+ spin_unlock_irqrestore(&gi2c->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
+{
+ u32 val;
+ unsigned long time_left = ABORT_TIMEOUT;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gi2c->lock, flags);
+ geni_i2c_err(gi2c, GENI_TIMEOUT);
+ gi2c->cur = NULL;
+ geni_se_abort_m_cmd(&gi2c->se);
+ spin_unlock_irqrestore(&gi2c->lock, flags);
+ do {
+ time_left = wait_for_completion_timeout(&gi2c->done, time_left);
+ val = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS);
+ } while (!(val & M_CMD_ABORT_EN) && time_left);
+
+ if (!(val & M_CMD_ABORT_EN))
+ dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n");
+}
+
+static void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c)
+{
+ u32 val;
+ unsigned long time_left = RST_TIMEOUT;
+
+ writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST);
+ do {
+ time_left = wait_for_completion_timeout(&gi2c->done, time_left);
+ val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
+ } while (!(val & RX_RESET_DONE) && time_left);
+
+ if (!(val & RX_RESET_DONE))
+ dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n");
+}
+
+static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c)
+{
+ u32 val;
+ unsigned long time_left = RST_TIMEOUT;
+
+ writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST);
+ do {
+ time_left = wait_for_completion_timeout(&gi2c->done, time_left);
+ val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
+ } while (!(val & TX_RESET_DONE) && time_left);
+
+ if (!(val & TX_RESET_DONE))
+ dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
+}
+
+static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
+ u32 m_param)
+{
+ dma_addr_t rx_dma;
+ enum geni_se_xfer_mode mode;
+ unsigned long time_left = XFER_TIMEOUT;
+
+ gi2c->cur = msg;
+ mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO;
+ geni_se_select_mode(&gi2c->se, mode);
+ writel_relaxed(msg->len, gi2c->se.base + SE_I2C_RX_TRANS_LEN);
+ geni_se_setup_m_cmd(&gi2c->se, I2C_READ, m_param);
+ if (mode == GENI_SE_DMA) {
+ int ret;
+
+ ret = geni_se_rx_dma_prep(&gi2c->se, msg->buf, msg->len,
+ &rx_dma);
+ if (!ret) {
+ mode = GENI_SE_FIFO;
+ geni_se_select_mode(&gi2c->se, mode);
+ }
+ }
+
+ time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
+ if (!time_left)
+ geni_i2c_abort_xfer(gi2c);
+
+ gi2c->cur_rd = 0;
+ if (mode == GENI_SE_DMA) {
+ if (gi2c->err)
+ geni_i2c_rx_fsm_rst(gi2c);
+ geni_se_rx_dma_unprep(&gi2c->se, rx_dma, msg->len);
+ }
+ return gi2c->err;
+}
+
+static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
+ u32 m_param)
+{
+ dma_addr_t tx_dma;
+ enum geni_se_xfer_mode mode;
+ unsigned long time_left;
+
+ gi2c->cur = msg;
+ mode = msg->len > 32 ? GENI_SE_DMA : GENI_SE_FIFO;
+ geni_se_select_mode(&gi2c->se, mode);
+ writel_relaxed(msg->len, gi2c->se.base + SE_I2C_TX_TRANS_LEN);
+ geni_se_setup_m_cmd(&gi2c->se, I2C_WRITE, m_param);
+ if (mode == GENI_SE_DMA) {
+ int ret;
+
+ ret = geni_se_tx_dma_prep(&gi2c->se, msg->buf, msg->len,
+ &tx_dma);
+ if (!ret) {
+ mode = GENI_SE_FIFO;
+ geni_se_select_mode(&gi2c->se, mode);
+ }
+ }
+
+ if (mode == GENI_SE_FIFO) /* Get FIFO IRQ */
+ writel_relaxed(1, gi2c->se.base + SE_GENI_TX_WATERMARK_REG);
+
+ time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
+ if (!time_left)
+ geni_i2c_abort_xfer(gi2c);
+
+ gi2c->cur_wr = 0;
+ if (mode == GENI_SE_DMA) {
+ if (gi2c->err)
+ geni_i2c_tx_fsm_rst(gi2c);
+ geni_se_tx_dma_unprep(&gi2c->se, tx_dma, msg->len);
+ }
+ return gi2c->err;
+}
+
+static int geni_i2c_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
+ int i, ret;
+
+ gi2c->err = 0;
+ reinit_completion(&gi2c->done);
+ ret = pm_runtime_get_sync(gi2c->se.dev);
+ if (ret < 0) {
+ dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
+ pm_runtime_put_noidle(gi2c->se.dev);
+ /* Set device in suspended since resume failed */
+ pm_runtime_set_suspended(gi2c->se.dev);
+ return ret;
+ }
+
+ qcom_geni_i2c_conf(gi2c);
+ for (i = 0; i < num; i++) {
+ u32 m_param = i < (num - 1) ? STOP_STRETCH : 0;
+
+ m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
+
+ if (msgs[i].flags & I2C_M_RD)
+ ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
+ else
+ ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param);
+
+ if (ret)
+ break;
+ }
+ if (ret == 0)
+ ret = num;
+
+ pm_runtime_mark_last_busy(gi2c->se.dev);
+ pm_runtime_put_autosuspend(gi2c->se.dev);
+ gi2c->cur = NULL;
+ gi2c->err = 0;
+ return ret;
+}
+
+static u32 geni_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm geni_i2c_algo = {
+ .master_xfer = geni_i2c_xfer,
+ .functionality = geni_i2c_func,
+};
+
+static int geni_i2c_probe(struct platform_device *pdev)
+{
+ struct geni_i2c_dev *gi2c;
+ struct resource *res;
+ u32 proto, tx_depth;
+ int ret;
+
+ gi2c = devm_kzalloc(&pdev->dev, sizeof(*gi2c), GFP_KERNEL);
+ if (!gi2c)
+ return -ENOMEM;
+
+ gi2c->se.dev = &pdev->dev;
+ gi2c->se.wrapper = dev_get_drvdata(pdev->dev.parent);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gi2c->se.base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gi2c->se.base))
+ return PTR_ERR(gi2c->se.base);
+
+ gi2c->se.clk = devm_clk_get(&pdev->dev, "se");
+ if (IS_ERR(gi2c->se.clk)) {
+ ret = PTR_ERR(gi2c->se.clk);
+ dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
+ return ret;
+ }
+
+ ret = device_property_read_u32(&pdev->dev, "clock-frequency",
+ &gi2c->clk_freq_out);
+ if (ret) {
+ dev_info(&pdev->dev,
+ "Bus frequency not specified, default to 100kHz.\n");
+ gi2c->clk_freq_out = KHZ(100);
+ }
+
+ gi2c->irq = platform_get_irq(pdev, 0);
+ if (gi2c->irq < 0) {
+ dev_err(&pdev->dev, "IRQ error for i2c-geni\n");
+ return gi2c->irq;
+ }
+
+ ret = geni_i2c_clk_map_idx(gi2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Invalid clk frequency %d Hz: %d\n",
+ gi2c->clk_freq_out, ret);
+ return ret;
+ }
+
+ gi2c->adap.algo = &geni_i2c_algo;
+ init_completion(&gi2c->done);
+ spin_lock_init(&gi2c->lock);
+ platform_set_drvdata(pdev, gi2c);
+ ret = devm_request_irq(&pdev->dev, gi2c->irq, geni_i2c_irq,
+ IRQF_TRIGGER_HIGH, "i2c_geni", gi2c);
+ if (ret) {
+ dev_err(&pdev->dev, "Request_irq failed:%d: err:%d\n",
+ gi2c->irq, ret);
+ return ret;
+ }
+ /* Disable the interrupt so that the system can enter low-power mode */
+ disable_irq(gi2c->irq);
+ i2c_set_adapdata(&gi2c->adap, gi2c);
+ gi2c->adap.dev.parent = &pdev->dev;
+ gi2c->adap.dev.of_node = pdev->dev.of_node;
+ strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name));
+
+ ret = geni_se_resources_on(&gi2c->se);
+ if (ret) {
+ dev_err(&pdev->dev, "Error turning on resources %d\n", ret);
+ return ret;
+ }
+ proto = geni_se_read_proto(&gi2c->se);
+ tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se);
+ if (proto != GENI_SE_I2C) {
+ dev_err(&pdev->dev, "Invalid proto %d\n", proto);
+ geni_se_resources_off(&gi2c->se);
+ return -ENXIO;
+ }
+ gi2c->tx_wm = tx_depth - 1;
+ geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth);
+ geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, PACKING_BYTES_PW,
+ true, true, true);
+ geni_se_resources_off(&gi2c->se);
+ dev_dbg(&pdev->dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth);
+
+ pm_runtime_set_suspended(gi2c->se.dev);
+ pm_runtime_set_autosuspend_delay(gi2c->se.dev, I2C_AUTO_SUSPEND_DELAY);
+ pm_runtime_use_autosuspend(gi2c->se.dev);
+ pm_runtime_enable(gi2c->se.dev);
+ i2c_add_adapter(&gi2c->adap);
+
+ return 0;
+}
+
+static int geni_i2c_remove(struct platform_device *pdev)
+{
+ struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(gi2c->se.dev);
+ i2c_del_adapter(&gi2c->adap);
+ return 0;
+}
+
+static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
+{
+ struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
+
+ disable_irq(gi2c->irq);
+ geni_se_resources_off(&gi2c->se);
+ return 0;
+}
+
+static int __maybe_unused geni_i2c_runtime_resume(struct device *dev)
+{
+ int ret;
+ struct geni_i2c_dev *gi2c = dev_get_drvdata(dev);
+
+ ret = geni_se_resources_on(&gi2c->se);
+ if (ret)
+ return ret;
+
+ enable_irq(gi2c->irq);
+ return 0;
+}
+
+static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev)
+{
+ if (!pm_runtime_suspended(dev)) {
+ geni_i2c_runtime_suspend(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+ }
+ return 0;
+}
+
+static const struct dev_pm_ops geni_i2c_pm_ops = {
+ SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(geni_i2c_suspend_noirq, NULL)
+ SET_RUNTIME_PM_OPS(geni_i2c_runtime_suspend, geni_i2c_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id geni_i2c_dt_match[] = {
+ { .compatible = "qcom,geni-i2c" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
+
+static struct platform_driver geni_i2c_driver = {
+ .probe = geni_i2c_probe,
+ .remove = geni_i2c_remove,
+ .driver = {
+ .name = "geni_i2c",
+ .pm = &geni_i2c_pm_ops,
+ .of_match_table = geni_i2c_dt_match,
+ },
+};
+
+module_platform_driver(geni_i2c_driver);
+
+MODULE_DESCRIPTION("I2C Controller Driver for GENI based QUP cores");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c
index 18ad956454f1..fa21c4d67678 100644
--- a/drivers/input/misc/pm8941-pwrkey.c
+++ b/drivers/input/misc/pm8941-pwrkey.c
@@ -28,6 +28,7 @@
#define PON_RT_STS 0x10
#define PON_KPDPWR_N_SET BIT(0)
+#define PON_RESIN_N_SET BIT(1)
#define PON_PS_HOLD_RST_CTL 0x5a
#define PON_PS_HOLD_RST_CTL2 0x5b
@@ -37,6 +38,7 @@
#define PON_PS_HOLD_TYPE_HARD_RESET 7
#define PON_PULL_CTL 0x70
+#define PON_RESIN_PULL_UP BIT(0)
#define PON_KPDPWR_PULL_UP BIT(1)
#define PON_DBC_CTL 0x71
@@ -52,6 +54,7 @@ struct pm8941_pwrkey {
unsigned int revision;
struct notifier_block reboot_notifier;
+ unsigned int resin_code;
};
static int pm8941_reboot_notify(struct notifier_block *nb,
@@ -130,6 +133,25 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
return IRQ_HANDLED;
}
+static irqreturn_t pm8941_resin_irq(int irq, void *_data)
+{
+ struct pm8941_pwrkey *pwrkey = _data;
+ unsigned int sts;
+ int error;
+
+ error = regmap_read(pwrkey->regmap,
+ pwrkey->baseaddr + PON_RT_STS, &sts);
+ if (error)
+ return IRQ_HANDLED;
+
+ input_report_key(pwrkey->input, pwrkey->resin_code,
+ !!(sts & PON_RESIN_N_SET));
+
+ input_sync(pwrkey->input);
+
+ return IRQ_HANDLED;
+}
+
static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -153,6 +175,46 @@ static int __maybe_unused pm8941_pwrkey_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
pm8941_pwrkey_suspend, pm8941_pwrkey_resume);
+static void pm8941_resin_setup(struct platform_device *pdev,
+ struct pm8941_pwrkey *pwrkey)
+{
+ int irq, error;
+ bool pull_up;
+ u32 code;
+
+ irq = platform_get_irq(pdev, 1);
+ if (irq < 0)
+ return;
+
+ pull_up = of_property_read_bool(pdev->dev.of_node, "resin-pull-up");
+
+ error = regmap_update_bits(pwrkey->regmap,
+ pwrkey->baseaddr + PON_PULL_CTL,
+ PON_RESIN_PULL_UP,
+ pull_up ? PON_RESIN_PULL_UP : 0);
+ if (error) {
+ dev_err(&pdev->dev, "failed to set pull: %d\n", error);
+ return;
+ }
+
+ error = of_property_read_u32(pdev->dev.of_node, "linux,code", &code);
+ if (error) {
+ dev_err(&pdev->dev, "resin no linux,code %d\n", error);
+ return;
+ }
+
+ pwrkey->resin_code = code;
+
+ input_set_capability(pwrkey->input, EV_KEY, code);
+
+ error = devm_request_threaded_irq(&pdev->dev, irq,
+ NULL, pm8941_resin_irq,
+ IRQF_ONESHOT,
+ "pm8941_resin", pwrkey);
+ if (error)
+ dev_err(&pdev->dev, "failed requesting IRQ: %d\n", error);
+}
+
static int pm8941_pwrkey_probe(struct platform_device *pdev)
{
struct pm8941_pwrkey *pwrkey;
@@ -241,6 +303,8 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
return error;
}
+ pm8941_resin_setup(pdev, pwrkey);
+
error = input_register_device(pwrkey->input);
if (error) {
dev_err(&pdev->dev, "failed to register input device: %d\n",
diff --git a/drivers/interconnect/Kconfig b/drivers/interconnect/Kconfig
new file mode 100644
index 000000000000..07a8276fa35a
--- /dev/null
+++ b/drivers/interconnect/Kconfig
@@ -0,0 +1,15 @@
+menuconfig INTERCONNECT
+ tristate "On-Chip Interconnect management support"
+ help
+ Support for management of the on-chip interconnects.
+
+ This framework is designed to provide a generic interface for
+ managing the interconnects in a SoC.
+
+ If unsure, say no.
+
+if INTERCONNECT
+
+source "drivers/interconnect/qcom/Kconfig"
+
+endif
diff --git a/drivers/interconnect/Makefile b/drivers/interconnect/Makefile
new file mode 100644
index 000000000000..7944cbca0527
--- /dev/null
+++ b/drivers/interconnect/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_INTERCONNECT) += core.o
+obj-$(CONFIG_INTERCONNECT_QCOM) += qcom/
diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
new file mode 100644
index 000000000000..5817f081f6cf
--- /dev/null
+++ b/drivers/interconnect/core.c
@@ -0,0 +1,737 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interconnect framework core driver
+ *
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/interconnect.h>
+#include <linux/interconnect-provider.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/uaccess.h>
+
+static DEFINE_IDR(icc_idr);
+static LIST_HEAD(icc_provider_list);
+static DEFINE_MUTEX(icc_lock);
+static struct dentry *icc_debugfs_dir;
+
+/**
+ * struct icc_req - constraints that are attached to each node
+ *
+ * @req_node: entry in list of requests for the particular @node
+ * @node: the interconnect node to which this constraint applies
+ * @dev: reference to the device that sets the constraints
+ * @avg_bw: an integer describing the average bandwidth in kbps
+ * @peak_bw: an integer describing the peak bandwidth in kbps
+ */
+struct icc_req {
+ struct hlist_node req_node;
+ struct icc_node *node;
+ struct device *dev;
+ u32 avg_bw;
+ u32 peak_bw;
+};
+
+/**
+ * struct icc_path - interconnect path structure
+ * @num_nodes: number of hops (nodes)
+ * @reqs: array of the requests applicable to this path of nodes
+ */
+struct icc_path {
+ size_t num_nodes;
+ struct icc_req reqs[];
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static void icc_summary_show_one(struct seq_file *s, struct icc_node *n)
+{
+ if (!n)
+ return;
+
+ seq_printf(s, "%-30s %12d %12d\n",
+ n->name, n->avg_bw, n->peak_bw);
+}
+
+static int icc_summary_show(struct seq_file *s, void *data)
+{
+ struct icc_provider *provider;
+
+ seq_puts(s, " node avg peak\n");
+ seq_puts(s, "--------------------------------------------------------\n");
+
+ mutex_lock(&icc_lock);
+
+ list_for_each_entry(provider, &icc_provider_list, provider_list) {
+ struct icc_node *n;
+
+ list_for_each_entry(n, &provider->nodes, node_list) {
+ struct icc_req *r;
+
+ icc_summary_show_one(s, n);
+ hlist_for_each_entry(r, &n->req_list, req_node) {
+ if (!r->dev)
+ continue;
+
+ seq_printf(s, " %-26s %12d %12d\n",
+ dev_name(r->dev), r->avg_bw,
+ r->peak_bw);
+ }
+ }
+ }
+
+ mutex_unlock(&icc_lock);
+
+ return 0;
+}
+
+static int icc_summary_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, icc_summary_show, inode->i_private);
+}
+
+static const struct file_operations icc_summary_fops = {
+ .open = icc_summary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init icc_debugfs_init(void)
+{
+ struct dentry *file;
+
+ icc_debugfs_dir = debugfs_create_dir("interconnect", NULL);
+ if (!icc_debugfs_dir) {
+ pr_err("interconnect: error creating debugfs directory\n");
+ return -ENODEV;
+ }
+
+ file = debugfs_create_file("interconnect_summary", 0444,
+ icc_debugfs_dir, NULL, &icc_summary_fops);
+ if (!file)
+ return -ENODEV;
+
+ return 0;
+}
+late_initcall(icc_debugfs_init);
+#endif
+
+static struct icc_node *node_find(const int id)
+{
+ return idr_find(&icc_idr, id);
+}
+
+static struct icc_path *path_init(struct device *dev, struct icc_node *dst,
+ ssize_t num_nodes)
+{
+ struct icc_node *node = dst;
+ struct icc_path *path;
+ size_t i;
+
+ path = kzalloc(struct_size(path, reqs, num_nodes), GFP_KERNEL);
+ if (!path)
+ return ERR_PTR(-ENOMEM);
+
+ path->num_nodes = num_nodes;
+
+ for (i = 0; i < num_nodes; i++) {
+ hlist_add_head(&path->reqs[i].req_node, &node->req_list);
+
+ path->reqs[i].node = node;
+ path->reqs[i].dev = dev;
+ /* reference to previous node was saved during path traversal */
+ node = node->reverse;
+ }
+
+ return path;
+}
+
+static struct icc_path *path_find(struct device *dev, struct icc_node *src,
+ struct icc_node *dst)
+{
+ struct icc_node *n, *node = NULL;
+ struct icc_provider *provider;
+ struct list_head traverse_list;
+ struct list_head edge_list;
+ struct list_head visited_list;
+ size_t i, depth = 1;
+ bool found = false;
+ int ret = -EPROBE_DEFER;
+
+ INIT_LIST_HEAD(&traverse_list);
+ INIT_LIST_HEAD(&edge_list);
+ INIT_LIST_HEAD(&visited_list);
+
+ list_add_tail(&src->search_list, &traverse_list);
+ src->reverse = NULL;
+
+ do {
+ list_for_each_entry_safe(node, n, &traverse_list, search_list) {
+ if (node == dst) {
+ found = true;
+ list_add(&node->search_list, &visited_list);
+ break;
+ }
+ for (i = 0; i < node->num_links; i++) {
+ struct icc_node *tmp = node->links[i];
+
+ if (!tmp) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (tmp->is_traversed)
+ continue;
+
+ tmp->is_traversed = true;
+ tmp->reverse = node;
+ list_add(&tmp->search_list, &edge_list);
+ }
+ }
+ if (found)
+ break;
+
+ list_splice_init(&traverse_list, &visited_list);
+ list_splice_init(&edge_list, &traverse_list);
+
+ /* count the hops including the source */
+ depth++;
+
+ } while (!list_empty(&traverse_list));
+
+out:
+ /* reset the traversed state */
+ list_for_each_entry(provider, &icc_provider_list, provider_list)
+ list_for_each_entry(n, &provider->nodes, node_list)
+ n->is_traversed = false;
+
+ if (found) {
+ struct icc_path *path = path_init(dev, dst, depth);
+
+ if (IS_ERR(path))
+ return path;
+
+ for (i = 0; i < path->num_nodes; i++) {
+ node = path->reqs[i].node;
+ node->provider->users++;
+ }
+ return path;
+ }
+
+ return ERR_PTR(ret);
+}
+
+/*
+ * We want the path to honor all bandwidth requests, so the average
+ * bandwidth requirements from each consumer are aggregated at each node
+ * and provider level. By default the average bandwidth is the sum of all
+ * averages and the peak will be the highest of all peak bandwidth requests.
+ */
+
+static int aggregate_requests(struct icc_node *node)
+{
+ struct icc_provider *p = node->provider;
+ struct icc_req *r;
+
+ node->avg_bw = 0;
+ node->peak_bw = 0;
+
+ hlist_for_each_entry(r, &node->req_list, req_node)
+ p->aggregate(node, r->avg_bw, r->peak_bw,
+ &node->avg_bw, &node->peak_bw);
+
+ return 0;
+}
+
+static void aggregate_provider(struct icc_provider *p)
+{
+ struct icc_node *n;
+
+ p->avg_bw = 0;
+ p->peak_bw = 0;
+
+ list_for_each_entry(n, &p->nodes, node_list)
+ p->aggregate(n, n->avg_bw, n->peak_bw,
+ &p->avg_bw, &p->peak_bw);
+}
+
+static int apply_constraints(struct icc_path *path)
+{
+ struct icc_node *next, *prev = NULL;
+ int ret;
+ int i;
+
+ for (i = 0; i < path->num_nodes; i++, prev = next) {
+ struct icc_provider *p;
+
+ next = path->reqs[i].node;
+ /*
+ * Both endpoints should be valid master-slave pairs of the
+ * same interconnect provider that will be configured.
+ */
+ if (!prev || next->provider != prev->provider)
+ continue;
+
+ p = next->provider;
+
+ aggregate_provider(p);
+
+ /* set the constraints */
+ ret = p->set(prev, next, p->avg_bw, p->peak_bw);
+ if (ret)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+struct icc_path *of_icc_get(struct device *dev, const char *name)
+{
+ struct device_node *np = NULL;
+ struct of_phandle_args src_args, dst_args;
+ u32 src_id, dst_id;
+ int idx = 0;
+ int ret;
+
+ if (!dev || !dev->of_node)
+ return ERR_PTR(-ENODEV);
+
+ np = dev->of_node;
+
+ /*
+ * When the consumer DT node do not have "interconnects" property
+ * return a NULL path to skip setting constraints.
+ */
+ if (!of_find_property(np, "interconnects", NULL))
+ return NULL;
+
+ /*
+ * We use a combination of phandle and specifier for endpoint. For now
+ * lets support only global ids and extend this is the future if needed
+ * without breaking DT compatibility.
+ */
+ if (name) {
+ idx = of_property_match_string(np, "interconnect-names", name);
+ if (idx < 0)
+ return ERR_PTR(idx);
+ }
+
+ ret = of_parse_phandle_with_args(np, "interconnects",
+ "#interconnect-cells", idx * 2,
+ &src_args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ of_node_put(src_args.np);
+
+ if (!src_args.args_count || src_args.args_count > 1)
+ return ERR_PTR(-EINVAL);
+
+ src_id = src_args.args[0];
+
+ ret = of_parse_phandle_with_args(np, "interconnects",
+ "#interconnect-cells", idx * 2 + 1,
+ &dst_args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ of_node_put(dst_args.np);
+
+ if (!dst_args.args_count || dst_args.args_count > 1)
+ return ERR_PTR(-EINVAL);
+
+ dst_id = dst_args.args[0];
+
+ return icc_get(dev, src_id, dst_id);
+}
+EXPORT_SYMBOL_GPL(of_icc_get);
+
+/**
+ * icc_set() - set constraints on an interconnect path between two endpoints
+ * @path: reference to the path returned by icc_get()
+ * @avg_bw: average bandwidth in kbps
+ * @peak_bw: peak bandwidth in kbps
+ *
+ * This function is used by an interconnect consumer to express its own needs
+ * in terms of bandwidth for a previously requested path between two endpoints.
+ * The requests are aggregated and each node is updated accordingly. The entire
+ * path is locked by a mutex to ensure that the set() is completed.
+ * The @path can be NULL when the "interconnects" DT properties is missing,
+ * which will mean that no constraints will be set.
+ *
+ * Returns 0 on success, or an appropriate error code otherwise.
+ */
+int icc_set(struct icc_path *path, u32 avg_bw, u32 peak_bw)
+{
+ struct icc_node *node;
+ struct icc_provider *p;
+ size_t i;
+ int ret;
+
+ if (!path)
+ return 0;
+
+ mutex_lock(&icc_lock);
+
+ for (i = 0; i < path->num_nodes; i++) {
+ node = path->reqs[i].node;
+ p = node->provider;
+
+ /* update the consumer request for this path */
+ path->reqs[i].avg_bw = avg_bw;
+ path->reqs[i].peak_bw = peak_bw;
+
+ /* aggregate requests for this node */
+ aggregate_requests(node);
+ }
+
+ ret = apply_constraints(path);
+ if (ret)
+ pr_err("interconnect: error applying constraints (%d)", ret);
+
+ mutex_unlock(&icc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(icc_set);
+
+/**
+ * icc_get() - return a handle for path between two endpoints
+ * @dev: the device requesting the path
+ * @src_id: source device port id
+ * @dst_id: destination device port id
+ *
+ * This function will search for a path between two endpoints and return an
+ * icc_path handle on success. Use icc_put() to release
+ * constraints when the they are not needed anymore.
+ *
+ * Return: icc_path pointer on success, or ERR_PTR() on error
+ */
+struct icc_path *icc_get(struct device *dev, const int src_id, const int dst_id)
+{
+ struct icc_node *src, *dst;
+ struct icc_path *path = ERR_PTR(-EPROBE_DEFER);
+
+ mutex_lock(&icc_lock);
+
+ src = node_find(src_id);
+ if (!src)
+ goto out;
+
+ dst = node_find(dst_id);
+ if (!dst)
+ goto out;
+
+ path = path_find(dev, src, dst);
+ if (IS_ERR(path))
+ dev_err(dev, "%s: invalid path=%ld\n", __func__, PTR_ERR(path));
+
+out:
+ mutex_unlock(&icc_lock);
+ return path;
+}
+EXPORT_SYMBOL_GPL(icc_get);
+
+/**
+ * icc_put() - release the reference to the icc_path
+ * @path: interconnect path
+ *
+ * Use this function to release the constraints on a path when the path is
+ * no longer needed. The constraints will be re-aggregated.
+ */
+void icc_put(struct icc_path *path)
+{
+ struct icc_node *node;
+ size_t i;
+ int ret;
+
+ if (!path || WARN_ON(IS_ERR(path)))
+ return;
+
+ ret = icc_set(path, 0, 0);
+ if (ret)
+ pr_err("%s: error (%d)\n", __func__, ret);
+
+ mutex_lock(&icc_lock);
+ for (i = 0; i < path->num_nodes; i++) {
+ node = path->reqs[i].node;
+ hlist_del(&path->reqs[i].req_node);
+
+ node->provider->users--;
+ }
+ mutex_unlock(&icc_lock);
+
+ kfree(path);
+}
+EXPORT_SYMBOL_GPL(icc_put);
+
+static struct icc_node *icc_node_create_nolock(int id)
+{
+ struct icc_node *node;
+
+ /* check if node already exists */
+ node = node_find(id);
+ if (node)
+ goto out;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ node = ERR_PTR(-ENOMEM);
+ goto out;
+ }
+
+ id = idr_alloc(&icc_idr, node, id, id + 1, GFP_KERNEL);
+ if (WARN(id < 0, "couldn't get idr")) {
+ kfree(node);
+ node = ERR_PTR(id);
+ goto out;
+ }
+
+ node->id = id;
+
+out:
+ return node;
+}
+
+/**
+ * icc_node_create() - create a node
+ * @id: node id
+ *
+ * Return: icc_node pointer on success, or ERR_PTR() on error
+ */
+struct icc_node *icc_node_create(int id)
+{
+ struct icc_node *node;
+
+ mutex_lock(&icc_lock);
+
+ node = icc_node_create_nolock(id);
+
+ mutex_unlock(&icc_lock);
+
+ return node;
+}
+EXPORT_SYMBOL_GPL(icc_node_create);
+
+/**
+ * icc_node_destroy() - destroy a node
+ * @id: node id
+ *
+ */
+void icc_node_destroy(int id)
+{
+ struct icc_node *node;
+
+ node = node_find(id);
+ if (node) {
+ mutex_lock(&icc_lock);
+ idr_remove(&icc_idr, node->id);
+ WARN_ON(!hlist_empty(&node->req_list));
+ mutex_unlock(&icc_lock);
+ }
+
+ kfree(node);
+}
+EXPORT_SYMBOL_GPL(icc_node_destroy);
+
+/**
+ * icc_link_create() - create a link between two nodes
+ * @src_id: source node id
+ * @dst_id: destination node id
+ *
+ * Create a link between two nodes. The nodes might belong to different
+ * interconnect providers and the @dst_id node might not exist (if the
+ * provider driver has not probed yet). So just create the @dst_id node
+ * and when the actual provider driver is probed, the rest of the node
+ * data is filled.
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_link_create(struct icc_node *node, const int dst_id)
+{
+ struct icc_node *dst;
+ struct icc_node **new;
+ int ret = 0;
+
+ if (!node->provider)
+ return -EINVAL;
+
+ mutex_lock(&icc_lock);
+
+ dst = node_find(dst_id);
+ if (!dst) {
+ dst = icc_node_create_nolock(dst_id);
+
+ if (IS_ERR(dst)) {
+ ret = PTR_ERR(dst);
+ goto out;
+ }
+ }
+
+ new = krealloc(node->links,
+ (node->num_links + 1) * sizeof(*node->links),
+ GFP_KERNEL);
+ if (!new) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ node->links = new;
+ node->links[node->num_links++] = dst;
+
+out:
+ mutex_unlock(&icc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(icc_link_create);
+
+/**
+ * icc_link_destroy() - destroy a link between two nodes
+ * @src: pointer to source node
+ * @dst: pointer to destination node
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_link_destroy(struct icc_node *src, struct icc_node *dst)
+{
+ struct icc_node **new;
+ struct icc_node *last;
+ int ret = 0;
+ size_t slot;
+
+ if (IS_ERR_OR_NULL(src))
+ return -EINVAL;
+
+ if (IS_ERR_OR_NULL(dst))
+ return -EINVAL;
+
+ mutex_lock(&icc_lock);
+
+ for (slot = 0; slot < src->num_links; slot++)
+ if (src->links[slot] == dst)
+ break;
+
+ last = src->links[src->num_links];
+
+ new = krealloc(src->links,
+ (src->num_links - 1) * sizeof(*src->links),
+ GFP_KERNEL);
+ if (!new) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ src->links = new;
+
+ if (slot < src->num_links - 1)
+ /* move the last element to the slot that was freed */
+ src->links[slot] = last;
+
+ src->num_links--;
+
+out:
+ mutex_unlock(&icc_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(icc_link_destroy);
+
+/**
+ * icc_node_add() - add interconnect node to interconnect provider
+ * @node: pointer to the interconnect node
+ * @provider: pointer to the interconnect provider
+ *
+ */
+void icc_node_add(struct icc_node *node, struct icc_provider *provider)
+{
+ mutex_lock(&icc_lock);
+
+ node->provider = provider;
+ list_add(&node->node_list, &provider->nodes);
+
+ mutex_unlock(&icc_lock);
+}
+EXPORT_SYMBOL_GPL(icc_node_add);
+
+/**
+ * icc_node_del() - delete interconnect node from interconnect provider
+ * @node: pointer to the interconnect node
+ *
+ */
+void icc_node_del(struct icc_node *node)
+{
+ mutex_lock(&icc_lock);
+
+ list_del(&node->node_list);
+
+ mutex_unlock(&icc_lock);
+}
+EXPORT_SYMBOL_GPL(icc_node_del);
+
+/**
+ * icc_provider_add() - add a new interconnect provider
+ * @icc_provider: the interconnect provider that will be added into topology
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_provider_add(struct icc_provider *provider)
+{
+ if (WARN_ON(!provider->set))
+ return -EINVAL;
+
+ mutex_lock(&icc_lock);
+
+ INIT_LIST_HEAD(&provider->nodes);
+ list_add(&provider->provider_list, &icc_provider_list);
+
+ mutex_unlock(&icc_lock);
+
+ dev_dbg(provider->dev, "interconnect provider added to topology\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(icc_provider_add);
+
+/**
+ * icc_provider_del() - delete previously added interconnect provider
+ * @icc_provider: the interconnect provider that will be removed from topology
+ *
+ * Return: 0 on success, or an error code otherwise
+ */
+int icc_provider_del(struct icc_provider *provider)
+{
+ mutex_lock(&icc_lock);
+ if (provider->users) {
+ pr_warn("interconnect provider still has %d users\n",
+ provider->users);
+ mutex_unlock(&icc_lock);
+ return -EBUSY;
+ }
+
+ if (!list_empty(&provider->nodes)) {
+ pr_warn("interconnect provider still has nodes\n");
+ mutex_unlock(&icc_lock);
+ return -EBUSY;
+ }
+
+ list_del(&provider->provider_list);
+ mutex_unlock(&icc_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(icc_provider_del);
+
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org");
+MODULE_DESCRIPTION("Interconnect Driver Core");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig
new file mode 100644
index 000000000000..c840e7ae29ff
--- /dev/null
+++ b/drivers/interconnect/qcom/Kconfig
@@ -0,0 +1,29 @@
+config INTERCONNECT_QCOM
+ bool "Qualcomm Network-on-Chip interconnect drivers"
+ depends on INTERCONNECT
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ Support for Qualcomm's Network-on-Chip interconnect hardware.
+
+config INTERCONNECT_QCOM_SMD_RPM
+ tristate "Qualcomm SMD RPM interconnect driver"
+ depends on INTERCONNECT_QCOM
+ help
+ This is a driver for communicating interconnect related configuration
+ details with a remote processor (RPM) on Qualcomm platforms.
+
+config INTERCONNECT_QCOM_MSM8916
+ tristate "Qualcomm MSM8916 interconnect driver"
+ depends on INTERCONNECT_QCOM
+ select INTERCONNECT_QCOM_SMD_RPM
+ help
+ This is a driver for the Qualcomm Network-on-Chip on msm8916-based
+ platforms.
+
+config INTERCONNECT_QCOM_MSM8996
+ tristate "Qualcomm MSM8996 interconnect driver"
+ depends on INTERCONNECT_QCOM
+ select INTERCONNECT_QCOM_SMD_RPM
+ help
+ This is a driver for the Qualcomm Network-on-Chip on msm8996-based
+ platforms.
diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile
new file mode 100644
index 000000000000..b3e5f0ab6bac
--- /dev/null
+++ b/drivers/interconnect/qcom/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += smd-rpm.o
+
+obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += msm8916.o
+obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += msm8996.o
diff --git a/drivers/interconnect/qcom/msm8916.c b/drivers/interconnect/qcom/msm8916.c
new file mode 100644
index 000000000000..6128867a6faa
--- /dev/null
+++ b/drivers/interconnect/qcom/msm8916.c
@@ -0,0 +1,508 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Linaro Ltd
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <dt-bindings/interconnect/qcom.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "smd-rpm.h"
+
+#define RPM_BUS_MASTER_REQ 0x73616d62
+#define RPM_BUS_SLAVE_REQ 0x766c7362
+
+#define to_qcom_provider(_provider) \
+ container_of(_provider, struct qcom_icc_provider, provider)
+
+enum qcom_qos_mode {
+ QCOM_QOS_MODE_BYPASS = 0,
+ QCOM_QOS_MODE_FIXED,
+ QCOM_QOS_MODE_MAX,
+};
+
+struct qcom_icc_provider {
+ struct icc_provider provider;
+ void __iomem *base;
+ struct clk *bus_clk;
+ struct clk *bus_a_clk;
+};
+
+#define MSM8916_MAX_LINKS 8
+
+/**
+ * struct qcom_icc_node - Qualcomm specific interconnect nodes
+ * @name: the node name used in debugfs
+ * @id: a unique node identifier
+ * @links: an array of nodes where we can go next while traversing
+ * @num_links: the total number of @links
+ * @port: the offset index into the masters QoS register space
+ * @buswidth: width of the interconnect between a node and the bus (bytes)
+ * @ap_owned: the AP CPU does the writing to QoS registers
+ * @qos_mode: QoS mode for ap_owned resources
+ * @mas_rpm_id: RPM id for devices that are bus masters
+ * @slv_rpm_id: RPM id for devices that are bus slaves
+ * @rate: current bus clock rate in Hz
+ */
+struct qcom_icc_node {
+ unsigned char *name;
+ u16 id;
+ u16 links[MSM8916_MAX_LINKS];
+ u16 num_links;
+ u16 port;
+ u16 buswidth;
+ bool ap_owned;
+ enum qcom_qos_mode qos_mode;
+ int mas_rpm_id;
+ int slv_rpm_id;
+ u64 rate;
+};
+
+struct qcom_icc_desc {
+ struct qcom_icc_node **nodes;
+ size_t num_nodes;
+};
+
+#define DEFINE_QNODE(_name, _id, _port, _buswidth, _ap_owned, \
+ _mas_rpm_id, _slv_rpm_id, _qos_mode, \
+ _numlinks, ...) \
+ static struct qcom_icc_node _name = { \
+ .name = #_name, \
+ .id = _id, \
+ .port = _port, \
+ .buswidth = _buswidth, \
+ .ap_owned = _ap_owned, \
+ .mas_rpm_id = _mas_rpm_id, \
+ .slv_rpm_id = _slv_rpm_id, \
+ .qos_mode = _qos_mode, \
+ .num_links = _numlinks, \
+ .links = { __VA_ARGS__ }, \
+ }
+
+DEFINE_QNODE(mas_video, MASTER_VIDEO_P0, 8, 16, 1, -1, -1, QCOM_QOS_MODE_BYPASS, 2, SNOC_MM_INT_0, SNOC_MM_INT_2);
+DEFINE_QNODE(mas_jpeg, MASTER_JPEG, 6, 16, 1, -1, -1, QCOM_QOS_MODE_BYPASS, 2, SNOC_MM_INT_0, SNOC_MM_INT_2);
+DEFINE_QNODE(mas_vfe, MASTER_VFE, 9, 16, 1, -1, -1, QCOM_QOS_MODE_BYPASS, 2, SNOC_MM_INT_1, SNOC_MM_INT_2);
+DEFINE_QNODE(mas_mdp, MASTER_MDP_PORT0, 7, 16, 1, -1, -1, QCOM_QOS_MODE_BYPASS, 2, SNOC_MM_INT_0, SNOC_MM_INT_2);
+DEFINE_QNODE(mas_qdss_bam, MASTER_QDSS_BAM, 11, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_QDSS_INT);
+DEFINE_QNODE(mas_snoc_cfg, MASTER_SNOC_CFG, 0, 16, 0, 20, -1, QCOM_QOS_MODE_BYPASS, 1, SNOC_QDSS_INT);
+DEFINE_QNODE(mas_qdss_etr, MASTER_QDSS_ETR, 10, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_QDSS_INT);
+DEFINE_QNODE(mm_int_0, SNOC_MM_INT_0, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_MM_INT_BIMC);
+DEFINE_QNODE(mm_int_1, SNOC_MM_INT_1, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_MM_INT_BIMC);
+DEFINE_QNODE(mm_int_2, SNOC_MM_INT_2, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_INT_0);
+DEFINE_QNODE(mm_int_bimc, SNOC_MM_INT_BIMC, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_BIMC_1_MAS);
+DEFINE_QNODE(snoc_int_0, SNOC_INT_0, 0, 8, 0, 99, 130, QCOM_QOS_MODE_FIXED, 3, SLAVE_QDSS_STM, SLAVE_SYSTEM_IMEM, MNOC_BIMC_MAS);
+DEFINE_QNODE(snoc_int_1, SNOC_INT_1, 0, 8, 0, 100, 131, QCOM_QOS_MODE_FIXED, 3, SYSTEM_SLAVE_FAB_APPS, SLAVE_CATS_128, SLAVE_OCMEM_64);
+DEFINE_QNODE(snoc_int_bimc, SNOC_INT_BIMC, 0, 8, 0, 101, 132, QCOM_QOS_MODE_FIXED, 1, SNOC_BIMC_0_MAS);
+DEFINE_QNODE(snoc_bimc_0_mas, SNOC_BIMC_0_MAS, 0, 8, 0, 3, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_BIMC_0_SLV);
+DEFINE_QNODE(snoc_bimc_1_mas, SNOC_BIMC_1_MAS, 0, 16, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SNOC_BIMC_1_SLV);
+DEFINE_QNODE(qdss_int, SNOC_QDSS_INT, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 2, SNOC_INT_0, SNOC_INT_BIMC);
+DEFINE_QNODE(bimc_snoc_slv, BIMC_SNOC_SLV, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 2, SNOC_INT_0, SNOC_INT_1);
+DEFINE_QNODE(snoc_pnoc_mas, MNOC_BIMC_MAS, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(pnoc_snoc_slv, PNOC_SNOC_SLV, 0, 8, 0, -1, 45, QCOM_QOS_MODE_FIXED, 3, SNOC_INT_0, SNOC_INT_BIMC, SNOC_INT_1);
+DEFINE_QNODE(slv_srvc_snoc, SLAVE_SERVICE_SNOC, 0, 8, 0, -1, 29, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_qdss_stm, SLAVE_QDSS_STM, 0, 4, 0, -1, 30, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_imem, SLAVE_SYSTEM_IMEM, 0, 8, 0, -1, 26, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_apss, SYSTEM_SLAVE_FAB_APPS, 0, 4, 0, -1, 20, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_cats_0, SLAVE_CATS_128, 0, 16, 0, -1, 106, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_cats_1, SLAVE_OCMEM_64, 0, 8, 0, -1, 107, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(mas_apss, MASTER_AMPSS_M0, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_EBI_CH0, BIMC_SNOC_MAS, SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_tcu0, MASTER_TCU_0, 5, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_EBI_CH0, BIMC_SNOC_MAS, SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_tcu1, MASTER_TCU_1, 6, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_EBI_CH0, BIMC_SNOC_MAS, SLAVE_AMPSS_L2);
+DEFINE_QNODE(mas_gfx, MASTER_GRAPHICS_3D, 2, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_EBI_CH0, BIMC_SNOC_MAS, SLAVE_AMPSS_L2);
+DEFINE_QNODE(bimc_snoc_mas, BIMC_SNOC_MAS, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, BIMC_SNOC_SLV);
+DEFINE_QNODE(snoc_bimc_0_slv, SNOC_BIMC_0_SLV, 0, 8, 0, -1, 24, QCOM_QOS_MODE_FIXED, 1, SLAVE_EBI_CH0);
+DEFINE_QNODE(snoc_bimc_1_slv, SNOC_BIMC_1_SLV, 0, 8, 1, -1, -1, QCOM_QOS_MODE_FIXED, 1, SLAVE_EBI_CH0);
+DEFINE_QNODE(slv_ebi_ch0, SLAVE_EBI_CH0, 0, 8, 0, -1, 0, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_apps_l2, SLAVE_AMPSS_L2, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(snoc_pnoc_slv, MNOC_BIMC_SLV, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_0);
+DEFINE_QNODE(pnoc_int_0, PNOC_INT_0, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 8, PNOC_SNOC_MAS, PNOC_SLV_0, PNOC_SLV_1, PNOC_SLV_2, PNOC_SLV_3, PNOC_SLV_4, PNOC_SLV_8, PNOC_SLV_9);
+DEFINE_QNODE(pnoc_int_1, PNOC_INT_1, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_SNOC_MAS);
+DEFINE_QNODE(pnoc_m_0, PNOC_M_0, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_0);
+DEFINE_QNODE(pnoc_m_1, PNOC_M_1, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_SNOC_MAS);
+DEFINE_QNODE(pnoc_s_0, PNOC_SLV_0, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 5, SLAVE_CLK_CTL, SLAVE_TLMM, SLAVE_MSM_TCSR, SLAVE_SECURITY, SLAVE_MSS);
+DEFINE_QNODE(pnoc_s_1, PNOC_SLV_1, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 5, SLAVE_IMEM_CFG, SLAVE_CRYPTO_0_CFG, SLAVE_RPM_MSG_RAM, SLAVE_MSM_PDM, SLAVE_PRNG);
+DEFINE_QNODE(pnoc_s_2, PNOC_SLV_2, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 5, SLAVE_SPDM, SLAVE_BOOT_ROM, SLAVE_BIMC_CFG, SLAVE_PNOC_CFG, SLAVE_PMIC_ARB);
+DEFINE_QNODE(pnoc_s_3, PNOC_SLV_3, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 5, SLAVE_MPM, SLAVE_IPS_CFG, SLAVE_RBCPR_CFG, SLAVE_QDSS_CFG, SLAVE_DEHR_CFG);
+DEFINE_QNODE(pnoc_s_4, PNOC_SLV_4, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_VENUS_CFG, SLAVE_CAMERA_CFG, SLAVE_DISPLAY_CFG);
+DEFINE_QNODE(pnoc_s_8, PNOC_SLV_8, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_USB_HS, SLAVE_SDCC_1, SLAVE_BLSP_1);
+DEFINE_QNODE(pnoc_s_9, PNOC_SLV_9, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 3, SLAVE_SDCC_4, SLAVE_LPASS, SLAVE_GRAPHICS_3D_CFG);
+DEFINE_QNODE(slv_imem_cfg, SLAVE_IMEM_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_crypto_0_cfg, SLAVE_CRYPTO_0_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_msg_ram, SLAVE_RPM_MSG_RAM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_pdm, SLAVE_MSM_PDM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_prng, SLAVE_PRNG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_clk_ctl, SLAVE_CLK_CTL, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_mss, SLAVE_MSS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_tlmm, SLAVE_TLMM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_tcsr, SLAVE_MSM_TCSR, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_security, SLAVE_SECURITY, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_spdm, SLAVE_SPDM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_pnoc_cfg, SLAVE_PNOC_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_pmic_arb, SLAVE_PMIC_ARB, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_bimc_cfg, SLAVE_BIMC_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_boot_rom, SLAVE_BOOT_ROM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_mpm, SLAVE_MPM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_qdss_cfg, SLAVE_QDSS_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_rbcpr_cfg, SLAVE_RBCPR_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_snoc_cfg, SLAVE_IPS_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_dehr_cfg, SLAVE_DEHR_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_venus_cfg, SLAVE_VENUS_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_display_cfg, SLAVE_DISPLAY_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_camera_cfg, SLAVE_CAMERA_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_usb_hs, SLAVE_USB_HS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_sdcc_1, SLAVE_SDCC_1, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_blsp_1, SLAVE_BLSP_1, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_sdcc_2, SLAVE_SDCC_4, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_gfx_cfg, SLAVE_GRAPHICS_3D_CFG, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(slv_audio, SLAVE_LPASS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 0, 0);
+DEFINE_QNODE(mas_blsp_1, MASTER_BLSP_1, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_1);
+DEFINE_QNODE(mas_spdm, MASTER_SPDM, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_0);
+DEFINE_QNODE(mas_dehr, MASTER_DEHR, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_0);
+DEFINE_QNODE(mas_audio, MASTER_LPASS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_0);
+DEFINE_QNODE(mas_usb_hs, MASTER_USB_HS, 0, 4, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_M_1);
+DEFINE_QNODE(mas_pnoc_crypto_0, MASTER_CRYPTO_CORE0, 0, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_1);
+DEFINE_QNODE(mas_pnoc_sdcc_1, MASTER_SDCC_1, 7, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_1);
+DEFINE_QNODE(mas_pnoc_sdcc_2, MASTER_SDCC_2, 8, 8, 0, -1, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_INT_1);
+DEFINE_QNODE(pnoc_snoc_mas, PNOC_SNOC_MAS, 0, 8, 0, 29, -1, QCOM_QOS_MODE_FIXED, 1, PNOC_SNOC_SLV);
+
+static struct qcom_icc_node *msm8916_snoc_nodes[] = {
+ &mas_video,
+ &mas_jpeg,
+ &mas_vfe,
+ &mas_mdp,
+ &mas_qdss_bam,
+ &mas_snoc_cfg,
+ &mas_qdss_etr,
+ &mm_int_0,
+ &mm_int_1,
+ &mm_int_2,
+ &mm_int_bimc,
+ &snoc_int_0,
+ &snoc_int_1,
+ &snoc_int_bimc,
+ &snoc_bimc_0_mas,
+ &snoc_bimc_1_mas,
+ &qdss_int,
+ &bimc_snoc_slv,
+ &snoc_pnoc_mas,
+ &pnoc_snoc_slv,
+ &slv_srvc_snoc,
+ &slv_qdss_stm,
+ &slv_imem,
+ &slv_apss,
+ &slv_cats_0,
+ &slv_cats_1,
+};
+
+static struct qcom_icc_desc msm8916_snoc = {
+ .nodes = msm8916_snoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_snoc_nodes),
+};
+
+static struct qcom_icc_node *msm8916_bimc_nodes[] = {
+ &mas_apss,
+ &mas_tcu0,
+ &mas_tcu1,
+ &mas_gfx,
+ &bimc_snoc_mas,
+ &snoc_bimc_0_slv,
+ &snoc_bimc_1_slv,
+ &slv_ebi_ch0,
+ &slv_apps_l2,
+};
+
+static struct qcom_icc_desc msm8916_bimc = {
+ .nodes = msm8916_bimc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_bimc_nodes),
+};
+
+static struct qcom_icc_node *msm8916_pnoc_nodes[] = {
+ &snoc_pnoc_slv,
+ &pnoc_int_0,
+ &pnoc_int_1,
+ &pnoc_m_0,
+ &pnoc_m_1,
+ &pnoc_s_0,
+ &pnoc_s_1,
+ &pnoc_s_2,
+ &pnoc_s_3,
+ &pnoc_s_4,
+ &pnoc_s_8,
+ &pnoc_s_9,
+ &slv_imem_cfg,
+ &slv_crypto_0_cfg,
+ &slv_msg_ram,
+ &slv_pdm,
+ &slv_prng,
+ &slv_clk_ctl,
+ &slv_mss,
+ &slv_tlmm,
+ &slv_tcsr,
+ &slv_security,
+ &slv_spdm,
+ &slv_pnoc_cfg,
+ &slv_pmic_arb,
+ &slv_bimc_cfg,
+ &slv_boot_rom,
+ &slv_mpm,
+ &slv_qdss_cfg,
+ &slv_rbcpr_cfg,
+ &slv_snoc_cfg,
+ &slv_dehr_cfg,
+ &slv_venus_cfg,
+ &slv_display_cfg,
+ &slv_camera_cfg,
+ &slv_usb_hs,
+ &slv_sdcc_1,
+ &slv_blsp_1,
+ &slv_sdcc_2,
+ &slv_gfx_cfg,
+ &slv_audio,
+ &mas_blsp_1,
+ &mas_spdm,
+ &mas_dehr,
+ &mas_audio,
+ &mas_usb_hs,
+ &mas_pnoc_crypto_0,
+ &mas_pnoc_sdcc_1,
+ &mas_pnoc_sdcc_2,
+ &pnoc_snoc_mas,
+};
+
+static struct qcom_icc_desc msm8916_pnoc = {
+ .nodes = msm8916_pnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8916_pnoc_nodes),
+};
+
+static int qcom_icc_aggregate(struct icc_node *node, u32 avg_bw, u32 peak_bw,
+ u32 *agg_avg, u32 *agg_peak)
+{
+ *agg_avg += avg_bw;
+ *agg_peak = max(*agg_peak, peak_bw);
+
+ return 0;
+}
+
+static int qcom_icc_set(struct icc_node *src, struct icc_node *dst,
+ u32 avg, u32 peak)
+{
+ struct qcom_icc_provider *qp;
+ struct qcom_icc_node *qn;
+ struct icc_node *node;
+ struct icc_provider *provider;
+ u64 avg_bw = icc_units_to_bps(avg);
+ u64 peak_bw = icc_units_to_bps(peak);
+ int ret = 0;
+ u64 rate;
+
+ if (!src)
+ node = dst;
+ else
+ node = src;
+
+ qn = node->data;
+ provider = node->provider;
+ qp = to_qcom_provider(provider);
+
+ /* set bandwidth */
+ if (qn->ap_owned) {
+ /* TODO: set QoS */
+ } else {
+ /* send message to the RPM processor */
+ if (qn->mas_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_MASTER_REQ,
+ qn->mas_rpm_id,
+ avg_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send mas error %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ if (qn->slv_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_SLAVE_REQ,
+ qn->slv_rpm_id,
+ avg_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send slv error %d\n",
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ rate = max(avg_bw, peak_bw);
+
+ do_div(rate, qn->buswidth);
+
+ if (qn->rate != rate) {
+ ret = clk_set_rate(qp->bus_clk, rate);
+ if (ret) {
+ pr_err("set clk rate %lld error %d\n", rate, ret);
+ return ret;
+ }
+
+ ret = clk_set_rate(qp->bus_a_clk, rate);
+ if (ret) {
+ pr_err("set clk rate %lld error %d\n", rate, ret);
+ return ret;
+ }
+
+ qn->rate = rate;
+ }
+
+ return ret;
+}
+
+static int qnoc_probe(struct platform_device *pdev)
+{
+ const struct qcom_icc_desc *desc;
+ struct qcom_icc_node **qnodes;
+ struct icc_node *node;
+ struct qcom_icc_provider *qp;
+ struct resource *res;
+ struct icc_provider *provider;
+ size_t num_nodes, i;
+ int ret;
+
+ /* wait for RPM */
+ if (!qcom_icc_rpm_smd_available())
+ return -EPROBE_DEFER;
+
+ desc = of_device_get_match_data(&pdev->dev);
+ if (!desc)
+ return -EINVAL;
+
+ qnodes = desc->nodes;
+ num_nodes = desc->num_nodes;
+
+ qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
+ if (!qp)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ qp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(qp->base))
+ return PTR_ERR(qp->base);
+
+ qp->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(qp->bus_clk))
+ return PTR_ERR(qp->bus_clk);
+
+ ret = clk_prepare_enable(qp->bus_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "error enabling bus_clk: %d\n", ret);
+ return ret;
+ }
+
+ qp->bus_a_clk = devm_clk_get(&pdev->dev, "bus_a_clk");
+ if (IS_ERR(qp->bus_a_clk))
+ return PTR_ERR(qp->bus_a_clk);
+
+ ret = clk_prepare_enable(qp->bus_a_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "error enabling bus_a_clk: %d\n", ret);
+ clk_disable_unprepare(qp->bus_clk);
+ return ret;
+ }
+
+ provider = &qp->provider;
+ provider->dev = &pdev->dev;
+ provider->set = &qcom_icc_set;
+ provider->aggregate = &qcom_icc_aggregate;
+ INIT_LIST_HEAD(&provider->nodes);
+ provider->data = qp;
+
+ ret = icc_provider_add(provider);
+ if (ret) {
+ dev_err(&pdev->dev, "error adding interconnect provider\n");
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+ return ret;
+ }
+
+ for (i = 0; i < num_nodes; i++) {
+ int ret;
+ size_t j;
+
+ node = icc_node_create(qnodes[i]->id);
+ if (IS_ERR(node)) {
+ ret = PTR_ERR(node);
+ goto err;
+ }
+
+ node->name = qnodes[i]->name;
+ node->data = qnodes[i];
+ icc_node_add(node, provider);
+
+ dev_dbg(&pdev->dev, "registered node %s\n", node->name);
+
+ /* populate links */
+ for (j = 0; j < qnodes[i]->num_links; j++)
+ if (qnodes[i]->links[j])
+ icc_link_create(node, qnodes[i]->links[j]);
+ }
+
+ platform_set_drvdata(pdev, provider);
+
+ return ret;
+err:
+ list_for_each_entry(node, &provider->nodes, node_list) {
+ icc_node_del(node);
+ icc_node_destroy(node->id);
+ }
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+ icc_provider_del(provider);
+
+ return ret;
+}
+
+static int qnoc_remove(struct platform_device *pdev)
+{
+ struct icc_provider *provider = platform_get_drvdata(pdev);
+ struct qcom_icc_provider *qp = to_qcom_provider(provider);
+ struct icc_node *n;
+
+ list_for_each_entry(n, &provider->nodes, node_list) {
+ icc_node_del(n);
+ icc_node_destroy(n->id);
+ }
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+
+
+ return icc_provider_del(provider);
+}
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,msm8916-pnoc", .data = &msm8916_pnoc },
+ { .compatible = "qcom,msm8916-snoc", .data = &msm8916_snoc },
+ { .compatible = "qcom,msm8916-bimc", .data = &msm8916_bimc },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qnoc_probe,
+ .remove = qnoc_remove,
+ .driver = {
+ .name = "qnoc-msm8916",
+ .of_match_table = qnoc_of_match,
+ },
+};
+module_platform_driver(qnoc_driver);
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm msm8916 NoC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c
new file mode 100644
index 000000000000..5f5af3ee80d2
--- /dev/null
+++ b/drivers/interconnect/qcom/msm8996.c
@@ -0,0 +1,658 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Linaro Ltd
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <dt-bindings/interconnect/qcom.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interconnect-provider.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "smd-rpm.h"
+
+#define RPM_MASTER_FIELD_BW 0x00007762
+#define RPM_BUS_MASTER_REQ 0x73616d62
+#define RPM_BUS_SLAVE_REQ 0x766c7362
+
+#define to_qcom_provider(_provider) \
+ container_of(_provider, struct qcom_icc_provider, provider)
+
+enum qcom_qos_mode {
+ QCOM_QOS_MODE_BYPASS = 0,
+ QCOM_QOS_MODE_FIXED,
+ QCOM_QOS_MODE_MAX,
+};
+
+struct qcom_icc_provider {
+ struct icc_provider provider;
+ void __iomem *base;
+ struct clk *bus_clk;
+ struct clk *bus_a_clk;
+};
+
+#define MSM8996_MAX_LINKS 38
+
+/**
+ * struct qcom_icc_node - Qualcomm specific interconnect nodes
+ * @name: the node name used in debugfs
+ * @id: a unique node identifier
+ * @links: an array of nodes where we can go next while traversing
+ * @num_links: the total number of @links
+ * @port: the offset index into the masters QoS register space
+ * @agg_ports: the number of aggregation ports on the bus
+ * @buswidth: width of the interconnect between a node and the bus (bytes)
+ * @ap_owned: the AP CPU does the writing to QoS registers
+ * @qos_mode: QoS mode for ap_owned resources
+ * @mas_rpm_id: RPM id for devices that are bus masters
+ * @slv_rpm_id: RPM id for devices that are bus slaves
+ * @rate: current bus clock rate in Hz
+ */
+struct qcom_icc_node {
+ unsigned char *name;
+ u16 id;
+ u16 links[MSM8996_MAX_LINKS];
+ u16 num_links;
+ u16 port;
+ u16 agg_ports;
+ u16 buswidth;
+ bool ap_owned;
+ enum qcom_qos_mode qos_mode;
+ int mas_rpm_id;
+ int slv_rpm_id;
+ u64 rate;
+};
+
+struct qcom_icc_desc {
+ struct qcom_icc_node **nodes;
+ size_t num_nodes;
+};
+
+#define DEFINE_QNODE(_name, _id, _port, _agg_ports, _buswidth, \
+ _qos_mode, _ap_owned, _mas_rpm_id, _slv_rpm_id, \
+ _numlinks, ...) \
+ static struct qcom_icc_node _name = { \
+ .name = #_name, \
+ .id = _id, \
+ .port = _port, \
+ .agg_ports = _agg_ports, \
+ .buswidth = _buswidth, \
+ .qos_mode = _qos_mode, \
+ .ap_owned = _ap_owned, \
+ .mas_rpm_id = _mas_rpm_id, \
+ .slv_rpm_id = _slv_rpm_id, \
+ .num_links = _numlinks, \
+ .links = { __VA_ARGS__ }, \
+ }
+
+DEFINE_QNODE(mas_pcie_0, MASTER_PCIE, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, 65, -1, 1, A0NOC_SNOC_SLV);
+DEFINE_QNODE(mas_pcie_1, MASTER_PCIE_1, 1, 1, 8, QCOM_QOS_MODE_FIXED, 1, 66, -1, 1, A0NOC_SNOC_SLV);
+DEFINE_QNODE(mas_pcie_2, MASTER_PCIE_2, 2, 1, 8, QCOM_QOS_MODE_FIXED, 1, 119, -1, 1, A0NOC_SNOC_SLV);
+DEFINE_QNODE(mas_cnoc_a1noc, CNOC_A1NOC_MAS, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, 116, -1, 1, A1NOC_SNOC_SLV);
+DEFINE_QNODE(mas_crypto_c0, MASTER_CRYPTO_CORE0, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, 23, -1, 1, A1NOC_SNOC_SLV);
+DEFINE_QNODE(mas_pnoc_a1noc, PNOC_A1NOC_MAS, 1, 1, 8, QCOM_QOS_MODE_FIXED, 0, 117, -1, 1, A1NOC_SNOC_SLV);
+DEFINE_QNODE(mas_usb3, MASTER_USB3, 3, 1, 8, QCOM_QOS_MODE_FIXED, 1, 32, -1, 1, A2NOC_SNOC_SLV);
+DEFINE_QNODE(mas_ipa, MASTER_IPA, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, 59, -1, 1, A2NOC_SNOC_SLV);
+DEFINE_QNODE(mas_ufs, MASTER_UFS, 2, 1, 8, QCOM_QOS_MODE_FIXED, 1, 68, -1, 1, A2NOC_SNOC_SLV);
+DEFINE_QNODE(mas_apps_proc, MASTER_AMPSS_M0, 0, 2, 8, QCOM_QOS_MODE_FIXED, 1, 0, -1, 3, BIMC_SNOC_1_SLV, SLAVE_EBI_CH0, BIMC_SNOC_SLV);
+DEFINE_QNODE(mas_oxili, MASTER_GRAPHICS_3D, 1, 2, 8, QCOM_QOS_MODE_BYPASS, 1, 6, -1, 4, BIMC_SNOC_1_SLV, SLAVE_HMSS_L3, SLAVE_EBI_CH0, BIMC_SNOC_SLV);
+DEFINE_QNODE(mas_mnoc_bimc, MNOC_BIMC_MAS, 2, 2, 8, QCOM_QOS_MODE_BYPASS, 1, 2, -1, 4, BIMC_SNOC_1_SLV, SLAVE_HMSS_L3, SLAVE_EBI_CH0, BIMC_SNOC_SLV);
+DEFINE_QNODE(mas_snoc_bimc, SNOC_BIMC_MAS, 0, 2, 8, QCOM_QOS_MODE_BYPASS, 0, 3, -1, 2, SLAVE_HMSS_L3, SLAVE_EBI_CH0);
+DEFINE_QNODE(mas_snoc_cnoc, SNOC_CNOC_MAS, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 52, -1, 37, SLAVE_CLK_CTL, SLAVE_RBCPR_CX, SLAVE_A2NOC_SMMU_CFG, SLAVE_A0NOC_MPU_CFG, SLAVE_MESSAGE_RAM, SLAVE_CNOC_MNOC_MMSS_CFG, SLAVE_PCIE_0_CFG, SLAVE_TLMM, SLAVE_MPM, SLAVE_A0NOC_SMMU_CFG, SLAVE_EBI1_PHY_CFG, SLAVE_BIMC_CFG, SLAVE_PIMEM_CFG, SLAVE_RBCPR_MX, SLAVE_PRNG, SLAVE_PCIE20_AHB2PHY, SLAVE_A2NOC_MPU_CFG, SLAVE_QDSS_CFG, SLAVE_A2NOC_CFG, SLAVE_A0NOC_CFG, SLAVE_UFS_CFG, SLAVE_CRYPTO_0_CFG, SLAVE_PCIE_1_CFG, SLAVE_SNOC_CFG, SLAVE_SNOC_MPU_CFG, SLAVE_A1NOC_MPU_CFG, SLAVE_A1NOC_SMMU_CFG, SLAVE_PCIE_2_CFG, SLAVE_CNOC_MNOC_CFG, SLAVE_QDSS_RBCPR_APU_CFG, SLAVE_PMIC_ARB, SLAVE_IMEM_CFG, SLAVE_A1NOC_CFG, SLAVE_SSC_CFG, SLAVE_TCSR, SLAVE_LPASS_SMMU_CFG, SLAVE_DCC_CFG);
+DEFINE_QNODE(mas_qdss_dap, MASTER_QDSS_DAP, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 1, 49, -1, 38, SLAVE_QDSS_RBCPR_APU_CFG, SLAVE_RBCPR_CX, SLAVE_A2NOC_SMMU_CFG, SLAVE_A0NOC_MPU_CFG, SLAVE_MESSAGE_RAM, SLAVE_PCIE_0_CFG, SLAVE_TLMM, SLAVE_MPM, SLAVE_A0NOC_SMMU_CFG, SLAVE_EBI1_PHY_CFG, SLAVE_BIMC_CFG, SLAVE_PIMEM_CFG, SLAVE_RBCPR_MX, SLAVE_CLK_CTL, SLAVE_PRNG, SLAVE_PCIE20_AHB2PHY, SLAVE_A2NOC_MPU_CFG, SLAVE_QDSS_CFG, SLAVE_A2NOC_CFG, SLAVE_A0NOC_CFG, SLAVE_UFS_CFG, SLAVE_CRYPTO_0_CFG, CNOC_SNOC_SLV, SLAVE_PCIE_1_CFG, SLAVE_SNOC_CFG, SLAVE_SNOC_MPU_CFG, SLAVE_A1NOC_MPU_CFG, SLAVE_A1NOC_SMMU_CFG, SLAVE_PCIE_2_CFG, SLAVE_CNOC_MNOC_CFG, SLAVE_CNOC_MNOC_MMSS_CFG, SLAVE_PMIC_ARB, SLAVE_IMEM_CFG, SLAVE_A1NOC_CFG, SLAVE_SSC_CFG, SLAVE_TCSR, SLAVE_LPASS_SMMU_CFG, SLAVE_DCC_CFG);
+DEFINE_QNODE(mas_cnoc_mnoc_mmss_cfg, MASTER_CNOC_MNOC_MMSS_CFG, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 1, 4, -1, 21, SLAVE_MMAGIC_CFG, SLAVE_DSA_MPU_CFG, SLAVE_MMSS_CLK_CFG, SLAVE_CAMERA_THROTTLE_CFG, SLAVE_VENUS_CFG, SLAVE_SMMU_VFE_CFG, SLAVE_MISC_CFG, SLAVE_SMMU_CPP_CFG, SLAVE_GRAPHICS_3D_CFG, SLAVE_DISPLAY_THROTTLE_CFG, SLAVE_VENUS_THROTTLE_CFG, SLAVE_CAMERA_CFG, SLAVE_DISPLAY_CFG, SLAVE_CPR_CFG, SLAVE_SMMU_ROTATOR_CFG, SLAVE_DSA_CFG, SLAVE_SMMU_VENUS_CFG, SLAVE_VMEM_CFG, SLAVE_SMMU_JPEG_CFG, SLAVE_SMMU_MDP_CFG, SLAVE_MNOC_MPU_CFG);
+DEFINE_QNODE(mas_cnoc_mnoc_cfg, MASTER_CNOC_MNOC_CFG, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 1, 5, -1, 1, SLAVE_SERVICE_MNOC);
+DEFINE_QNODE(mas_cpp, MASTER_CPP, 5, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 115, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_jpeg, MASTER_JPEG, 7, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 7, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_mdp_p0, MASTER_MDP_PORT0, 1, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 8, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_mdp_p1, MASTER_MDP_PORT1, 2, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 61, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_rotator, MASTER_ROTATOR, 0, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 120, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_venus, MASTER_VIDEO_P0, 3, 2, 32, QCOM_QOS_MODE_BYPASS, 1, 9, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_vfe, MASTER_VFE, 6, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 11, -1, 1, MNOC_BIMC_SLV);
+DEFINE_QNODE(mas_snoc_vmem, MASTER_SNOC_VMEM, 0, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 114, -1, 1, SLAVE_VMEM_CFG);
+DEFINE_QNODE(mas_venus_vmem, MASTER_VIDEO_P0_OCMEM, 0, 1, 32, QCOM_QOS_MODE_BYPASS, 1, 121, -1, 1, SLAVE_VMEM_CFG);
+DEFINE_QNODE(mas_snoc_pnoc, SNOC_PNOC_MAS, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 44, -1, 9, SLAVE_BLSP_1, SLAVE_BLSP_2, SLAVE_USB_HS, SLAVE_SDCC_1, SLAVE_SDCC_2, SLAVE_SDCC_4, SLAVE_TSIF, SLAVE_PDM, SLAVE_AHB2PHY);
+DEFINE_QNODE(mas_sdcc_1, MASTER_SDCC_1, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 33, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_sdcc_2, MASTER_SDCC_2, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 35, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_sdcc_4, MASTER_SDCC_4, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 36, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_usb_hs, MASTER_USB_HS, 0, 1, 8, QCOM_QOS_MODE_BYPASS, 0, 42, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_blsp_1, MASTER_BLSP_1, 0, 1, 4, QCOM_QOS_MODE_BYPASS, 0, 41, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_blsp_2, MASTER_BLSP_2, 0, 1, 4, QCOM_QOS_MODE_BYPASS, 0, 39, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_tsif, MASTER_TSIF, 0, 1, 4, QCOM_QOS_MODE_BYPASS, 0, 37, -1, 1, PNOC_A1NOC_SLV);
+DEFINE_QNODE(mas_hmss, MASTER_HMSS, 4, 1, 8, QCOM_QOS_MODE_FIXED, 1, 118, -1, 3, SLAVE_PIMEM, SLAVE_OCIMEM, SNOC_BIMC_SLV);
+DEFINE_QNODE(mas_qdss_bam, MASTER_QDSS_BAM, 2, 1, 16, QCOM_QOS_MODE_FIXED, 1, 19, -1, 5, SLAVE_PIMEM, SLAVE_USB3, SLAVE_OCIMEM, SNOC_BIMC_SLV, SNOC_PNOC_SLV);
+DEFINE_QNODE(mas_snoc_cfg, MASTER_SNOC_CFG, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, 20, -1, 1, SLAVE_SERVICE_SNOC);
+DEFINE_QNODE(mas_bimc_snoc_0, BIMC_SNOC_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, 21, -1, 9, SLAVE_SNOC_VMEM, SLAVE_USB3, SLAVE_PIMEM, SLAVE_LPASS, SLAVE_APPSS, SNOC_CNOC_SLV, SNOC_PNOC_SLV, SLAVE_OCIMEM, SLAVE_QDSS_STM);
+DEFINE_QNODE(mas_bimc_snoc_1, BIMC_SNOC_1_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, 109, -1, 3, SLAVE_PCIE_2, SLAVE_PCIE_1, SLAVE_PCIE_0);
+DEFINE_QNODE(mas_a0noc_snoc, A0NOC_SNOC_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, 110, -1, 5, SNOC_PNOC_SLV, SLAVE_OCIMEM, SLAVE_APPSS, SNOC_BIMC_SLV, SLAVE_PIMEM);
+DEFINE_QNODE(mas_a1noc_snoc, A1NOC_SNOC_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, 111, -1, 13, SLAVE_SNOC_VMEM, SLAVE_USB3, SLAVE_PCIE_0, SLAVE_PIMEM, SLAVE_PCIE_2, SLAVE_LPASS, SLAVE_PCIE_1, SLAVE_APPSS, SNOC_BIMC_SLV, SNOC_CNOC_SLV, SNOC_PNOC_SLV, SLAVE_OCIMEM, SLAVE_QDSS_STM);
+DEFINE_QNODE(mas_a2noc_snoc, A2NOC_SNOC_MAS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, 112, -1, 12, SLAVE_SNOC_VMEM, SLAVE_USB3, SLAVE_PCIE_1, SLAVE_PIMEM, SLAVE_PCIE_2, SLAVE_QDSS_STM, SLAVE_LPASS, SNOC_BIMC_SLV, SNOC_CNOC_SLV, SNOC_PNOC_SLV, SLAVE_OCIMEM, SLAVE_PCIE_0);
+DEFINE_QNODE(mas_qdss_etr, MASTER_QDSS_ETR, 3, 1, 16, QCOM_QOS_MODE_FIXED, 1, 31, -1, 5, SLAVE_PIMEM, SLAVE_USB3, SLAVE_OCIMEM, SNOC_BIMC_SLV, SNOC_PNOC_SLV);
+DEFINE_QNODE(slv_a0noc_snoc, A0NOC_SNOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 141, 1, A0NOC_SNOC_MAS);
+DEFINE_QNODE(slv_a1noc_snoc, A1NOC_SNOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 0, -1, 142, 1, A1NOC_SNOC_MAS);
+DEFINE_QNODE(slv_a2noc_snoc, A2NOC_SNOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 0, -1, 143, 1, A2NOC_SNOC_MAS);
+DEFINE_QNODE(slv_ebi, SLAVE_EBI_CH0, 0, 2, 8, QCOM_QOS_MODE_FIXED, 0, -1, 0, 0, 0);
+DEFINE_QNODE(slv_hmss_l3, SLAVE_HMSS_L3, 0, 1, 8, QCOM_QOS_MODE_FIXED, 0, -1, 160, 0, 0);
+DEFINE_QNODE(slv_bimc_snoc_0, BIMC_SNOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 2, 1, BIMC_SNOC_MAS);
+DEFINE_QNODE(slv_bimc_snoc_1, BIMC_SNOC_1_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 138, 1, BIMC_SNOC_1_MAS);
+DEFINE_QNODE(slv_cnoc_a1noc, CNOC_SNOC_SLV, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 75, 1, CNOC_A1NOC_MAS);
+DEFINE_QNODE(slv_clk_ctl, SLAVE_CLK_CTL, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 47, 0, 0);
+DEFINE_QNODE(slv_tcsr, SLAVE_TCSR, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 50, 0, 0);
+DEFINE_QNODE(slv_tlmm, SLAVE_TLMM, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 51, 0, 0);
+DEFINE_QNODE(slv_crypto0_cfg, SLAVE_CRYPTO_0_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 52, 0, 0);
+DEFINE_QNODE(slv_mpm, SLAVE_MPM, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 62, 0, 0);
+DEFINE_QNODE(slv_pimem_cfg, SLAVE_PIMEM_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 167, 0, 0);
+DEFINE_QNODE(slv_imem_cfg, SLAVE_IMEM_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 54, 0, 0);
+DEFINE_QNODE(slv_message_ram, SLAVE_MESSAGE_RAM, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 55, 0, 0);
+DEFINE_QNODE(slv_bimc_cfg, SLAVE_BIMC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 56, 0, 0);
+DEFINE_QNODE(slv_pmic_arb, SLAVE_PMIC_ARB, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 59, 0, 0);
+DEFINE_QNODE(slv_prng, SLAVE_PRNG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 44, 0, 0);
+DEFINE_QNODE(slv_dcc_cfg, SLAVE_DCC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 155, 0, 0);
+DEFINE_QNODE(slv_rbcpr_mx, SLAVE_RBCPR_MX, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 170, 0, 0);
+DEFINE_QNODE(slv_qdss_cfg, SLAVE_QDSS_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 63, 0, 0);
+DEFINE_QNODE(slv_rbcpr_cx, SLAVE_RBCPR_CX, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 169, 0, 0);
+DEFINE_QNODE(slv_cpr_apu_cfg, SLAVE_QDSS_RBCPR_APU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 168, 0, 0);
+DEFINE_QNODE(slv_cnoc_mnoc_cfg, SLAVE_CNOC_MNOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 66, 1, MASTER_CNOC_MNOC_CFG);
+DEFINE_QNODE(slv_snoc_cfg, SLAVE_SNOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 70, 0, 0);
+DEFINE_QNODE(slv_snoc_mpu_cfg, SLAVE_SNOC_MPU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 67, 0, 0);
+DEFINE_QNODE(slv_ebi1_phy_cfg, SLAVE_EBI1_PHY_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 73, 0, 0);
+DEFINE_QNODE(slv_a0noc_cfg, SLAVE_A0NOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 144, 0, 0);
+DEFINE_QNODE(slv_pcie_1_cfg, SLAVE_PCIE_1_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 89, 0, 0);
+DEFINE_QNODE(slv_pcie_2_cfg, SLAVE_PCIE_2_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 165, 0, 0);
+DEFINE_QNODE(slv_pcie_0_cfg, SLAVE_PCIE_0_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 88, 0, 0);
+DEFINE_QNODE(slv_pcie20_ahb2phy, SLAVE_PCIE20_AHB2PHY, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 163, 0, 0);
+DEFINE_QNODE(slv_a0noc_mpu_cfg, SLAVE_A0NOC_MPU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 145, 0, 0);
+DEFINE_QNODE(slv_ufs_cfg, SLAVE_UFS_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 92, 0, 0);
+DEFINE_QNODE(slv_a1noc_cfg, SLAVE_A1NOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 147, 0, 0);
+DEFINE_QNODE(slv_a1noc_mpu_cfg, SLAVE_A1NOC_MPU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 148, 0, 0);
+DEFINE_QNODE(slv_a2noc_cfg, SLAVE_A2NOC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 150, 0, 0);
+DEFINE_QNODE(slv_a2noc_mpu_cfg, SLAVE_A2NOC_MPU_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 151, 0, 0);
+DEFINE_QNODE(slv_ssc_cfg, SLAVE_SSC_CFG, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 177, 0, 0);
+DEFINE_QNODE(slv_a0noc_smmu_cfg, SLAVE_A0NOC_SMMU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 146, 0, 0);
+DEFINE_QNODE(slv_a1noc_smmu_cfg, SLAVE_A1NOC_SMMU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 149, 0, 0);
+DEFINE_QNODE(slv_a2noc_smmu_cfg, SLAVE_A2NOC_SMMU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 152, 0, 0);
+DEFINE_QNODE(slv_lpass_smmu_cfg, SLAVE_LPASS_SMMU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 161, 0, 0);
+DEFINE_QNODE(slv_cnoc_mnoc_mmss_cfg, SLAVE_CNOC_MNOC_MMSS_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 58, 1, MASTER_CNOC_MNOC_MMSS_CFG);
+DEFINE_QNODE(slv_mmagic_cfg, SLAVE_MMAGIC_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 162, 0, 0);
+DEFINE_QNODE(slv_cpr_cfg, SLAVE_CPR_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 6, 0, 0);
+DEFINE_QNODE(slv_misc_cfg, SLAVE_MISC_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 8, 0, 0);
+DEFINE_QNODE(slv_venus_throttle_cfg, SLAVE_VENUS_THROTTLE_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 178, 0, 0);
+DEFINE_QNODE(slv_venus_cfg, SLAVE_VENUS_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 10, 0, 0);
+DEFINE_QNODE(slv_vmem_cfg, SLAVE_VMEM_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 180, 0, 0);
+DEFINE_QNODE(slv_dsa_cfg, SLAVE_DSA_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 157, 0, 0);
+DEFINE_QNODE(slv_mnoc_clocks_cfg, SLAVE_MMSS_CLK_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 12, 0, 0);
+DEFINE_QNODE(slv_dsa_mpu_cfg, SLAVE_DSA_MPU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 158, 0, 0);
+DEFINE_QNODE(slv_mnoc_mpu_cfg, SLAVE_MNOC_MPU_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 14, 0, 0);
+DEFINE_QNODE(slv_display_cfg, SLAVE_DISPLAY_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 4, 0, 0);
+DEFINE_QNODE(slv_display_throttle_cfg, SLAVE_DISPLAY_THROTTLE_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 156, 0, 0);
+DEFINE_QNODE(slv_camera_cfg, SLAVE_CAMERA_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 3, 0, 0);
+DEFINE_QNODE(slv_camera_throttle_cfg, SLAVE_CAMERA_THROTTLE_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 154, 0, 0);
+DEFINE_QNODE(slv_oxili_cfg, SLAVE_GRAPHICS_3D_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 11, 0, 0);
+DEFINE_QNODE(slv_smmu_mdp_cfg, SLAVE_SMMU_MDP_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 173, 0, 0);
+DEFINE_QNODE(slv_smmu_rot_cfg, SLAVE_SMMU_ROTATOR_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 174, 0, 0);
+DEFINE_QNODE(slv_smmu_venus_cfg, SLAVE_SMMU_VENUS_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 175, 0, 0);
+DEFINE_QNODE(slv_smmu_cpp_cfg, SLAVE_SMMU_CPP_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 171, 0, 0);
+DEFINE_QNODE(slv_smmu_jpeg_cfg, SLAVE_SMMU_JPEG_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 172, 0, 0);
+DEFINE_QNODE(slv_smmu_vfe_cfg, SLAVE_SMMU_VFE_CFG, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 176, 0, 0);
+DEFINE_QNODE(slv_mnoc_bimc, MNOC_BIMC_SLV, 0, 2, 32, QCOM_QOS_MODE_FIXED, 1, -1, 16, 1, MNOC_BIMC_MAS);
+DEFINE_QNODE(slv_vmem, SLAVE_VMEM, 0, 1, 32, QCOM_QOS_MODE_FIXED, 1, -1, 179, 0, 0);
+DEFINE_QNODE(slv_srvc_mnoc, SLAVE_SERVICE_MNOC, 0, 1, 8, QCOM_QOS_MODE_FIXED, 1, -1, 17, 0, 0);
+DEFINE_QNODE(slv_pnoc_a1noc, PNOC_A1NOC_SLV, 0, 1, 8, QCOM_QOS_MODE_FIXED, 0, -1, 139, 1, PNOC_A1NOC_MAS);
+DEFINE_QNODE(slv_usb_hs, SLAVE_USB_HS, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 40, 0, 0);
+DEFINE_QNODE(slv_sdcc_2, SLAVE_SDCC_2, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 33, 0, 0);
+DEFINE_QNODE(slv_sdcc_4, SLAVE_SDCC_4, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 34, 0, 0);
+DEFINE_QNODE(slv_tsif, SLAVE_TSIF, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 35, 0, 0);
+DEFINE_QNODE(slv_blsp_2, SLAVE_BLSP_2, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 37, 0, 0);
+DEFINE_QNODE(slv_sdcc_1, SLAVE_SDCC_1, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 31, 0, 0);
+DEFINE_QNODE(slv_blsp_1, SLAVE_BLSP_1, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 39, 0, 0);
+DEFINE_QNODE(slv_pdm, SLAVE_PDM, 0, 1, 4, QCOM_QOS_MODE_FIXED, 0, -1, 41, 0, 0);
+DEFINE_QNODE(slv_ahb2phy, SLAVE_AHB2PHY, 0, 1, 4, QCOM_QOS_MODE_FIXED, 1, -1, 153, 0, 0);
+DEFINE_QNODE(slv_hmss, SLAVE_APPSS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 20, 0, 0);
+DEFINE_QNODE(slv_lpass, SLAVE_LPASS, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 21, 0, 0);
+DEFINE_QNODE(slv_usb3, SLAVE_USB3, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 22, 0, 0);
+DEFINE_QNODE(slv_snoc_bimc, SNOC_BIMC_SLV, 0, 2, 32, QCOM_QOS_MODE_FIXED, 0, -1, 24, 1, SNOC_BIMC_MAS);
+DEFINE_QNODE(slv_snoc_cnoc, SNOC_CNOC_SLV, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 25, 1, SNOC_CNOC_MAS);
+DEFINE_QNODE(slv_imem, SLAVE_OCIMEM, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 26, 0, 0);
+DEFINE_QNODE(slv_pimem, SLAVE_PIMEM, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 166, 0, 0);
+DEFINE_QNODE(slv_snoc_vmem, SLAVE_SNOC_VMEM, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 140, 1, MASTER_SNOC_VMEM);
+DEFINE_QNODE(slv_snoc_pnoc, SNOC_PNOC_SLV, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 28, 1, SNOC_PNOC_MAS);
+DEFINE_QNODE(slv_qdss_stm, SLAVE_QDSS_STM, 0, 1, 16, QCOM_QOS_MODE_FIXED, 0, -1, 30, 0, 0);
+DEFINE_QNODE(slv_pcie_0, SLAVE_PCIE_0, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 84, 0, 0);
+DEFINE_QNODE(slv_pcie_1, SLAVE_PCIE_1, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 85, 0, 0);
+DEFINE_QNODE(slv_pcie_2, SLAVE_PCIE_2, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 164, 0, 0);
+DEFINE_QNODE(slv_srvc_snoc, SLAVE_SERVICE_SNOC, 0, 1, 16, QCOM_QOS_MODE_FIXED, 1, -1, 29, 0, 0);
+
+static struct qcom_icc_node *msm8996_snoc_nodes[] = {
+ &mas_hmss,
+ &mas_qdss_bam,
+ &mas_snoc_cfg,
+ &mas_bimc_snoc_0,
+ &mas_bimc_snoc_1,
+ &mas_a0noc_snoc,
+ &mas_a1noc_snoc,
+ &mas_a2noc_snoc,
+ &mas_qdss_etr,
+ &slv_a0noc_snoc,
+ &slv_a1noc_snoc,
+ &slv_a2noc_snoc,
+ &slv_hmss,
+ &slv_lpass,
+ &slv_usb3,
+ &slv_snoc_bimc,
+ &slv_snoc_cnoc,
+ &slv_imem,
+ &slv_pimem,
+ &slv_snoc_vmem,
+ &slv_snoc_pnoc,
+ &slv_qdss_stm,
+ &slv_pcie_0,
+ &slv_pcie_1,
+ &slv_pcie_2,
+ &slv_srvc_snoc,
+};
+
+static struct qcom_icc_desc msm8996_snoc = {
+ .nodes = msm8996_snoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_snoc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_bimc_nodes[] = {
+ &mas_apps_proc,
+ &mas_oxili,
+ &mas_mnoc_bimc,
+ &mas_snoc_bimc,
+ &slv_ebi,
+ &slv_hmss_l3,
+ &slv_bimc_snoc_0,
+ &slv_bimc_snoc_1,
+};
+
+static struct qcom_icc_desc msm8996_bimc = {
+ .nodes = msm8996_bimc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_bimc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_pnoc_nodes[] = {
+ &mas_snoc_pnoc,
+ &mas_sdcc_1,
+ &mas_sdcc_2,
+ &mas_sdcc_4,
+ &mas_usb_hs,
+ &mas_blsp_1,
+ &mas_blsp_2,
+ &mas_tsif,
+ &slv_pnoc_a1noc,
+ &slv_usb_hs,
+ &slv_sdcc_2,
+ &slv_sdcc_4,
+ &slv_tsif,
+ &slv_blsp_2,
+ &slv_sdcc_1,
+ &slv_blsp_1,
+ &slv_pdm,
+ &slv_ahb2phy,
+};
+
+static struct qcom_icc_desc msm8996_pnoc = {
+ .nodes = msm8996_pnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_pnoc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_cnoc_nodes[] = {
+ &mas_snoc_cnoc,
+ &mas_qdss_dap,
+ &slv_cnoc_a1noc,
+ &slv_clk_ctl,
+ &slv_tcsr,
+ &slv_tlmm,
+ &slv_crypto0_cfg,
+ &slv_mpm,
+ &slv_pimem_cfg,
+ &slv_imem_cfg,
+ &slv_message_ram,
+ &slv_bimc_cfg,
+ &slv_pmic_arb,
+ &slv_prng,
+ &slv_dcc_cfg,
+ &slv_rbcpr_mx,
+ &slv_qdss_cfg,
+ &slv_rbcpr_cx,
+ &slv_cpr_apu_cfg,
+ &slv_cnoc_mnoc_cfg,
+ &slv_snoc_cfg,
+ &slv_snoc_mpu_cfg,
+ &slv_ebi1_phy_cfg,
+ &slv_a0noc_cfg,
+ &slv_pcie_1_cfg,
+ &slv_pcie_2_cfg,
+ &slv_pcie_0_cfg,
+ &slv_pcie20_ahb2phy,
+ &slv_a0noc_mpu_cfg,
+ &slv_ufs_cfg,
+ &slv_a1noc_cfg,
+ &slv_a1noc_mpu_cfg,
+ &slv_a2noc_cfg,
+ &slv_a2noc_mpu_cfg,
+ &slv_ssc_cfg,
+ &slv_a0noc_smmu_cfg,
+ &slv_a1noc_smmu_cfg,
+ &slv_a2noc_smmu_cfg,
+ &slv_lpass_smmu_cfg,
+ &slv_cnoc_mnoc_mmss_cfg,
+};
+
+static struct qcom_icc_desc msm8996_cnoc = {
+ .nodes = msm8996_cnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_cnoc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_mnoc_nodes[] = {
+ &mas_cnoc_mnoc_mmss_cfg,
+ &mas_cnoc_mnoc_cfg,
+ &mas_cpp,
+ &mas_jpeg,
+ &mas_mdp_p0,
+ &mas_mdp_p1,
+ &mas_rotator,
+ &mas_venus,
+ &mas_vfe,
+ &mas_snoc_vmem,
+ &mas_venus_vmem,
+ &slv_mmagic_cfg,
+ &slv_cpr_cfg,
+ &slv_misc_cfg,
+ &slv_venus_throttle_cfg,
+ &slv_venus_cfg,
+ &slv_vmem_cfg,
+ &slv_dsa_cfg,
+ &slv_mnoc_clocks_cfg,
+ &slv_dsa_mpu_cfg,
+ &slv_mnoc_mpu_cfg,
+ &slv_display_cfg,
+ &slv_display_throttle_cfg,
+ &slv_camera_cfg,
+ &slv_camera_throttle_cfg,
+ &slv_oxili_cfg,
+ &slv_smmu_mdp_cfg,
+ &slv_smmu_rot_cfg,
+ &slv_smmu_venus_cfg,
+ &slv_smmu_cpp_cfg,
+ &slv_smmu_jpeg_cfg,
+ &slv_smmu_vfe_cfg,
+ &slv_mnoc_bimc,
+ &slv_vmem,
+ &slv_srvc_mnoc,
+};
+
+static struct qcom_icc_desc msm8996_mnoc = {
+ .nodes = msm8996_mnoc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_mnoc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_a0noc_nodes[] = {
+ &mas_pcie_0,
+ &mas_pcie_1,
+ &mas_pcie_2,
+};
+
+static struct qcom_icc_desc msm8996_a0noc = {
+ .nodes = msm8996_a0noc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_a0noc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_a1noc_nodes[] = {
+ &mas_cnoc_a1noc,
+ &mas_crypto_c0,
+ &mas_pnoc_a1noc,
+};
+
+static struct qcom_icc_desc msm8996_a1noc = {
+ .nodes = msm8996_a1noc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_a1noc_nodes),
+};
+
+static struct qcom_icc_node *msm8996_a2noc_nodes[] = {
+ &mas_usb3,
+ &mas_ipa,
+ &mas_ufs,
+};
+
+static struct qcom_icc_desc msm8996_a2noc = {
+ .nodes = msm8996_a2noc_nodes,
+ .num_nodes = ARRAY_SIZE(msm8996_a2noc_nodes),
+};
+
+static int qcom_icc_aggregate(struct icc_node *node, u32 avg_bw, u32 peak_bw,
+ u32 *agg_avg, u32 *agg_peak)
+{
+ *agg_avg += avg_bw;
+ *agg_peak = max(*agg_peak, peak_bw);
+
+ return 0;
+}
+
+static int qcom_icc_set(struct icc_node *src, struct icc_node *dst,
+ u32 avg, u32 peak)
+{
+ struct qcom_icc_provider *qp;
+ struct qcom_icc_node *qn;
+ struct icc_node *node;
+ struct icc_provider *provider;
+ u64 avg_bw = icc_units_to_bps(avg);
+ u64 peak_bw = icc_units_to_bps(peak);
+ int ret = 0;
+ u64 rate;
+
+ if (!src)
+ node = dst;
+ else
+ node = src;
+
+ qn = node->data;
+ provider = node->provider;
+ qp = to_qcom_provider(provider);
+
+ /* set bandwidth */
+ if (qn->ap_owned) {
+ /* TODO: set QoS */
+ } else {
+ /* send message to the RPM processor */
+
+ if (qn->mas_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_MASTER_REQ,
+ qn->mas_rpm_id,
+ avg_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send mas error %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ if (qn->slv_rpm_id != -1) {
+ ret = qcom_icc_rpm_smd_send(QCOM_SMD_RPM_ACTIVE_STATE,
+ RPM_BUS_SLAVE_REQ,
+ qn->slv_rpm_id,
+ avg_bw);
+ if (ret) {
+ pr_err("qcom_icc_rpm_smd_send slv error %d\n",
+ ret);
+ return ret;
+ }
+ }
+ }
+
+ rate = max(avg_bw, peak_bw);
+
+ do_div(rate, qn->buswidth);
+
+ if (qn->rate != rate) {
+ ret = clk_set_rate(qp->bus_clk, rate);
+ if (ret) {
+ pr_err("set clk rate %lld error %d\n", rate, ret);
+ return ret;
+ }
+
+ ret = clk_set_rate(qp->bus_a_clk, rate);
+ if (ret) {
+ pr_err("set clk rate %lld error %d\n", rate, ret);
+ return ret;
+ }
+
+ qn->rate = rate;
+ }
+
+ return ret;
+}
+
+static int qnoc_probe(struct platform_device *pdev)
+{
+ const struct qcom_icc_desc *desc;
+ struct qcom_icc_node **qnodes;
+ struct icc_node *node;
+ struct qcom_icc_provider *qp;
+ struct resource *res;
+ struct icc_provider *provider;
+ size_t num_nodes, i;
+ int ret;
+
+ /* wait for RPM */
+ if (!qcom_icc_rpm_smd_available())
+ return -EPROBE_DEFER;
+
+ desc = of_device_get_match_data(&pdev->dev);
+ if (!desc)
+ return -EINVAL;
+
+ qnodes = desc->nodes;
+ num_nodes = desc->num_nodes;
+
+ qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
+ if (!qp)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ qp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(qp->base))
+ return PTR_ERR(qp->base);
+
+ qp->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+ if (IS_ERR(qp->bus_clk))
+ return PTR_ERR(qp->bus_clk);
+
+ ret = clk_prepare_enable(qp->bus_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "error enabling bus_clk: %d\n", ret);
+ return ret;
+ }
+
+ qp->bus_a_clk = devm_clk_get(&pdev->dev, "bus_a_clk");
+ if (IS_ERR(qp->bus_a_clk))
+ return PTR_ERR(qp->bus_a_clk);
+
+ ret = clk_prepare_enable(qp->bus_a_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "error enabling bus_a_clk: %d\n", ret);
+ clk_disable_unprepare(qp->bus_clk);
+ return ret;
+ }
+
+ provider = &qp->provider;
+ provider->dev = &pdev->dev;
+ provider->set = &qcom_icc_set;
+ provider->aggregate = &qcom_icc_aggregate;
+ INIT_LIST_HEAD(&provider->nodes);
+ provider->data = qp;
+
+ ret = icc_provider_add(provider);
+ if (ret) {
+ dev_err(&pdev->dev, "error adding interconnect provider\n");
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+ return ret;
+ }
+
+ for (i = 0; i < num_nodes; i++) {
+ int ret;
+ size_t j;
+
+ node = icc_node_create(qnodes[i]->id);
+ if (IS_ERR(node)) {
+ ret = PTR_ERR(node);
+ goto err;
+ }
+ node->name = qnodes[i]->name;
+ node->data = qnodes[i];
+ icc_node_add(node, provider);
+
+ dev_dbg(&pdev->dev, "registered node %s\n", node->name);
+
+ /* populate links */
+ for (j = 0; j < qnodes[i]->num_links; j++)
+ if (qnodes[i]->links[j])
+ icc_link_create(node, qnodes[i]->links[j]);
+ }
+
+ platform_set_drvdata(pdev, provider);
+
+ return ret;
+err:
+ list_for_each_entry(node, &provider->nodes, node_list) {
+ icc_node_del(node);
+ icc_node_destroy(node->id);
+ }
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+ icc_provider_del(provider);
+
+ return ret;
+}
+
+static int qnoc_remove(struct platform_device *pdev)
+{
+ struct icc_provider *provider = platform_get_drvdata(pdev);
+ struct qcom_icc_provider *qp = to_qcom_provider(provider);
+ struct icc_node *n;
+
+ list_for_each_entry(n, &provider->nodes, node_list) {
+ icc_node_del(n);
+ icc_node_destroy(n->id);
+ }
+ clk_disable_unprepare(qp->bus_clk);
+ clk_disable_unprepare(qp->bus_a_clk);
+
+ return icc_provider_del(provider);
+}
+
+static const struct of_device_id qnoc_of_match[] = {
+ { .compatible = "qcom,msm8996-bimc", .data = &msm8996_bimc },
+ { .compatible = "qcom,msm8996-cnoc", .data = &msm8996_cnoc },
+ { .compatible = "qcom,msm8996-snoc", .data = &msm8996_snoc },
+ { .compatible = "qcom,msm8996-a0noc", .data = &msm8996_a0noc },
+ { .compatible = "qcom,msm8996-a1noc", .data = &msm8996_a1noc },
+ { .compatible = "qcom,msm8996-a2noc", .data = &msm8996_a2noc },
+ { .compatible = "qcom,msm8996-mmnoc", .data = &msm8996_mnoc },
+ { .compatible = "qcom,msm8996-pnoc", .data = &msm8996_pnoc },
+ { },
+};
+MODULE_DEVICE_TABLE(of, qnoc_of_match);
+
+static struct platform_driver qnoc_driver = {
+ .probe = qnoc_probe,
+ .remove = qnoc_remove,
+ .driver = {
+ .name = "qnoc-msm8996",
+ .of_match_table = qnoc_of_match,
+ },
+};
+module_platform_driver(qnoc_driver);
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm msm8996 NoC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/smd-rpm.c b/drivers/interconnect/qcom/smd-rpm.c
new file mode 100644
index 000000000000..48b7a2a6eb84
--- /dev/null
+++ b/drivers/interconnect/qcom/smd-rpm.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RPM over SMD communication wrapper for interconnects
+ *
+ * Copyright (C) 2018 Linaro Ltd
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#include <linux/interconnect-provider.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/soc/qcom/smd-rpm.h>
+#include "smd-rpm.h"
+
+#define RPM_KEY_BW 0x00007762
+
+static struct qcom_icc_rpm {
+ struct qcom_smd_rpm *rpm;
+} icc_rpm_smd;
+
+struct icc_rpm_smd_req {
+ __le32 key;
+ __le32 nbytes;
+ __le32 value;
+};
+
+bool qcom_icc_rpm_smd_available(void)
+{
+ if (!icc_rpm_smd.rpm)
+ return false;
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_available);
+
+int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val)
+{
+ struct icc_rpm_smd_req req = {
+ .key = cpu_to_le32(RPM_KEY_BW),
+ .nbytes = cpu_to_le32(sizeof(u32)),
+ .value = cpu_to_le32(val),
+ };
+
+ return qcom_rpm_smd_write(icc_rpm_smd.rpm, ctx, rsc_type, id, &req,
+ sizeof(req));
+}
+EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_send);
+
+static int qcom_icc_rpm_smd_probe(struct platform_device *pdev)
+{
+ icc_rpm_smd.rpm = dev_get_drvdata(pdev->dev.parent);
+ if (!icc_rpm_smd.rpm) {
+ dev_err(&pdev->dev, "unable to retrieve handle to RPM\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id qcom_icc_rpm_smd_dt_match[] = {
+ { .compatible = "qcom,interconnect-smd-rpm", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, qcom_icc_rpm_smd_dt_match);
+
+static struct platform_driver qcom_interconnect_rpm_smd_driver = {
+ .driver = {
+ .name = "qcom-interconnect-smd-rpm",
+ .of_match_table = qcom_icc_rpm_smd_dt_match,
+ },
+ .probe = qcom_icc_rpm_smd_probe,
+};
+
+static int __init rpm_smd_interconnect_init(void)
+{
+ return platform_driver_register(&qcom_interconnect_rpm_smd_driver);
+}
+subsys_initcall(rpm_smd_interconnect_init);
+
+static void __exit rpm_smd_interconnect_exit(void)
+{
+ platform_driver_unregister(&qcom_interconnect_rpm_smd_driver);
+}
+module_exit(rpm_smd_interconnect_exit)
+
+MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm SMD RPM interconnect driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/interconnect/qcom/smd-rpm.h b/drivers/interconnect/qcom/smd-rpm.h
new file mode 100644
index 000000000000..c33b91a3dd51
--- /dev/null
+++ b/drivers/interconnect/qcom/smd-rpm.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef __DRIVERS_INTERCONNECT_QCOM_RPM_H
+#define __DRIVERS_INTERCONNECT_QCOM_RPM_H
+
+#include <linux/soc/qcom/smd-rpm.h>
+
+bool qcom_icc_rpm_smd_available(void);
+int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val);
+
+#endif
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index f7a96bcf94a6..23c01304e57a 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -48,6 +48,7 @@
#include <linux/of_iommu.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
@@ -118,6 +119,7 @@ enum arm_smmu_implementation {
GENERIC_SMMU,
ARM_MMU500,
CAVIUM_SMMUV2,
+ QCOM_SMMUV2,
};
struct arm_smmu_s2cr {
@@ -205,6 +207,8 @@ struct arm_smmu_device {
u32 num_global_irqs;
u32 num_context_irqs;
unsigned int *irqs;
+ struct clk_bulk_data *clks;
+ int num_clks;
u32 cavium_id_base; /* Specific to Cavium */
@@ -265,6 +269,20 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
{ 0, NULL},
};
+static inline int arm_smmu_rpm_get(struct arm_smmu_device *smmu)
+{
+ if (pm_runtime_enabled(smmu->dev))
+ return pm_runtime_get_sync(smmu->dev);
+
+ return 0;
+}
+
+static inline void arm_smmu_rpm_put(struct arm_smmu_device *smmu)
+{
+ if (pm_runtime_enabled(smmu->dev))
+ pm_runtime_put(smmu->dev);
+}
+
static struct arm_smmu_domain *to_smmu_domain(struct iommu_domain *dom)
{
return container_of(dom, struct arm_smmu_domain, domain);
@@ -910,11 +928,15 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
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;
- int irq;
+ int ret, irq;
if (!smmu || domain->type == IOMMU_DOMAIN_IDENTITY)
return;
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret < 0)
+ return;
+
/*
* Disable the context bank and free the page tables before freeing
* it.
@@ -929,6 +951,8 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
free_io_pgtable_ops(smmu_domain->pgtbl_ops);
__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
+
+ arm_smmu_rpm_put(smmu);
}
static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
@@ -1210,10 +1234,15 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
return -ENODEV;
smmu = fwspec_smmu(fwspec);
+
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret < 0)
+ return ret;
+
/* Ensure that the domain is finalised */
ret = arm_smmu_init_domain_context(domain, smmu);
if (ret < 0)
- return ret;
+ goto rpm_put;
/*
* Sanity check the domain. We don't support domains across
@@ -1223,33 +1252,50 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
dev_err(dev,
"cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n",
dev_name(smmu_domain->smmu->dev), dev_name(smmu->dev));
- return -EINVAL;
+ ret = -EINVAL;
+ goto rpm_put;
}
/* Looks ok, so add the device to the domain */
- return arm_smmu_domain_add_master(smmu_domain, fwspec);
+ ret = arm_smmu_domain_add_master(smmu_domain, fwspec);
+
+rpm_put:
+ arm_smmu_rpm_put(smmu);
+ return ret;
}
static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot)
{
struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
+ struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
+ int ret;
if (!ops)
return -ENODEV;
- return ops->map(ops, iova, paddr, size, prot);
+ arm_smmu_rpm_get(smmu);
+ ret = ops->map(ops, iova, paddr, size, prot);
+ arm_smmu_rpm_put(smmu);
+
+ return ret;
}
static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size)
{
struct io_pgtable_ops *ops = to_smmu_domain(domain)->pgtbl_ops;
+ struct arm_smmu_device *smmu = to_smmu_domain(domain)->smmu;
+ size_t ret;
if (!ops)
return 0;
- return ops->unmap(ops, iova, size);
+ arm_smmu_rpm_get(smmu);
+ ret = ops->unmap(ops, iova, size);
+ arm_smmu_rpm_put(smmu);
+
+ return ret;
}
static void arm_smmu_iotlb_sync(struct iommu_domain *domain)
@@ -1404,14 +1450,32 @@ static int arm_smmu_add_device(struct device *dev)
while (i--)
cfg->smendx[i] = INVALID_SMENDX;
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret < 0)
+ goto out_cfg_free;
+
ret = arm_smmu_master_alloc_smes(dev);
+ arm_smmu_rpm_put(smmu);
+
if (ret)
goto out_cfg_free;
iommu_device_link(&smmu->iommu, dev);
+ if (pm_runtime_enabled(smmu->dev) &&
+ !device_link_add(dev, smmu->dev,
+ DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_S)) {
+ dev_err(smmu->dev, "Unable to add link to the consumer %s\n",
+ dev_name(dev));
+ ret = -ENODEV;
+ goto out_unlink;
+ }
+
return 0;
+out_unlink:
+ iommu_device_unlink(&smmu->iommu, dev);
+ arm_smmu_master_free_smes(fwspec);
out_cfg_free:
kfree(cfg);
out_free:
@@ -1424,7 +1488,7 @@ static void arm_smmu_remove_device(struct device *dev)
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
struct arm_smmu_master_cfg *cfg;
struct arm_smmu_device *smmu;
-
+ int ret;
if (!fwspec || fwspec->ops != &arm_smmu_ops)
return;
@@ -1432,8 +1496,15 @@ static void arm_smmu_remove_device(struct device *dev)
cfg = fwspec->iommu_priv;
smmu = cfg->smmu;
+ ret = arm_smmu_rpm_get(smmu);
+ if (ret < 0)
+ return;
+
iommu_device_unlink(&smmu->iommu, dev);
arm_smmu_master_free_smes(fwspec);
+
+ arm_smmu_rpm_put(smmu);
+
iommu_group_remove_device(dev);
kfree(fwspec->iommu_priv);
iommu_fwspec_free(dev);
@@ -1897,10 +1968,12 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
struct arm_smmu_match_data {
enum arm_smmu_arch_version version;
enum arm_smmu_implementation model;
+ const char * const *clks;
+ int num_clks;
};
#define ARM_SMMU_MATCH_DATA(name, ver, imp) \
-static struct arm_smmu_match_data name = { .version = ver, .model = imp }
+static const struct arm_smmu_match_data name = { .version = ver, .model = imp }
ARM_SMMU_MATCH_DATA(smmu_generic_v1, ARM_SMMU_V1, GENERIC_SMMU);
ARM_SMMU_MATCH_DATA(smmu_generic_v2, ARM_SMMU_V2, GENERIC_SMMU);
@@ -1908,6 +1981,17 @@ ARM_SMMU_MATCH_DATA(arm_mmu401, ARM_SMMU_V1_64K, GENERIC_SMMU);
ARM_SMMU_MATCH_DATA(arm_mmu500, ARM_SMMU_V2, ARM_MMU500);
ARM_SMMU_MATCH_DATA(cavium_smmuv2, ARM_SMMU_V2, CAVIUM_SMMUV2);
+static const char * const qcom_smmuv2_clks[] = {
+ "bus", "iface",
+};
+
+static const struct arm_smmu_match_data qcom_smmuv2 = {
+ .version = ARM_SMMU_V2,
+ .model = QCOM_SMMUV2,
+ .clks = qcom_smmuv2_clks,
+ .num_clks = ARRAY_SIZE(qcom_smmuv2_clks),
+};
+
static const struct of_device_id arm_smmu_of_match[] = {
{ .compatible = "arm,smmu-v1", .data = &smmu_generic_v1 },
{ .compatible = "arm,smmu-v2", .data = &smmu_generic_v2 },
@@ -1915,10 +1999,28 @@ static const struct of_device_id arm_smmu_of_match[] = {
{ .compatible = "arm,mmu-401", .data = &arm_mmu401 },
{ .compatible = "arm,mmu-500", .data = &arm_mmu500 },
{ .compatible = "cavium,smmu-v2", .data = &cavium_smmuv2 },
+ { .compatible = "qcom,smmu-v2", .data = &qcom_smmuv2 },
{ },
};
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);
+static void arm_smmu_fill_clk_data(struct arm_smmu_device *smmu,
+ const char * const *clks)
+{
+ int i;
+
+ if (smmu->num_clks < 1)
+ return;
+
+ smmu->clks = devm_kcalloc(smmu->dev, smmu->num_clks,
+ sizeof(*smmu->clks), GFP_KERNEL);
+ if (!smmu->clks)
+ return;
+
+ for (i = 0; i < smmu->num_clks; i++)
+ smmu->clks[i].id = clks[i];
+}
+
#ifdef CONFIG_ACPI
static int acpi_smmu_get_data(u32 model, struct arm_smmu_device *smmu)
{
@@ -2001,6 +2103,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev,
data = of_device_get_match_data(dev);
smmu->version = data->version;
smmu->model = data->model;
+ smmu->num_clks = data->num_clks;
+
+ arm_smmu_fill_clk_data(smmu, data->clks);
parse_driver_options(smmu);
@@ -2099,6 +2204,29 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
smmu->irqs[i] = irq;
}
+ platform_set_drvdata(pdev, smmu);
+
+ err = devm_clk_bulk_get(smmu->dev, smmu->num_clks, smmu->clks);
+ if (err)
+ return err;
+
+ err = clk_bulk_prepare(smmu->num_clks, smmu->clks);
+ if (err)
+ return err;
+
+ /*
+ * We want to avoid touching dev->power.lock in fastpaths unless
+ * it's really going to do something useful - pm_runtime_enabled()
+ * can serve as an ideal proxy for that decision. So, conditionally
+ * enable pm_runtime.
+ */
+ if (dev->pm_domain)
+ pm_runtime_enable(dev);
+
+ err = arm_smmu_rpm_get(smmu);
+ if (err < 0)
+ return err;
+
err = arm_smmu_device_cfg_probe(smmu);
if (err)
return err;
@@ -2140,10 +2268,11 @@ static int arm_smmu_device_probe(struct platform_device *pdev)
return err;
}
- platform_set_drvdata(pdev, smmu);
arm_smmu_device_reset(smmu);
arm_smmu_test_smr_masks(smmu);
+ arm_smmu_rpm_put(smmu);
+
/*
* For ACPI and generic DT bindings, an SMMU will be probed before
* any device which might need it, so we want the bus ops in place
@@ -2179,8 +2308,16 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
dev_err(&pdev->dev, "removing device with active domains!\n");
+ arm_smmu_rpm_get(smmu);
/* Turn the thing off */
writel(sCR0_CLIENTPD, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
+ arm_smmu_rpm_put(smmu);
+
+ if (pm_runtime_enabled(smmu->dev))
+ pm_runtime_disable(smmu->dev);
+
+ clk_bulk_unprepare(smmu->num_clks, smmu->clks);
+
return 0;
}
@@ -2197,7 +2334,27 @@ static int __maybe_unused arm_smmu_pm_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(arm_smmu_pm_ops, NULL, arm_smmu_pm_resume);
+static int __maybe_unused arm_smmu_runtime_resume(struct device *dev)
+{
+ struct arm_smmu_device *smmu = dev_get_drvdata(dev);
+
+ return clk_bulk_enable(smmu->num_clks, smmu->clks);
+}
+
+static int __maybe_unused arm_smmu_runtime_suspend(struct device *dev)
+{
+ struct arm_smmu_device *smmu = dev_get_drvdata(dev);
+
+ clk_bulk_disable(smmu->num_clks, smmu->clks);
+
+ return 0;
+}
+
+static const struct dev_pm_ops arm_smmu_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, arm_smmu_pm_resume)
+ SET_RUNTIME_PM_OPS(arm_smmu_runtime_suspend,
+ arm_smmu_runtime_resume, NULL)
+};
static struct platform_driver arm_smmu_driver = {
.driver = {
@@ -2217,6 +2374,7 @@ IOMMU_OF_DECLARE(arm_mmu400, "arm,mmu-400");
IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401");
IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500");
IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2");
+IOMMU_OF_DECLARE(qcom_smmuv2, "qcom,smmu-v2");
MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations");
MODULE_AUTHOR("Will Deacon <will.deacon@arm.com>");
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 76ea56d779a1..d3f6e3d92462 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -139,6 +139,11 @@ static void gic_enable_redist(bool enable)
u32 count = 1000000; /* 1s! */
u32 val;
+ /*
+ * on msm8996 access to GICR_WAKER is disabled
+ * This would need a proper fix in TZ firmware
+ */
+ return;
rbase = gic_data_rdist_rd_base();
val = readl_relaxed(rbase + GICR_WAKER);
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f1849775e47e..092483c65f1c 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -86,6 +86,7 @@ static unsigned int fmax = 515633;
* @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
+ * @any_blksize: true if block any sizes are supported
*/
struct variant_data {
unsigned int clkreg;
@@ -118,6 +119,7 @@ struct variant_data {
bool mmcimask1;
u32 start_err;
u32 opendrain;
+ bool any_blksize;
};
static struct variant_data variant_arm = {
@@ -242,6 +244,7 @@ static struct variant_data variant_ux500v2 = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .any_blksize = true,
};
static struct variant_data variant_stm32 = {
@@ -280,6 +283,7 @@ static struct variant_data variant_qcom = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .any_blksize = true,
};
/* Busy detection for the ST Micro variant */
@@ -303,10 +307,11 @@ static int mmci_card_busy(struct mmc_host *mmc)
static int mmci_validate_data(struct mmci_host *host,
struct mmc_data *data)
{
+ struct variant_data *variant = host->variant;
+
if (!data)
return 0;
-
- if (!is_power_of_2(data->blksz)) {
+ if (!is_power_of_2(data->blksz) && !variant->any_blksize) {
dev_err(mmc_dev(host->mmc),
"unsupported block size (%d bytes)\n", data->blksz);
return -EINVAL;
@@ -863,7 +868,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
writel(host->size, base + MMCIDATALENGTH);
blksz_bits = ffs(data->blksz) - 1;
- BUG_ON(1 << blksz_bits != data->blksz);
if (variant->blksz_datactrl16)
datactrl = MCI_DPSM_ENABLE | (data->blksz << 16);
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index 31ff03dbeb83..fbc4e4f15776 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -125,6 +125,27 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
+struct regulator *dev_pm_opp_get_regulator(struct device *dev)
+{
+ struct opp_table *opp_table;
+ struct regulator *reg;
+
+ rcu_read_lock();
+
+ opp_table = _find_opp_table(dev);
+ if (IS_ERR(opp_table)) {
+ rcu_read_unlock();
+ return ERR_CAST(opp_table);
+ }
+
+ reg = opp_table->regulators[0];
+
+ rcu_read_unlock();
+
+ return reg;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_regulator);
+
/**
* dev_pm_opp_is_turbo() - Returns if opp is turbo OPP or not
* @opp: opp for which turbo mode is being verified
@@ -1314,11 +1335,13 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
if (!opp_table)
return ERR_PTR(-ENOMEM);
+#if 0
/* This should be called before OPPs are initialized */
if (WARN_ON(!list_empty(&opp_table->opp_list))) {
ret = -EBUSY;
goto err;
}
+#endif
/* Another CPU that shares the OPP table has set the regulators ? */
if (opp_table->regulators)
@@ -1620,6 +1643,76 @@ put_table:
}
/**
+ * dev_pm_opp_adjust_voltage() - helper to change the voltage of an OPP
+ * @dev: device for which we do this operation
+ * @freq: OPP frequency to adjust voltage of
+ * @u_volt: new OPP voltage
+ *
+ * Change the voltage of an OPP with an RCU operation.
+ *
+ * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
+ * copy operation, returns 0 if no modifcation was done OR modification was
+ * successful.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks to
+ * keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex locking or synchronize_rcu() blocking calls cannot be used.
+ */
+int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
+ unsigned long u_volt)
+{
+ struct opp_table *opp_table;
+ struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV);
+ int r = 0;
+ unsigned long tol;
+
+ mutex_lock(&opp_table_lock);
+
+ /* Find the opp_table */
+ opp_table = _find_opp_table_unlocked(dev);
+ if (IS_ERR(opp_table)) {
+ r = PTR_ERR(opp_table);
+ dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
+ goto unlock;
+ }
+
+ /* Do we have the frequency? */
+ list_for_each_entry(tmp_opp, &opp_table->opp_list, node) {
+ if (tmp_opp->rate == freq) {
+ opp = tmp_opp;
+ break;
+ }
+ }
+ if (IS_ERR(opp)) {
+ r = PTR_ERR(opp);
+ goto unlock;
+ }
+
+ /* Is update really needed? */
+ if (opp->supplies[0].u_volt == u_volt)
+ goto unlock;
+
+ /* adjust voltage node */
+ tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
+ opp->supplies[0].u_volt = u_volt;
+ opp->supplies[0].u_volt_min = u_volt - tol;
+ opp->supplies[0].u_volt_max = u_volt + tol;
+
+ mutex_unlock(&opp_table_lock);
+
+ /* Notify the change of the OPP */
+ blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADJUST_VOLTAGE, opp);
+
+ return 0;
+
+unlock:
+ mutex_unlock(&opp_table_lock);
+ return r;
+}
+
+/**
* dev_pm_opp_enable() - Enable a specific OPP
* @dev: device for which we do this operation
* @freq: OPP frequency to enable
diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c
index 842135cf35a3..591877cacb7a 100644
--- a/drivers/perf/qcom_l2_pmu.c
+++ b/drivers/perf/qcom_l2_pmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
*
* This 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,7 +30,7 @@
#include <asm/barrier.h>
#include <asm/local64.h>
-#include <asm/sysreg.h>
+#include <soc/qcom/kryo-l2-accessors.h>
#define MAX_L2_CTRS 9
@@ -87,9 +87,6 @@
#define L2_COUNTER_RELOAD BIT_ULL(31)
#define L2_CYCLE_COUNTER_RELOAD BIT_ULL(63)
-#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
-#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
-
#define reg_idx(reg, i) (((i) * IA_L2_REG_OFFSET) + reg##_BASE)
/*
@@ -107,49 +104,6 @@
#define L2_EVENT_STREX 0x421
#define L2_EVENT_CLREX 0x422
-static DEFINE_RAW_SPINLOCK(l2_access_lock);
-
-/**
- * set_l2_indirect_reg: write value to an L2 register
- * @reg: Address of L2 register.
- * @value: Value to be written to register.
- *
- * Use architecturally required barriers for ordering between system register
- * accesses
- */
-static void set_l2_indirect_reg(u64 reg, u64 val)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&l2_access_lock, flags);
- write_sysreg_s(reg, L2CPUSRSELR_EL1);
- isb();
- write_sysreg_s(val, L2CPUSRDR_EL1);
- isb();
- raw_spin_unlock_irqrestore(&l2_access_lock, flags);
-}
-
-/**
- * get_l2_indirect_reg: read an L2 register value
- * @reg: Address of L2 register.
- *
- * Use architecturally required barriers for ordering between system register
- * accesses
- */
-static u64 get_l2_indirect_reg(u64 reg)
-{
- u64 val;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&l2_access_lock, flags);
- write_sysreg_s(reg, L2CPUSRSELR_EL1);
- isb();
- val = read_sysreg_s(L2CPUSRDR_EL1);
- raw_spin_unlock_irqrestore(&l2_access_lock, flags);
-
- return val;
-}
-
struct cluster_pmu;
/*
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c
index 4c470104a0d6..cb068bca4a13 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.c
@@ -156,6 +156,11 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[] = {
[QPHY_PCS_LFPS_RXTERM_IRQ_STATUS] = 0x170,
};
+static const unsigned int ufsphy_regs_layout[] = {
+ [QPHY_START_CTRL] = 0x00,
+ [QPHY_PCS_READY_STATUS] = 0x168,
+};
+
static const struct qmp_phy_init_tbl msm8996_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1c),
QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
@@ -601,6 +606,73 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60),
};
+static const struct qmp_phy_init_tbl ufsphy_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0xd5),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_CTRL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL1, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_INITVAL2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xda),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE1, 0x98),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE1, 0xc1),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE1, 0x32),
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE1, 0x0f),
+
+ /*Rate B*/
+ QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x44),
+};
+
+static const struct qmp_phy_init_tbl ufsphy_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06),
+};
+
+static const struct qmp_phy_init_tbl ufsphy_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_LVL, 0x24),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_TERM_BW, 0x5b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1d),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SVS_SO_GAIN, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x81),
+ QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x80),
+};
+
+static const struct qmp_phy_init_tbl ufsphy_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_DOWN_CONTROL, 0x01),
+ QMP_PHY_INIT_CFG(QPHY_V3_PCS_MULTI_LANE_CTRL1, 0x02),
+};
/* struct qmp_phy_cfg - per-PHY initialization config */
struct qmp_phy_cfg {
@@ -652,6 +724,9 @@ struct qmp_phy_cfg {
/* Register offset of secondary tx/rx lanes for USB DP combo PHY */
unsigned int tx_b_lane_offset;
unsigned int rx_b_lane_offset;
+
+ /* true, if PCS block has a separate SW_RESET register */
+ bool has_sw_rst;
};
/**
@@ -748,6 +823,10 @@ static const char * const qmp_v3_phy_clk_l[] = {
"aux", "cfg_ahb", "ref", "com_aux",
};
+static const char * const sdm845_ufs_phy_clk_l[] = {
+ "ref_clk", "ref_aux_clk",
+};
+
/* list of resets */
static const char * const msm8996_pciephy_reset_l[] = {
"phy", "common", "cfg",
@@ -791,6 +870,7 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = {
.has_pwrdn_delay = true,
.pwrdn_delay_min = POWER_DOWN_DELAY_US_MIN,
.pwrdn_delay_max = POWER_DOWN_DELAY_US_MAX,
+ .has_sw_rst = true,
};
static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
@@ -816,6 +896,7 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {
.start_ctrl = SERDES_START | PCS_START,
.pwrdn_ctrl = SW_PWRDN,
.mask_pcs_ready = PHYSTATUS,
+ .has_sw_rst = true,
};
/* list of resets */
@@ -852,6 +933,7 @@ static const struct qmp_phy_cfg ipq8074_pciephy_cfg = {
.has_pwrdn_delay = true,
.pwrdn_delay_min = 995, /* us */
.pwrdn_delay_max = 1005, /* us */
+ .has_sw_rst = true,
};
static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
@@ -885,6 +967,30 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = {
.has_phy_dp_com_ctrl = true,
.tx_b_lane_offset = 0x400,
.rx_b_lane_offset = 0x400,
+ .has_sw_rst = true,
+};
+
+static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
+ .type = PHY_TYPE_UFS,
+ .nlanes = 2,
+
+ .serdes_tbl = ufsphy_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(ufsphy_serdes_tbl),
+ .tx_tbl = ufsphy_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(ufsphy_tx_tbl),
+ .rx_tbl = ufsphy_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(ufsphy_rx_tbl),
+ .pcs_tbl = ufsphy_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(ufsphy_pcs_tbl),
+ .clk_list = sdm845_ufs_phy_clk_l,
+ .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l),
+ .vreg_list = msm8996_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(msm8996_phy_vreg_l),
+ .regs = ufsphy_regs_layout,
+
+ .start_ctrl = SERDES_START,
+ .pwrdn_ctrl = SW_PWRDN,
+ .mask_pcs_ready = PCS_READY,
};
static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = {
@@ -1008,7 +1114,9 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)
void __iomem *status;
unsigned int mask, val;
- qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET], SW_RESET);
+ if (cfg->has_sw_rst)
+ qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET],
+ SW_RESET);
qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL],
SERDES_START | PCS_START);
@@ -1056,7 +1164,8 @@ static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp)
if (cfg->has_phy_com_ctrl) {
qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL],
SERDES_START | PCS_START);
- qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET],
+ if (cfg->has_sw_rst)
+ qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET],
SW_RESET);
qphy_setbits(serdes, cfg->regs[QPHY_COM_POWER_DOWN_CONTROL],
SW_PWRDN);
@@ -1133,7 +1242,8 @@ static int qcom_qmp_phy_init(struct phy *phy)
usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max);
/* Pull PHY out of reset state */
- qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+ if (cfg->has_sw_rst)
+ qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
if (cfg->has_phy_dp_com_ctrl)
qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET);
@@ -1173,7 +1283,8 @@ static int qcom_qmp_phy_exit(struct phy *phy)
clk_disable_unprepare(qphy->pipe_clk);
/* PHY reset */
- qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
+ if (cfg->has_sw_rst)
+ qphy_setbits(qphy->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET);
/* stop SerDes and Phy-Coding-Sublayer */
qphy_clrbits(qphy->pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl);
@@ -1520,8 +1631,8 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
.compatible = "qcom,sdm845-qmp-usb3-phy",
.data = &qmp_v3_usb3phy_cfg,
}, {
- .compatible = "qcom,sdm845-qmp-usb3-uni-phy",
- .data = &qmp_v3_usb3_uniphy_cfg,
+ .compatible = "qcom,sdm845-qmp-ufs-phy",
+ .data = &sdm845_ufsphy_cfg,
},
{ },
};
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h
index 5d78d43ba9fc..3cbcfe1b75f2 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp.h
@@ -184,6 +184,8 @@
#define QSERDES_V3_COM_VCO_TUNE2_MODE0 0x0f8
#define QSERDES_V3_COM_VCO_TUNE1_MODE1 0x0fc
#define QSERDES_V3_COM_VCO_TUNE2_MODE1 0x100
+#define QSERDES_V3_COM_VCO_TUNE_INITVAL1 0x104
+#define QSERDES_V3_COM_VCO_TUNE_INITVAL2 0x108
#define QSERDES_V3_COM_VCO_TUNE_TIMER1 0x11c
#define QSERDES_V3_COM_VCO_TUNE_TIMER2 0x120
#define QSERDES_V3_COM_CLK_SELECT 0x138
@@ -211,8 +213,13 @@
/* Only for QMP V3 PHY - RX registers */
#define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c
#define QSERDES_V3_RX_UCDR_SO_GAIN 0x014
+#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024
+#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_QUARTER 0x028
+#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN 0x02c
#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030
#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
+#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c
+#define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044
#define QSERDES_V3_RX_RX_TERM_BW 0x07c
#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc
#define QSERDES_V3_RX_VGA_CAL_CNTRL2 0x0c0
@@ -275,6 +282,7 @@
#define QPHY_V3_PCS_FLL_CNT_VAL_L 0x0cc
#define QPHY_V3_PCS_FLL_CNT_VAL_H_TOL 0x0d0
#define QPHY_V3_PCS_FLL_MAN_CODE 0x0d4
+#define QPHY_V3_PCS_MULTI_LANE_CTRL1 0x1c4
#define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c
#define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210
diff --git a/drivers/power/avs/Kconfig b/drivers/power/avs/Kconfig
index a67eeace6a89..44d9f5bdc898 100644
--- a/drivers/power/avs/Kconfig
+++ b/drivers/power/avs/Kconfig
@@ -11,6 +11,21 @@ menuconfig POWER_AVS
Say Y here to enable Adaptive Voltage Scaling class support.
+config QCOM_CPR
+ tristate "QCOM Core Power Reduction (CPR) support"
+ depends on POWER_AVS
+ select PM_OPP
+ help
+ Say Y here to enable support for the CPR hardware found on Qualcomm
+ SoCs like MSM8916.
+
+ This driver populates CPU OPPs tables and makes adjustments to the
+ tables based on feedback from the CPR hardware. If you want to do
+ CPUfrequency scaling say Y here.
+
+ To compile this driver as a module, choose M here: the module will
+ be called qcom-cpr
+
config ROCKCHIP_IODOMAIN
tristate "Rockchip IO domain support"
depends on POWER_AVS && ARCH_ROCKCHIP && OF
diff --git a/drivers/power/avs/Makefile b/drivers/power/avs/Makefile
index ba4c7bc69225..88f4d5d49cba 100644
--- a/drivers/power/avs/Makefile
+++ b/drivers/power/avs/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
obj-$(CONFIG_ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
+obj-$(CONFIG_QCOM_CPR) += qcom-cpr.o
diff --git a/drivers/power/avs/qcom-cpr.c b/drivers/power/avs/qcom-cpr.c
new file mode 100644
index 000000000000..dc8ebc92c81b
--- /dev/null
+++ b/drivers/power/avs/qcom-cpr.c
@@ -0,0 +1,2015 @@
+/*
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regulator/consumer.h>
+#include <linux/cpufreq.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/bitops.h>
+#include <linux/regulator/qcom_smd-regulator.h>
+
+/* Register Offsets for RB-CPR and Bit Definitions */
+
+/* RBCPR Version Register */
+#define REG_RBCPR_VERSION 0
+#define RBCPR_VER_2 0x02
+
+/* RBCPR Gate Count and Target Registers */
+#define REG_RBCPR_GCNT_TARGET(n) (0x60 + 4 * n)
+
+#define RBCPR_GCNT_TARGET_TARGET_SHIFT 0
+#define RBCPR_GCNT_TARGET_TARGET_MASK GENMASK(11, 0)
+#define RBCPR_GCNT_TARGET_GCNT_SHIFT 12
+#define RBCPR_GCNT_TARGET_GCNT_MASK GENMASK(9, 0)
+
+/* RBCPR Timer Control */
+#define REG_RBCPR_TIMER_INTERVAL 0x44
+#define REG_RBIF_TIMER_ADJUST 0x4c
+
+#define RBIF_TIMER_ADJ_CONS_UP_MASK GENMASK(3, 0)
+#define RBIF_TIMER_ADJ_CONS_UP_SHIFT 0
+#define RBIF_TIMER_ADJ_CONS_DOWN_MASK GENMASK(3, 0)
+#define RBIF_TIMER_ADJ_CONS_DOWN_SHIFT 4
+#define RBIF_TIMER_ADJ_CLAMP_INT_MASK GENMASK(7, 0)
+#define RBIF_TIMER_ADJ_CLAMP_INT_SHIFT 8
+
+/* RBCPR Config Register */
+#define REG_RBIF_LIMIT 0x48
+#define RBIF_LIMIT_CEILING_MASK GENMASK(5, 0)
+#define RBIF_LIMIT_CEILING_SHIFT 6
+#define RBIF_LIMIT_FLOOR_BITS 6
+#define RBIF_LIMIT_FLOOR_MASK GENMASK(5, 0)
+
+#define RBIF_LIMIT_CEILING_DEFAULT RBIF_LIMIT_CEILING_MASK
+#define RBIF_LIMIT_FLOOR_DEFAULT 0
+
+#define REG_RBIF_SW_VLEVEL 0x94
+#define RBIF_SW_VLEVEL_DEFAULT 0x20
+
+#define REG_RBCPR_STEP_QUOT 0x80
+#define RBCPR_STEP_QUOT_STEPQUOT_MASK GENMASK(7, 0)
+#define RBCPR_STEP_QUOT_IDLE_CLK_MASK GENMASK(3, 0)
+#define RBCPR_STEP_QUOT_IDLE_CLK_SHIFT 8
+
+/* RBCPR Control Register */
+#define REG_RBCPR_CTL 0x90
+
+#define RBCPR_CTL_LOOP_EN BIT(0)
+#define RBCPR_CTL_TIMER_EN BIT(3)
+#define RBCPR_CTL_SW_AUTO_CONT_ACK_EN BIT(5)
+#define RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN BIT(6)
+#define RBCPR_CTL_COUNT_MODE BIT(10)
+#define RBCPR_CTL_UP_THRESHOLD_MASK GENMASK(3, 0)
+#define RBCPR_CTL_UP_THRESHOLD_SHIFT 24
+#define RBCPR_CTL_DN_THRESHOLD_MASK GENMASK(3, 0)
+#define RBCPR_CTL_DN_THRESHOLD_SHIFT 28
+
+/* RBCPR Ack/Nack Response */
+#define REG_RBIF_CONT_ACK_CMD 0x98
+#define REG_RBIF_CONT_NACK_CMD 0x9c
+
+/* RBCPR Result status Register */
+#define REG_RBCPR_RESULT_0 0xa0
+
+#define RBCPR_RESULT0_BUSY_SHIFT 19
+#define RBCPR_RESULT0_BUSY_MASK BIT(RBCPR_RESULT0_BUSY_SHIFT)
+#define RBCPR_RESULT0_ERROR_LT0_SHIFT 18
+#define RBCPR_RESULT0_ERROR_SHIFT 6
+#define RBCPR_RESULT0_ERROR_MASK GENMASK(11, 0)
+#define RBCPR_RESULT0_ERROR_STEPS_SHIFT 2
+#define RBCPR_RESULT0_ERROR_STEPS_MASK GENMASK(3, 0)
+#define RBCPR_RESULT0_STEP_UP_SHIFT 1
+
+/* RBCPR Interrupt Control Register */
+#define REG_RBIF_IRQ_EN(n) (0x100 + 4 * n)
+#define REG_RBIF_IRQ_CLEAR 0x110
+#define REG_RBIF_IRQ_STATUS 0x114
+
+#define CPR_INT_DONE BIT(0)
+#define CPR_INT_MIN BIT(1)
+#define CPR_INT_DOWN BIT(2)
+#define CPR_INT_MID BIT(3)
+#define CPR_INT_UP BIT(4)
+#define CPR_INT_MAX BIT(5)
+#define CPR_INT_CLAMP BIT(6)
+#define CPR_INT_ALL (CPR_INT_DONE | CPR_INT_MIN | CPR_INT_DOWN | \
+ CPR_INT_MID | CPR_INT_UP | CPR_INT_MAX | CPR_INT_CLAMP)
+#define CPR_INT_DEFAULT (CPR_INT_UP | CPR_INT_DOWN)
+
+#define CPR_NUM_RING_OSC 8
+
+/* RBCPR Clock Control Register */
+#define RBCPR_CLK_SEL_MASK BIT(-1)
+#define RBCPR_CLK_SEL_19P2_MHZ 0
+#define RBCPR_CLK_SEL_AHB_CLK BIT(0)
+
+/* CPR eFuse parameters */
+#define CPR_FUSE_TARGET_QUOT_BITS_MASK GENMASK(11, 0)
+
+#define CPR_FUSE_MIN_QUOT_DIFF 50
+
+#define SPEED_BIN_NONE UINT_MAX
+
+#define FUSE_REVISION_UNKNOWN (-1)
+#define FUSE_MAP_NO_MATCH (-1)
+#define FUSE_PARAM_MATCH_ANY 0xffffffff
+
+enum vdd_mx_vmin_method {
+ VDD_MX_VMIN_APC_CORNER_CEILING,
+ VDD_MX_VMIN_FUSE_CORNER_MAP,
+};
+
+enum voltage_change_dir {
+ NO_CHANGE,
+ DOWN,
+ UP,
+};
+
+struct qfprom_offset {
+ u16 offset;
+ u8 width;
+ u8 shift;
+};
+
+struct cpr_fuse {
+ struct qfprom_offset ring_osc;
+ struct qfprom_offset init_voltage;
+ struct qfprom_offset quotient;
+ struct qfprom_offset quotient_offset;
+};
+
+struct fuse_corner_data {
+ int ref_uV;
+ int max_uV;
+ int min_uV;
+ int max_quot_scale;
+ int quot_offset;
+ int quot_scale;
+ int max_volt_scale;
+ int vdd_mx_req;
+};
+
+struct cpr_fuses {
+ struct qfprom_offset redundant;
+ u8 redundant_value;
+ int init_voltage_step;
+ struct fuse_corner_data *fuse_corner_data;
+ struct cpr_fuse *cpr_fuse;
+ struct qfprom_offset *disable;
+};
+
+struct pvs_bin {
+ int *uV;
+};
+
+struct pvs_fuses {
+ struct qfprom_offset redundant;
+ u8 redundant_value;
+ struct qfprom_offset *pvs_fuse;
+ struct pvs_bin *pvs_bins;
+};
+
+struct corner_data {
+ unsigned int fuse_corner;
+ unsigned long freq;
+};
+
+struct freq_plan {
+ u32 speed_bin;
+ u32 pvs_version;
+ const struct corner_data **plan;
+};
+
+struct fuse_conditional_min_volt {
+ struct qfprom_offset redundant;
+ u8 expected;
+ int min_uV;
+};
+
+struct fuse_uplift_wa {
+ struct qfprom_offset redundant;
+ u8 expected;
+ int uV;
+ int *quot;
+ int max_uV;
+ int speed_bin;
+};
+
+struct corner_override {
+ u32 speed_bin;
+ u32 pvs_version;
+ int *max_uV;
+ int *min_uV;
+};
+
+struct corner_adjustment {
+ u32 speed_bin;
+ u32 pvs_version;
+ u32 cpr_rev;
+ u8 *ring_osc_idx;
+ int *fuse_quot;
+ int *fuse_quot_diff;
+ int *fuse_quot_min;
+ int *fuse_quot_offset;
+ int *fuse_init_uV;
+ int *quot;
+ int *init_uV;
+ bool disable_closed_loop;
+};
+
+struct cpr_desc {
+ unsigned int num_fuse_corners;
+ unsigned int num_corners;
+ enum vdd_mx_vmin_method vdd_mx_vmin_method;
+ int min_diff_quot;
+ int *step_quot;
+ struct cpr_fuses cpr_fuses;
+ struct qfprom_offset fuse_revision;
+ struct qfprom_offset speed_bin;
+ struct qfprom_offset pvs_version;
+ struct corner_data *corner_data;
+ struct freq_plan *freq_plans;
+ size_t num_freq_plans;
+ struct pvs_fuses *pvs_fuses;
+ struct fuse_conditional_min_volt *min_volt_fuse;
+ struct fuse_uplift_wa *uplift_wa;
+ struct corner_override *corner_overrides;
+ size_t num_corner_overrides;
+ struct corner_adjustment *adjustments;
+ size_t num_adjustments;
+ bool reduce_to_fuse_uV;
+ bool reduce_to_corner_uV;
+};
+
+struct acc_desc {
+ unsigned int enable_reg;
+ u32 enable_mask;
+
+ struct reg_sequence *settings;
+ struct reg_sequence *override_settings;
+ int num_regs_per_fuse;
+
+ struct qfprom_offset override;
+ u8 override_value;
+};
+
+struct fuse_corner {
+ int min_uV;
+ int max_uV;
+ int uV;
+ int quot;
+ int step_quot;
+ const struct reg_sequence *accs;
+ int num_accs;
+ int vdd_mx_req;
+ unsigned long max_freq;
+ u8 ring_osc_idx;
+};
+
+struct corner {
+ int min_uV;
+ int max_uV;
+ int uV;
+ int last_uV;
+ int quot_adjust;
+ u32 save_ctl;
+ u32 save_irq;
+ unsigned long freq;
+ struct fuse_corner *fuse_corner;
+};
+
+struct cpr_drv {
+ unsigned int num_fuse_corners;
+ unsigned int num_corners;
+
+ unsigned int nb_count;
+ struct notifier_block cpufreq_nb;
+ bool switching_opp;
+ struct notifier_block reg_nb;
+
+ unsigned int ref_clk_khz;
+ unsigned int timer_delay_us;
+ unsigned int timer_cons_up;
+ unsigned int timer_cons_down;
+ unsigned int up_threshold;
+ unsigned int down_threshold;
+ unsigned int idle_clocks;
+ unsigned int gcnt_us;
+ unsigned int vdd_apc_step_up_limit;
+ unsigned int vdd_apc_step_down_limit;
+ unsigned int clamp_timer_interval;
+ enum vdd_mx_vmin_method vdd_mx_vmin_method;
+
+ struct device *dev;
+ struct mutex lock;
+ void __iomem *base;
+ struct corner *corner;
+ struct regulator *vdd_apc;
+ struct regulator *vdd_mx;
+ struct clk *cpu_clk;
+ struct device *cpu_dev;
+ struct regmap *tcsr;
+ bool loop_disabled;
+ bool suspended;
+ u32 gcnt;
+ unsigned long flags;
+#define FLAGS_IGNORE_1ST_IRQ_STATUS BIT(0)
+
+ struct fuse_corner *fuse_corners;
+ struct corner *corners;
+};
+
+static bool cpr_is_allowed(struct cpr_drv *drv)
+{
+ if (drv->loop_disabled) /* || disabled in software */
+ return false;
+ else
+ return true;
+}
+
+static void cpr_write(struct cpr_drv *drv, u32 offset, u32 value)
+{
+ writel_relaxed(value, drv->base + offset);
+}
+
+static u32 cpr_read(struct cpr_drv *drv, u32 offset)
+{
+ return readl_relaxed(drv->base + offset);
+}
+
+static void
+cpr_masked_write(struct cpr_drv *drv, u32 offset, u32 mask, u32 value)
+{
+ u32 val;
+
+ val = readl_relaxed(drv->base + offset);
+ val &= ~mask;
+ val |= value & mask;
+ writel_relaxed(val, drv->base + offset);
+}
+
+static void cpr_irq_clr(struct cpr_drv *drv)
+{
+ cpr_write(drv, REG_RBIF_IRQ_CLEAR, CPR_INT_ALL);
+}
+
+static void cpr_irq_clr_nack(struct cpr_drv *drv)
+{
+ cpr_irq_clr(drv);
+ cpr_write(drv, REG_RBIF_CONT_NACK_CMD, 1);
+}
+
+static void cpr_irq_clr_ack(struct cpr_drv *drv)
+{
+ cpr_irq_clr(drv);
+ cpr_write(drv, REG_RBIF_CONT_ACK_CMD, 1);
+}
+
+static void cpr_irq_set(struct cpr_drv *drv, u32 int_bits)
+{
+ cpr_write(drv, REG_RBIF_IRQ_EN(0), int_bits);
+}
+
+static void cpr_ctl_modify(struct cpr_drv *drv, u32 mask, u32 value)
+{
+ cpr_masked_write(drv, REG_RBCPR_CTL, mask, value);
+}
+
+static void cpr_ctl_enable(struct cpr_drv *drv, struct corner *corner)
+{
+ u32 val, mask;
+
+ if (drv->suspended)
+ return;
+
+ /* Program Consecutive Up & Down */
+ val = drv->timer_cons_down << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT;
+ val |= drv->timer_cons_up << RBIF_TIMER_ADJ_CONS_UP_SHIFT;
+ mask = RBIF_TIMER_ADJ_CONS_UP_MASK | RBIF_TIMER_ADJ_CONS_DOWN_MASK;
+ cpr_masked_write(drv, REG_RBIF_TIMER_ADJUST, mask, val);
+ cpr_masked_write(drv, REG_RBCPR_CTL,
+ RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
+ RBCPR_CTL_SW_AUTO_CONT_ACK_EN,
+ corner->save_ctl);
+ cpr_irq_set(drv, corner->save_irq);
+
+ if (cpr_is_allowed(drv) /*&& drv->vreg_enabled */ &&
+ corner->max_uV > corner->min_uV)
+ val = RBCPR_CTL_LOOP_EN;
+ else
+ val = 0;
+ cpr_ctl_modify(drv, RBCPR_CTL_LOOP_EN, val);
+}
+
+static void cpr_ctl_disable(struct cpr_drv *drv)
+{
+ if (drv->suspended)
+ return;
+
+ cpr_irq_set(drv, 0);
+ cpr_ctl_modify(drv, RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN |
+ RBCPR_CTL_SW_AUTO_CONT_ACK_EN, 0);
+ cpr_masked_write(drv, REG_RBIF_TIMER_ADJUST,
+ RBIF_TIMER_ADJ_CONS_UP_MASK |
+ RBIF_TIMER_ADJ_CONS_DOWN_MASK, 0);
+ cpr_irq_clr(drv);
+ cpr_write(drv, REG_RBIF_CONT_ACK_CMD, 1);
+ cpr_write(drv, REG_RBIF_CONT_NACK_CMD, 1);
+ cpr_ctl_modify(drv, RBCPR_CTL_LOOP_EN, 0);
+}
+
+static bool cpr_ctl_is_enabled(struct cpr_drv *drv)
+{
+ u32 reg_val;
+
+ reg_val = cpr_read(drv, REG_RBCPR_CTL);
+ return reg_val & RBCPR_CTL_LOOP_EN;
+}
+
+static bool cpr_ctl_is_busy(struct cpr_drv *drv)
+{
+ u32 reg_val;
+
+ reg_val = cpr_read(drv, REG_RBCPR_RESULT_0);
+ return reg_val & RBCPR_RESULT0_BUSY_MASK;
+}
+
+static void cpr_corner_save(struct cpr_drv *drv, struct corner *corner)
+{
+ corner->save_ctl = cpr_read(drv, REG_RBCPR_CTL);
+ corner->save_irq = cpr_read(drv, REG_RBIF_IRQ_EN(0));
+}
+
+static void cpr_corner_restore(struct cpr_drv *drv, struct corner *corner)
+{
+ u32 gcnt, ctl, irq, ro_sel, step_quot;
+ struct fuse_corner *fuse = corner->fuse_corner;
+ int i;
+
+ ro_sel = fuse->ring_osc_idx;
+ gcnt = drv->gcnt;
+ gcnt |= fuse->quot - corner->quot_adjust;
+
+ /* Program the step quotient and idle clocks */
+ step_quot = drv->idle_clocks << RBCPR_STEP_QUOT_IDLE_CLK_SHIFT;
+ step_quot |= fuse->step_quot;
+ cpr_write(drv, REG_RBCPR_STEP_QUOT, step_quot);
+
+ /* Clear the target quotient value and gate count of all ROs */
+ for (i = 0; i < CPR_NUM_RING_OSC; i++)
+ cpr_write(drv, REG_RBCPR_GCNT_TARGET(i), 0);
+
+ cpr_write(drv, REG_RBCPR_GCNT_TARGET(ro_sel), gcnt);
+ ctl = corner->save_ctl;
+ cpr_write(drv, REG_RBCPR_CTL, ctl);
+ irq = corner->save_irq;
+ cpr_irq_set(drv, irq);
+ dev_dbg(drv->dev, "gcnt = 0x%08x, ctl = 0x%08x, irq = 0x%08x\n", gcnt,
+ ctl, irq);
+}
+
+static int
+cpr_mx_get(struct cpr_drv *drv, struct fuse_corner *fuse, int apc_volt)
+{
+ switch (drv->vdd_mx_vmin_method) {
+ case VDD_MX_VMIN_APC_CORNER_CEILING:
+ return fuse->max_uV;
+ case VDD_MX_VMIN_FUSE_CORNER_MAP:
+ return fuse->vdd_mx_req;
+ }
+
+ dev_warn(drv->dev, "Failed to get mx\n");
+ return 0;
+}
+
+static void cpr_set_acc(struct regmap *tcsr, struct fuse_corner *f,
+ struct fuse_corner *end)
+{
+ if (f < end) {
+ for (f += 1; f <= end; f++)
+ regmap_multi_reg_write(tcsr, f->accs, f->num_accs);
+ } else {
+ for (f -= 1; f >= end; f--)
+ regmap_multi_reg_write(tcsr, f->accs, f->num_accs);
+ }
+}
+
+static int cpr_pre_voltage(struct cpr_drv *drv,
+ struct fuse_corner *fuse_corner,
+ enum voltage_change_dir dir, int vdd_mx_vmin)
+{
+ int ret = 0;
+ struct fuse_corner *prev_fuse_corner = drv->corner->fuse_corner;
+
+ if (drv->tcsr && dir == DOWN)
+ cpr_set_acc(drv->tcsr, prev_fuse_corner, fuse_corner);
+
+ if (vdd_mx_vmin && dir == UP)
+ ret = qcom_rpm_set_corner(drv->vdd_mx, vdd_mx_vmin);
+
+ return ret;
+}
+
+static int cpr_post_voltage(struct cpr_drv *drv,
+ struct fuse_corner *fuse_corner,
+ enum voltage_change_dir dir, int vdd_mx_vmin)
+{
+ int ret = 0;
+ struct fuse_corner *prev_fuse_corner = drv->corner->fuse_corner;
+
+ if (drv->tcsr && dir == UP)
+ cpr_set_acc(drv->tcsr, prev_fuse_corner, fuse_corner);
+
+ if (vdd_mx_vmin && dir == DOWN)
+ ret = qcom_rpm_set_corner(drv->vdd_mx, vdd_mx_vmin);
+
+ return ret;
+}
+
+static int cpr_regulator_notifier(struct notifier_block *nb,
+ unsigned long event, void *d)
+{
+ struct cpr_drv *drv = container_of(nb, struct cpr_drv, reg_nb);
+ u32 val, mask;
+ int last_uV, new_uV;
+
+ switch (event) {
+ case REGULATOR_EVENT_VOLTAGE_CHANGE:
+ new_uV = (int)(uintptr_t)d;
+ break;
+ default:
+ return NOTIFY_OK;
+ }
+
+ mutex_lock(&drv->lock);
+
+ last_uV = drv->corner->last_uV;
+
+ if (drv->switching_opp) {
+ goto unlock;
+ } else if (last_uV < new_uV) {
+ /* Disable auto nack down */
+ mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+ val = 0;
+ } else if (last_uV > new_uV) {
+ /* Restore default threshold for UP */
+ mask = RBCPR_CTL_UP_THRESHOLD_MASK;
+ mask <<= RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ val = drv->up_threshold;
+ val <<= RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ } else { /* Somehow it's the same? */
+ goto unlock;
+ }
+
+ cpr_ctl_modify(drv, mask, val);
+
+ /* Re-enable default interrupts */
+ cpr_irq_set(drv, CPR_INT_DEFAULT);
+
+ /* Ack */
+ cpr_irq_clr_ack(drv);
+
+ /* Save register values for the corner */
+ cpr_corner_save(drv, drv->corner);
+ drv->corner->last_uV = new_uV;
+unlock:
+ mutex_unlock(&drv->lock);
+
+ return NOTIFY_OK;
+}
+
+static int cpr_scale(struct cpr_drv *drv, enum voltage_change_dir dir)
+{
+ u32 val, error_steps, reg_mask;
+ int last_uV, new_uV, step_uV;
+ struct corner *corner;
+
+ //step_uV = regulator_get_linear_step(drv->vdd_apc);
+ step_uV = 12500; /*TODO: Get step volt here */
+ corner = drv->corner;
+
+ val = cpr_read(drv, REG_RBCPR_RESULT_0);
+
+ error_steps = val >> RBCPR_RESULT0_ERROR_STEPS_SHIFT;
+ error_steps &= RBCPR_RESULT0_ERROR_STEPS_MASK;
+ last_uV = corner->last_uV;
+
+ if (dir == UP) {
+ if (drv->clamp_timer_interval &&
+ error_steps < drv->up_threshold) {
+ /*
+ * Handle the case where another measurement started
+ * after the interrupt was triggered due to a core
+ * exiting from power collapse.
+ */
+ error_steps = max(drv->up_threshold,
+ drv->vdd_apc_step_up_limit);
+ }
+
+ if (last_uV >= corner->max_uV) {
+ cpr_irq_clr_nack(drv);
+
+ /* Maximize the UP threshold */
+ reg_mask = RBCPR_CTL_UP_THRESHOLD_MASK;
+ reg_mask <<= RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ val = reg_mask;
+ cpr_ctl_modify(drv, reg_mask, val);
+
+ /* Disable UP interrupt */
+ cpr_irq_set(drv, CPR_INT_DEFAULT & ~CPR_INT_UP);
+
+ return 0;
+ }
+
+ if (error_steps > drv->vdd_apc_step_up_limit)
+ error_steps = drv->vdd_apc_step_up_limit;
+
+ /* Calculate new voltage */
+ new_uV = last_uV + error_steps * step_uV;
+ new_uV = min(new_uV, corner->max_uV);
+ } else if (dir == DOWN) {
+ if (drv->clamp_timer_interval
+ && error_steps < drv->down_threshold) {
+ /*
+ * Handle the case where another measurement started
+ * after the interrupt was triggered due to a core
+ * exiting from power collapse.
+ */
+ error_steps = max(drv->down_threshold,
+ drv->vdd_apc_step_down_limit);
+ }
+
+ if (last_uV <= corner->min_uV) {
+ cpr_irq_clr_nack(drv);
+
+ /* Enable auto nack down */
+ reg_mask = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+ val = RBCPR_CTL_SW_AUTO_CONT_NACK_DN_EN;
+
+ cpr_ctl_modify(drv, reg_mask, val);
+
+ /* Disable DOWN interrupt */
+ cpr_irq_set(drv, CPR_INT_DEFAULT & ~CPR_INT_DOWN);
+
+ return 0;
+ }
+
+ if (error_steps > drv->vdd_apc_step_down_limit)
+ error_steps = drv->vdd_apc_step_down_limit;
+
+ /* Calculate new voltage */
+ new_uV = last_uV - error_steps * step_uV;
+ new_uV = max(new_uV, corner->min_uV);
+ }
+
+ return new_uV;
+}
+
+static irqreturn_t cpr_irq_handler(int irq, void *dev)
+{
+ struct cpr_drv *drv = dev;
+ u32 val;
+ int new_uV = 0;
+ struct corner *corner;
+
+ mutex_lock(&drv->lock);
+
+ val = cpr_read(drv, REG_RBIF_IRQ_STATUS);
+ if (drv->flags & FLAGS_IGNORE_1ST_IRQ_STATUS)
+ val = cpr_read(drv, REG_RBIF_IRQ_STATUS);
+
+ dev_dbg(drv->dev, "IRQ_STATUS = %#02x\n", val);
+
+ if (!cpr_ctl_is_enabled(drv)) {
+ dev_dbg(drv->dev, "CPR is disabled\n");
+ goto unlock;
+ } else if (cpr_ctl_is_busy(drv) && !drv->clamp_timer_interval) {
+ dev_dbg(drv->dev, "CPR measurement is not ready\n");
+ goto unlock;
+ } else if (!cpr_is_allowed(drv)) {
+ val = cpr_read(drv, REG_RBCPR_CTL);
+ dev_err_ratelimited(drv->dev,
+ "Interrupt broken? RBCPR_CTL = %#02x\n",
+ val);
+ goto unlock;
+ }
+
+ /* Following sequence of handling is as per each IRQ's priority */
+ if (val & CPR_INT_UP) {
+ new_uV = cpr_scale(drv, UP);
+ } else if (val & CPR_INT_DOWN) {
+ new_uV = cpr_scale(drv, DOWN);
+ } else if (val & CPR_INT_MIN) {
+ cpr_irq_clr_nack(drv);
+ } else if (val & CPR_INT_MAX) {
+ cpr_irq_clr_nack(drv);
+ } else if (val & CPR_INT_MID) {
+ /* RBCPR_CTL_SW_AUTO_CONT_ACK_EN is enabled */
+ dev_dbg(drv->dev, "IRQ occurred for Mid Flag\n");
+ } else {
+ dev_dbg(drv->dev, "IRQ occurred for unknown flag (%#08x)\n",
+ val);
+ }
+
+ /* Save register values for the corner */
+ corner = drv->corner;
+ cpr_corner_save(drv, corner);
+unlock:
+ mutex_unlock(&drv->lock);
+
+ if (new_uV)
+ dev_pm_opp_adjust_voltage(drv->cpu_dev, corner->freq, new_uV);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * TODO: Register for hotplug notifier and turn on/off CPR when CPUs are offline
+ */
+static int cpr_enable(struct cpr_drv *drv)
+{
+ int ret;
+
+ /* Enable dependency power before vdd_apc */
+ if (drv->vdd_mx) {
+ ret = regulator_enable(drv->vdd_mx);
+ if (ret)
+ return ret;
+ }
+
+ ret = regulator_enable(drv->vdd_apc);
+ if (ret)
+ return ret;
+
+ mutex_lock(&drv->lock);
+ //drv->vreg_enabled = true;
+ if (cpr_is_allowed(drv) && drv->corner) {
+ cpr_irq_clr(drv);
+ cpr_corner_restore(drv, drv->corner);
+ cpr_ctl_enable(drv, drv->corner);
+ }
+ mutex_unlock(&drv->lock);
+
+ return 0;
+}
+/*
+static int cpr_disable(struct cpr_drv *drv)
+{
+ int ret;
+
+ ret = regulator_disable(drv->vdd_apc);
+ if (ret)
+ return ret;
+
+ if (drv->vdd_mx)
+ ret = regulator_disable(drv->vdd_mx);
+ if (ret)
+ return ret;
+
+ mutex_lock(&drv->lock);
+ //drv->vreg_enabled = false;
+ if (cpr_is_allowed(drv))
+ cpr_ctl_disable(drv);
+ mutex_unlock(&drv->lock);
+
+ return 0;
+}
+*/
+
+
+#ifdef CONFIG_PM_SLEEP
+static int cpr_suspend(struct device *dev)
+{
+ struct cpr_drv *drv = platform_get_drvdata(to_platform_device(dev));
+
+ if (cpr_is_allowed(drv)) {
+ mutex_lock(&drv->lock);
+ cpr_ctl_disable(drv);
+ cpr_irq_clr(drv);
+ drv->suspended = true;
+ mutex_unlock(&drv->lock);
+ }
+
+ return 0;
+}
+
+static int cpr_resume(struct device *dev)
+{
+ struct cpr_drv *drv = platform_get_drvdata(to_platform_device(dev));
+
+ if (cpr_is_allowed(drv)) {
+ mutex_lock(&drv->lock);
+ drv->suspended = false;
+ cpr_irq_clr(drv);
+ cpr_ctl_enable(drv, drv->corner);
+ mutex_unlock(&drv->lock);
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(cpr_pm_ops, cpr_suspend, cpr_resume);
+
+static int cpr_config(struct cpr_drv *drv)
+{
+ int i;
+ u32 val, gcnt;
+ struct corner *corner;
+
+ /* Disable interrupt and CPR */
+ cpr_write(drv, REG_RBIF_IRQ_EN(0), 0);
+ cpr_write(drv, REG_RBCPR_CTL, 0);
+
+ /* Program the default HW Ceiling, Floor and vlevel */
+ val = RBIF_LIMIT_CEILING_DEFAULT << RBIF_LIMIT_CEILING_SHIFT;
+ val |= RBIF_LIMIT_FLOOR_DEFAULT;
+ cpr_write(drv, REG_RBIF_LIMIT, val);
+ cpr_write(drv, REG_RBIF_SW_VLEVEL, RBIF_SW_VLEVEL_DEFAULT);
+
+ /* Clear the target quotient value and gate count of all ROs */
+ for (i = 0; i < CPR_NUM_RING_OSC; i++)
+ cpr_write(drv, REG_RBCPR_GCNT_TARGET(i), 0);
+
+ /* Init and save gcnt */
+ gcnt = (drv->ref_clk_khz * drv->gcnt_us) / 1000;
+ gcnt = gcnt & RBCPR_GCNT_TARGET_GCNT_MASK;
+ gcnt <<= RBCPR_GCNT_TARGET_GCNT_SHIFT;
+ drv->gcnt = gcnt;
+
+ /* Program the delay count for the timer */
+ val = (drv->ref_clk_khz * drv->timer_delay_us) / 1000;
+ cpr_write(drv, REG_RBCPR_TIMER_INTERVAL, val);
+ dev_dbg(drv->dev, "Timer count: 0x%0x (for %d us)\n", val,
+ drv->timer_delay_us);
+
+ /* Program Consecutive Up & Down */
+ val = drv->timer_cons_down << RBIF_TIMER_ADJ_CONS_DOWN_SHIFT;
+ val |= drv->timer_cons_up << RBIF_TIMER_ADJ_CONS_UP_SHIFT;
+ val |= drv->clamp_timer_interval << RBIF_TIMER_ADJ_CLAMP_INT_SHIFT;
+ cpr_write(drv, REG_RBIF_TIMER_ADJUST, val);
+
+ /* Program the control register */
+ val = drv->up_threshold << RBCPR_CTL_UP_THRESHOLD_SHIFT;
+ val |= drv->down_threshold << RBCPR_CTL_DN_THRESHOLD_SHIFT;
+ val |= RBCPR_CTL_TIMER_EN | RBCPR_CTL_COUNT_MODE;
+ val |= RBCPR_CTL_SW_AUTO_CONT_ACK_EN;
+ cpr_write(drv, REG_RBCPR_CTL, val);
+
+ for (i = 0; i < drv->num_corners; i++) {
+ corner = &drv->corners[i];
+ corner->save_ctl = val;
+ corner->save_irq = CPR_INT_DEFAULT;
+ }
+
+ cpr_irq_set(drv, CPR_INT_DEFAULT);
+
+ val = cpr_read(drv, REG_RBCPR_VERSION);
+ if (val <= RBCPR_VER_2)
+ drv->flags |= FLAGS_IGNORE_1ST_IRQ_STATUS;
+
+ return 0;
+}
+
+/* Called twice for each CPU in policy, one pre and one post event */
+static int
+cpr_cpufreq_notifier(struct notifier_block *nb, unsigned long event, void *f)
+{
+ struct cpr_drv *drv = container_of(nb, struct cpr_drv, cpufreq_nb);
+ struct cpufreq_freqs *freqs = f;
+ unsigned long old = freqs->old * 1000;
+ unsigned long new = freqs->new * 1000;
+ struct corner *corner, *end;
+ enum voltage_change_dir dir;
+ int ret = 0, new_uV;
+ int vdd_mx_vmin = 0;
+ struct fuse_corner *fuse_corner;
+
+ /* Determine direction */
+ if (old > new)
+ dir = DOWN;
+ else if (old < new)
+ dir = UP;
+ else
+ dir = NO_CHANGE;
+
+ /* Determine new corner we're going to */
+ corner = drv->corners;
+ end = &corner[drv->num_corners - 1];
+ for (; corner <= end; corner++)
+ if (corner->freq == new)
+ break;
+
+ if (corner > end)
+ return -EINVAL;
+
+ fuse_corner = corner->fuse_corner;
+
+ if (cpr_is_allowed(drv)) {
+ new_uV = corner->last_uV;
+ } else {
+ new_uV = corner->uV;
+ }
+
+ if (dir != NO_CHANGE && drv->vdd_mx)
+ vdd_mx_vmin = cpr_mx_get(drv, fuse_corner, new_uV);
+
+ mutex_lock(&drv->lock);
+ if (event == CPUFREQ_PRECHANGE) {
+ if (drv->nb_count++)
+ goto unlock;
+
+ if (cpr_is_allowed(drv))
+ cpr_ctl_disable(drv);
+
+ ret = cpr_pre_voltage(drv, fuse_corner, dir, vdd_mx_vmin);
+ if (ret)
+ goto unlock;
+
+ drv->switching_opp = true;
+ }
+
+ if (event == CPUFREQ_POSTCHANGE) {
+ if (--drv->nb_count)
+ goto unlock;
+
+ ret = cpr_post_voltage(drv, fuse_corner, dir, vdd_mx_vmin);
+ if (ret)
+ goto unlock;
+
+ if (cpr_is_allowed(drv) /* && drv->vreg_enabled */) {
+ cpr_irq_clr(drv);
+ if (drv->corner != corner)
+ cpr_corner_restore(drv, corner);
+ cpr_ctl_enable(drv, corner);
+ }
+
+ drv->corner = corner;
+ drv->switching_opp = false;
+ }
+unlock:
+ mutex_unlock(&drv->lock);
+
+ return ret;
+}
+
+static u32 cpr_read_efuse(void __iomem *prom, const struct qfprom_offset *efuse)
+{
+ u64 buffer = 0;
+ u8 val;
+ int i, num_bytes;
+
+ num_bytes = DIV_ROUND_UP(efuse->width + efuse->shift, BITS_PER_BYTE);
+
+ for (i = 0; i < num_bytes; i++) {
+ val = readb_relaxed(prom + efuse->offset + i);
+ buffer |= val << (i * BITS_PER_BYTE);
+ }
+
+ buffer >>= efuse->shift;
+ buffer &= BIT(efuse->width) - 1;
+
+ return buffer;
+}
+
+static void
+cpr_populate_ring_osc_idx(const struct cpr_fuse *fuses, struct cpr_drv *drv,
+ void __iomem *prom)
+{
+ struct fuse_corner *fuse = drv->fuse_corners;
+ struct fuse_corner *end = fuse + drv->num_fuse_corners;
+
+ for (; fuse < end; fuse++, fuses++)
+ fuse->ring_osc_idx = cpr_read_efuse(prom, &fuses->ring_osc);
+}
+
+
+static const struct corner_adjustment *cpr_find_adjustment(u32 speed_bin,
+ u32 pvs_version, u32 cpr_rev, const struct cpr_desc *desc,
+ const struct cpr_drv *drv)
+{
+ int i, j;
+ u32 val, ro;
+ struct corner_adjustment *a;
+
+ for (i = 0; i < desc->num_adjustments; i++) {
+ a = &desc->adjustments[i];
+
+ if (a->speed_bin != speed_bin &&
+ a->speed_bin != FUSE_PARAM_MATCH_ANY)
+ continue;
+ if (a->pvs_version != pvs_version &&
+ a->pvs_version != FUSE_PARAM_MATCH_ANY)
+ continue;
+ if (a->cpr_rev != cpr_rev &&
+ a->cpr_rev != FUSE_PARAM_MATCH_ANY)
+ continue;
+ for (j = 0; j < drv->num_fuse_corners; j++) {
+ val = a->ring_osc_idx[j];
+ ro = drv->fuse_corners[j].ring_osc_idx;
+ if (val != ro && val != FUSE_PARAM_MATCH_ANY)
+ break;
+ }
+ if (j == drv->num_fuse_corners)
+ return a;
+ }
+
+ return NULL;
+}
+
+static const int *cpr_get_pvs_uV(const struct cpr_desc *desc,
+ struct nvmem_device *qfprom)
+{
+ const struct qfprom_offset *pvs_efuse;
+ const struct qfprom_offset *redun;
+ unsigned int idx = 0;
+ u8 expected;
+ u32 bin;
+
+ redun = &desc->pvs_fuses->redundant;
+ expected = desc->pvs_fuses->redundant_value;
+ if (redun->width)
+ idx = !!(cpr_read_efuse(qfprom, redun) == expected);
+
+ pvs_efuse = &desc->pvs_fuses->pvs_fuse[idx];
+ bin = cpr_read_efuse(qfprom, pvs_efuse);
+
+ return desc->pvs_fuses->pvs_bins[bin].uV;
+}
+
+static int cpr_read_fuse_uV(const struct cpr_desc *desc,
+ const struct fuse_corner_data *fdata,
+ const struct qfprom_offset *init_v_efuse,
+ struct nvmem_device *qfprom, int step_volt)
+{
+ int step_size_uV, steps, uV;
+ u32 bits;
+
+ bits = cpr_read_efuse(qfprom, init_v_efuse);
+ steps = bits & ~BIT(init_v_efuse->width - 1);
+ /* Not two's complement.. instead highest bit is sign bit */
+ if (bits & BIT(init_v_efuse->width - 1))
+ steps = -steps;
+
+ step_size_uV = desc->cpr_fuses.init_voltage_step;
+
+ uV = fdata->ref_uV + steps * step_size_uV;
+ return DIV_ROUND_UP(uV, step_volt) * step_volt;
+}
+
+static void cpr_fuse_corner_init(struct cpr_drv *drv,
+ const struct cpr_desc *desc,
+ void __iomem *qfprom,
+ const struct cpr_fuse *fuses, u32 speed,
+ const struct corner_adjustment *adjustments,
+ const struct acc_desc *acc_desc)
+{
+ int i;
+ unsigned int step_volt;
+ const struct fuse_corner_data *fdata;
+ struct fuse_corner *fuse, *end, *prev;
+ const struct qfprom_offset *redun;
+ const struct fuse_conditional_min_volt *min_v;
+ const struct fuse_uplift_wa *up;
+ bool do_min_v = false, do_uplift = false;
+ const int *pvs_uV = NULL;
+ const int *adj_min;
+ int uV, diff;
+ u32 min_uV;
+ u8 expected;
+ const struct reg_sequence *accs;
+
+ redun = &acc_desc->override;
+ expected = acc_desc->override_value;
+ if (redun->width && cpr_read_efuse(qfprom, redun) == expected)
+ accs = acc_desc->override_settings;
+ else
+ accs = acc_desc->settings;
+
+ /* Figure out if we should apply workarounds */
+ min_v = desc->min_volt_fuse;
+ do_min_v = min_v &&
+ cpr_read_efuse(qfprom, &min_v->redundant) == min_v->expected;
+ if (do_min_v)
+ min_uV = min_v->min_uV;
+
+ up = desc->uplift_wa;
+ if (!do_min_v && up)
+ if (cpr_read_efuse(qfprom, &up->redundant) == up->expected)
+ do_uplift = up->speed_bin == speed;
+
+ /*
+ * The initial voltage for each fuse corner may be determined by one of
+ * two ways. Either initial voltages are encoded for each fuse corner
+ * in a dedicated fuse per fuse corner (fuses::init_voltage), or we
+ * use the PVS bin fuse to use a table of initial voltages (pvs_uV).
+ */
+ if (fuses->init_voltage.width)
+ //step_volt = regulator_get_linear_step(drv->vdd_apc);
+ step_volt = 12500; /* TODO: Replace with ^ when apc_reg ready */
+ else
+ pvs_uV = cpr_get_pvs_uV(desc, qfprom);
+
+ /* Populate fuse_corner members */
+ adj_min = adjustments->fuse_quot_min;
+ fuse = drv->fuse_corners;
+ end = &fuse[drv->num_fuse_corners - 1];
+ fdata = desc->cpr_fuses.fuse_corner_data;
+
+ for (i = 0, prev = NULL; fuse <= end; fuse++, fuses++, i++, fdata++) {
+
+ /* Populate uV */
+ if (pvs_uV)
+ uV = pvs_uV[i];
+ else
+ uV = cpr_read_fuse_uV(desc, fdata, &fuses->init_voltage,
+ qfprom, step_volt);
+
+ if (adjustments->fuse_init_uV)
+ uV += adjustments->fuse_init_uV[i];
+
+ fuse->min_uV = fdata->min_uV;
+ fuse->max_uV = fdata->max_uV;
+
+ if (do_min_v) {
+ if (fuse->max_uV < min_uV) {
+ fuse->max_uV = min_uV;
+ fuse->min_uV = min_uV;
+ } else if (fuse->min_uV < min_uV) {
+ fuse->min_uV = min_uV;
+ }
+ }
+
+ fuse->uV = clamp(uV, fuse->min_uV, fuse->max_uV);
+
+ if (fuse == end) {
+ if (do_uplift) {
+ end->uV += up->uV;
+ end->uV = clamp(end->uV, 0, up->max_uV);
+ }
+ /*
+ * Allow the highest fuse corner's PVS voltage to
+ * define the ceiling voltage for that corner in order
+ * to support SoC's in which variable ceiling values
+ * are required.
+ */
+ end->max_uV = max(end->max_uV, end->uV);
+ }
+
+ /* Populate target quotient by scaling */
+ fuse->quot = cpr_read_efuse(qfprom, &fuses->quotient);
+ fuse->quot *= fdata->quot_scale;
+ fuse->quot += fdata->quot_offset;
+
+ if (adjustments->fuse_quot) {
+ fuse->quot += adjustments->fuse_quot[i];
+
+ if (prev && adjustments->fuse_quot_diff) {
+ diff = adjustments->fuse_quot_diff[i];
+ if (fuse->quot - prev->quot <= diff)
+ fuse->quot = prev->quot + adj_min[i];
+ }
+ prev = fuse;
+ }
+
+ if (do_uplift)
+ fuse->quot += up->quot[i];
+
+ fuse->step_quot = desc->step_quot[fuse->ring_osc_idx];
+
+ /* Populate acc settings */
+ fuse->accs = accs;
+ fuse->num_accs = acc_desc->num_regs_per_fuse;
+ accs += acc_desc->num_regs_per_fuse;
+
+ /* Populate MX request */
+ fuse->vdd_mx_req = fdata->vdd_mx_req;
+ }
+
+ /*
+ * Restrict all fuse corner PVS voltages based upon per corner
+ * ceiling and floor voltages.
+ */
+ for (fuse = drv->fuse_corners, i = 0; fuse <= end; fuse++, i++) {
+ if (fuse->uV > fuse->max_uV)
+ fuse->uV = fuse->max_uV;
+ else if (fuse->uV < fuse->min_uV)
+ fuse->uV = fuse->min_uV;
+
+ dev_dbg(drv->dev,
+ "fuse corner %d: [%d %d %d] RO%d quot %d squot %d\n",
+ i, fuse->min_uV, fuse->uV, fuse->max_uV,
+ fuse->ring_osc_idx, fuse->quot, fuse->step_quot);
+ }
+}
+
+static struct device *cpr_get_cpu_device(struct device_node *of_node, int index)
+{
+ struct device_node *np;
+ int cpu;
+
+ np = of_parse_phandle(of_node, "qcom,cpr-cpus", index);
+ if (!np)
+ return NULL;
+
+ for_each_possible_cpu(cpu)
+ if (arch_find_n_match_cpu_physical_id(np, cpu, NULL))
+ break;
+
+ of_node_put(np);
+ if (cpu >= nr_cpu_ids)
+ return NULL;
+
+ return get_cpu_device(cpu);
+}
+
+/*
+ * Get the clock and regulator for the first CPU so we can update OPPs,
+ * listen in on regulator voltage change events, and figure out the
+ * boot OPP based on clock frequency.
+ */
+static int
+cpr_get_cpu_resources(struct cpr_drv *drv, struct device_node *of_node)
+{
+ struct device *cpu_dev;
+
+ cpu_dev = cpr_get_cpu_device(of_node, 0);
+ if (!cpu_dev)
+ return -EINVAL;
+
+ drv->cpu_dev = cpu_dev;
+ drv->vdd_apc = devm_regulator_get(cpu_dev, "cpu");
+ if (IS_ERR(drv->vdd_apc))
+ return PTR_ERR(drv->vdd_apc);
+ drv->cpu_clk = devm_clk_get(cpu_dev, NULL);
+
+ return PTR_ERR_OR_ZERO(drv->cpu_clk);
+}
+
+static int cpr_populate_opps(struct device_node *of_node, struct cpr_drv *drv,
+ const struct corner_data **plan)
+{
+ int j, ret;
+ struct device *cpu_dev;
+ struct corner *corner;
+ const struct corner_data *p;
+
+ cpu_dev = get_cpu_device(0);
+ for (j = 0, corner = drv->corners; plan[j]; j++, corner++) {
+ p = plan[j];
+ ret = dev_pm_opp_add(cpu_dev, p->freq, corner->uV);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct corner_data **
+find_freq_plan(const struct cpr_desc *desc, u32 speed_bin, u32 pvs_version)
+{
+ int i;
+ const struct freq_plan *p;
+
+ for (i = 0; i < desc->num_freq_plans; i++) {
+ p = &desc->freq_plans[i];
+
+ if (p->speed_bin != speed_bin &&
+ p->speed_bin != FUSE_PARAM_MATCH_ANY)
+ continue;
+ if (p->pvs_version != pvs_version &&
+ p->pvs_version != FUSE_PARAM_MATCH_ANY)
+ continue;
+
+ return p->plan;
+ }
+
+ return NULL;
+
+}
+
+static struct corner_override *find_corner_override(const struct cpr_desc *desc,
+ u32 speed_bin, u32 pvs_version)
+{
+ int i;
+ struct corner_override *o;
+
+ for (i = 0; i < desc->num_corner_overrides; i++) {
+ o = &desc->corner_overrides[i];
+
+ if (o->speed_bin != speed_bin &&
+ o->speed_bin != FUSE_PARAM_MATCH_ANY)
+ continue;
+ if (o->pvs_version != pvs_version &&
+ o->pvs_version != FUSE_PARAM_MATCH_ANY)
+ continue;
+
+ return o;
+ }
+
+ return NULL;
+
+}
+static int cpr_calculate_scaling(const struct qfprom_offset *quot_offset,
+ struct nvmem_device *qfprom,
+ const struct fuse_corner_data *fdata,
+ int adj_quot_offset,
+ const struct corner *corner)
+{
+ int quot_diff;
+ unsigned long freq_diff;
+ int scaling;
+ const struct fuse_corner *fuse, *prev_fuse;
+
+ fuse = corner->fuse_corner;
+ prev_fuse = fuse - 1;
+
+ if (quot_offset->width) {
+ quot_diff = cpr_read_efuse(qfprom, quot_offset);
+ quot_diff *= fdata->quot_scale;
+ quot_diff += adj_quot_offset;
+ } else {
+ quot_diff = fuse->quot - prev_fuse->quot;
+ }
+
+ freq_diff = fuse->max_freq - prev_fuse->max_freq;
+ freq_diff /= 1000000; /* Convert to MHz */
+ scaling = 1000 * quot_diff / freq_diff;
+ return min(scaling, fdata->max_quot_scale);
+}
+
+static int cpr_interpolate(const struct corner *corner, int step_volt,
+ const struct fuse_corner_data *fdata)
+{
+ unsigned long f_high, f_low, f_diff;
+ int uV_high, uV_low, uV;
+ u64 temp, temp_limit;
+ const struct fuse_corner *fuse, *prev_fuse;
+
+ fuse = corner->fuse_corner;
+ prev_fuse = fuse - 1;
+
+ f_high = fuse->max_freq;
+ f_low = prev_fuse->max_freq;
+ uV_high = fuse->uV;
+ uV_low = prev_fuse->uV;
+ f_diff = fuse->max_freq - corner->freq;
+
+ /*
+ * Don't interpolate in the wrong direction. This could happen
+ * if the adjusted fuse voltage overlaps with the previous fuse's
+ * adjusted voltage.
+ */
+ if (f_high <= f_low || uV_high <= uV_low || f_high <= corner->freq)
+ return corner->uV;
+
+ temp = f_diff * (uV_high - uV_low);
+ do_div(temp, f_high - f_low);
+
+ /*
+ * max_volt_scale has units of uV/MHz while freq values
+ * have units of Hz. Divide by 1000000 to convert to.
+ */
+ temp_limit = f_diff * fdata->max_volt_scale;
+ do_div(temp_limit, 1000000);
+
+ uV = uV_high - min(temp, temp_limit);
+ return roundup(uV, step_volt);
+}
+
+static void cpr_corner_init(struct cpr_drv *drv, const struct cpr_desc *desc,
+ const struct cpr_fuse *fuses, u32 speed_bin,
+ u32 pvs_version, void __iomem *qfprom,
+ const struct corner_adjustment *adjustments,
+ const struct corner_data **plan)
+{
+ int i, fnum, scaling;
+ const struct qfprom_offset *quot_offset;
+ struct fuse_corner *fuse, *prev_fuse;
+ struct corner *corner, *end;
+ const struct corner_data *cdata, *p;
+ const struct fuse_corner_data *fdata;
+ bool apply_scaling;
+ const int *adj_quot_offset;
+ unsigned long freq_corner, freq_diff, freq_diff_mhz;
+ int step_volt = 12500; /* TODO: Get from regulator APIs */
+ const struct corner_override *override;
+
+ corner = drv->corners;
+ end = &corner[drv->num_corners - 1];
+ cdata = desc->corner_data;
+ adj_quot_offset = adjustments->fuse_quot_offset;
+
+ override = find_corner_override(desc, speed_bin, pvs_version);
+
+ /*
+ * Store maximum frequency for each fuse corner based on the frequency
+ * plan
+ */
+ for (i = 0; plan[i]; i++) {
+ p = plan[i];
+ freq_corner = p->freq;
+ fnum = p->fuse_corner;
+ fuse = &drv->fuse_corners[fnum];
+ if (freq_corner > fuse->max_freq)
+ fuse->max_freq = freq_corner;
+
+ }
+
+ /*
+ * Get the quotient adjustment scaling factor, according to:
+ *
+ * scaling = min(1000 * (QUOT(corner_N) - QUOT(corner_N-1))
+ * / (freq(corner_N) - freq(corner_N-1)), max_factor)
+ *
+ * QUOT(corner_N): quotient read from fuse for fuse corner N
+ * QUOT(corner_N-1): quotient read from fuse for fuse corner (N - 1)
+ * freq(corner_N): max frequency in MHz supported by fuse corner N
+ * freq(corner_N-1): max frequency in MHz supported by fuse corner
+ * (N - 1)
+ *
+ * Then walk through the corners mapped to each fuse corner
+ * and calculate the quotient adjustment for each one using the
+ * following formula:
+ *
+ * quot_adjust = (freq_max - freq_corner) * scaling / 1000
+ *
+ * freq_max: max frequency in MHz supported by the fuse corner
+ * freq_corner: frequency in MHz corresponding to the corner
+ * scaling: calculated from above equation
+ *
+ *
+ * + +
+ * | v |
+ * q | f c o | f c
+ * u | c l | c
+ * o | f t | f
+ * t | c a | c
+ * | c f g | c f
+ * | e |
+ * +--------------- +----------------
+ * 0 1 2 3 4 5 6 0 1 2 3 4 5 6
+ * corner corner
+ *
+ * c = corner
+ * f = fuse corner
+ *
+ */
+ for (apply_scaling = false, i = 0; corner <= end; corner++, i++) {
+ fnum = cdata[i].fuse_corner;
+ fdata = &desc->cpr_fuses.fuse_corner_data[fnum];
+ quot_offset = &fuses[fnum].quotient_offset;
+ fuse = &drv->fuse_corners[fnum];
+ if (fnum)
+ prev_fuse = &drv->fuse_corners[fnum - 1];
+ else
+ prev_fuse = NULL;
+
+ corner->fuse_corner = fuse;
+ corner->freq = cdata[i].freq;
+ corner->uV = fuse->uV;
+
+ if (prev_fuse && cdata[i - 1].freq == prev_fuse->max_freq) {
+ scaling = cpr_calculate_scaling(quot_offset, qfprom,
+ fdata, adj_quot_offset ?
+ adj_quot_offset[fnum] : 0,
+ corner);
+ apply_scaling = true;
+ } else if (corner->freq == fuse->max_freq) {
+ /* This is a fuse corner; don't scale anything */
+ apply_scaling = false;
+ }
+
+ if (apply_scaling) {
+ freq_diff = fuse->max_freq - corner->freq;
+ freq_diff_mhz = freq_diff / 1000000;
+ corner->quot_adjust = scaling * freq_diff_mhz / 1000;
+
+ corner->uV = cpr_interpolate(corner, step_volt, fdata);
+ }
+
+ if (adjustments->fuse_quot)
+ corner->quot_adjust -= adjustments->fuse_quot[i];
+
+ if (adjustments->init_uV)
+ corner->uV += adjustments->init_uV[i];
+
+ /* Load per corner ceiling and floor voltages if they exist. */
+ if (override) {
+ corner->max_uV = override->max_uV[i];
+ corner->min_uV = override->min_uV[i];
+ } else {
+ corner->max_uV = fuse->max_uV;
+ corner->min_uV = fuse->min_uV;
+ }
+
+ corner->uV = clamp(corner->uV, corner->min_uV, corner->max_uV);
+ corner->last_uV = corner->uV;
+
+ /* Reduce the ceiling voltage if needed */
+ if (desc->reduce_to_corner_uV && corner->uV < corner->max_uV)
+ corner->max_uV = corner->uV;
+ else if (desc->reduce_to_fuse_uV && fuse->uV < corner->max_uV)
+ corner->max_uV = max(corner->min_uV, fuse->uV);
+
+ dev_dbg(drv->dev, "corner %d: [%d %d %d] quot %d\n", i,
+ corner->min_uV, corner->uV, corner->max_uV,
+ fuse->quot - corner->quot_adjust);
+ }
+}
+
+static const struct cpr_fuse *
+cpr_get_fuses(const struct cpr_desc *desc, void __iomem *qfprom)
+{
+ u32 expected = desc->cpr_fuses.redundant_value;
+ const struct qfprom_offset *fuse = &desc->cpr_fuses.redundant;
+ unsigned int idx;
+
+ idx = !!(fuse->width && cpr_read_efuse(qfprom, fuse) == expected);
+
+ return &desc->cpr_fuses.cpr_fuse[idx * desc->num_fuse_corners];
+}
+
+static bool cpr_is_close_loop_disabled(struct cpr_drv *drv,
+ const struct cpr_desc *desc, void __iomem *qfprom,
+ const struct cpr_fuse *fuses,
+ const struct corner_adjustment *adj)
+{
+ const struct qfprom_offset *disable;
+ unsigned int idx;
+ struct fuse_corner *highest_fuse, *second_highest_fuse;
+ int min_diff_quot, diff_quot;
+
+ if (adj->disable_closed_loop)
+ return true;
+
+ if (!desc->cpr_fuses.disable)
+ return false;
+
+ /*
+ * Are the fuses the redundant ones? This avoids reading the fuse
+ * redundant bit again
+ */
+ idx = !!(fuses == desc->cpr_fuses.cpr_fuse);
+ disable = &desc->cpr_fuses.disable[idx];
+
+ if (cpr_read_efuse(qfprom, disable))
+ return true;
+
+ if (!fuses->quotient_offset.width) {
+ /*
+ * Check if the target quotients for the highest two fuse
+ * corners are too close together.
+ */
+ highest_fuse = &drv->fuse_corners[drv->num_fuse_corners - 1];
+ second_highest_fuse = highest_fuse - 1;
+
+ min_diff_quot = desc->min_diff_quot;
+ diff_quot = highest_fuse->quot - second_highest_fuse->quot;
+
+ return diff_quot < min_diff_quot;
+ }
+
+ return false;
+}
+
+static int cpr_init_parameters(struct platform_device *pdev,
+ struct cpr_drv *drv)
+{
+ struct device_node *of_node = pdev->dev.of_node;
+ int ret;
+
+ ret = of_property_read_u32(of_node, "qcom,cpr-ref-clk",
+ &drv->ref_clk_khz);
+ if (ret)
+ return ret;
+ ret = of_property_read_u32(of_node, "qcom,cpr-timer-delay-us",
+ &drv->timer_delay_us);
+ if (ret)
+ return ret;
+ ret = of_property_read_u32(of_node, "qcom,cpr-timer-cons-up",
+ &drv->timer_cons_up);
+ if (ret)
+ return ret;
+ ret = of_property_read_u32(of_node, "qcom,cpr-timer-cons-down",
+ &drv->timer_cons_down);
+ if (ret)
+ return ret;
+ drv->timer_cons_down &= RBIF_TIMER_ADJ_CONS_DOWN_MASK;
+
+ ret = of_property_read_u32(of_node, "qcom,cpr-up-threshold",
+ &drv->up_threshold);
+ drv->up_threshold &= RBCPR_CTL_UP_THRESHOLD_MASK;
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(of_node, "qcom,cpr-down-threshold",
+ &drv->down_threshold);
+ drv->down_threshold &= RBCPR_CTL_DN_THRESHOLD_MASK;
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(of_node, "qcom,cpr-idle-clocks",
+ &drv->idle_clocks);
+ drv->idle_clocks &= RBCPR_STEP_QUOT_IDLE_CLK_MASK;
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(of_node, "qcom,cpr-gcnt-us", &drv->gcnt_us);
+ if (ret)
+ return ret;
+ ret = of_property_read_u32(of_node, "qcom,vdd-apc-step-up-limit",
+ &drv->vdd_apc_step_up_limit);
+ if (ret)
+ return ret;
+ ret = of_property_read_u32(of_node, "qcom,vdd-apc-step-down-limit",
+ &drv->vdd_apc_step_down_limit);
+ if (ret)
+ return ret;
+
+ ret = of_property_read_u32(of_node, "qcom,cpr-clamp-timer-interval",
+ &drv->clamp_timer_interval);
+ if (ret && ret != -EINVAL)
+ return ret;
+
+ drv->clamp_timer_interval = min_t(unsigned int,
+ drv->clamp_timer_interval,
+ RBIF_TIMER_ADJ_CLAMP_INT_MASK);
+
+ dev_dbg(drv->dev, "up threshold = %u, down threshold = %u\n",
+ drv->up_threshold, drv->down_threshold);
+
+ return 0;
+}
+
+static int cpr_init_and_enable_corner(struct cpr_drv *drv)
+{
+ unsigned long rate;
+ const struct corner *end;
+
+ end = &drv->corners[drv->num_corners - 1];
+ rate = clk_get_rate(drv->cpu_clk);
+
+ for (drv->corner = drv->corners; drv->corner <= end; drv->corner++)
+ if (drv->corner->freq == rate)
+ break;
+
+ if (drv->corner > end)
+ return -EINVAL;
+
+ return cpr_enable(drv);
+}
+
+static struct corner_data msm8916_corner_data[] = {
+ /* [corner] -> { fuse corner, freq } */
+ { 0, 200000000 },
+ { 0, 400000000 },
+ { 1, 533330000 },
+ { 1, 800000000 },
+ { 2, 998400000 },
+ { 2, 1094400000 },
+ { 2, 1152000000 },
+ { 2, 1209600000 },
+ { 2, 1363200000 },
+};
+
+static const struct cpr_desc msm8916_desc = {
+ .num_fuse_corners = 3,
+ .vdd_mx_vmin_method = VDD_MX_VMIN_FUSE_CORNER_MAP,
+ .min_diff_quot = CPR_FUSE_MIN_QUOT_DIFF,
+ .step_quot = (int []){ 26, 26, 26, 26, 26, 26, 26, 26 },
+ .cpr_fuses = {
+ .init_voltage_step = 10000,
+ .fuse_corner_data = (struct fuse_corner_data[]){
+ /* ref_uV max_uV min_uV max_q q_off q_scl v_scl mx */
+ { 1050000, 1050000, 1050000, 0, 0, 1, 0, 3 },
+ { 1150000, 1150000, 1050000, 0, 0, 1, 0, 4 },
+ { 1350000, 1350000, 1162500, 650, 0, 1, 0, 6 },
+ },
+ .cpr_fuse = (struct cpr_fuse[]){
+ {
+ .ring_osc = { 222, 3, 6},
+ .init_voltage = { 220, 6, 2 },
+ .quotient = { 221, 12, 2 },
+ },
+ {
+ .ring_osc = { 222, 3, 6},
+ .init_voltage = { 218, 6, 2 },
+ .quotient = { 219, 12, 0 },
+ },
+ {
+ .ring_osc = { 222, 3, 6},
+ .init_voltage = { 216, 6, 0 },
+ .quotient = { 216, 12, 6 },
+ },
+ },
+ .disable = &(struct qfprom_offset){ 223, 1, 1 },
+ },
+ .speed_bin = { 12, 3, 2 },
+ .pvs_version = { 6, 2, 7 },
+ .corner_data = msm8916_corner_data,
+ .num_corners = ARRAY_SIZE(msm8916_corner_data),
+ .num_freq_plans = 3,
+ .freq_plans = (struct freq_plan[]){
+ {
+ .speed_bin = 0,
+ .pvs_version = 0,
+ .plan = (const struct corner_data* []){
+ msm8916_corner_data + 0,
+ msm8916_corner_data + 1,
+ msm8916_corner_data + 2,
+ msm8916_corner_data + 3,
+ msm8916_corner_data + 4,
+ msm8916_corner_data + 5,
+ msm8916_corner_data + 6,
+ msm8916_corner_data + 7,
+ NULL
+ },
+ },
+ {
+ .speed_bin = 0,
+ .pvs_version = 1,
+ .plan = (const struct corner_data* []){
+ msm8916_corner_data + 0,
+ msm8916_corner_data + 1,
+ msm8916_corner_data + 2,
+ msm8916_corner_data + 3,
+ msm8916_corner_data + 4,
+ msm8916_corner_data + 5,
+ msm8916_corner_data + 6,
+ msm8916_corner_data + 7,
+ NULL
+ },
+ },
+ {
+ .speed_bin = 2,
+ .pvs_version = 0,
+ .plan = (const struct corner_data* []){
+ msm8916_corner_data + 0,
+ msm8916_corner_data + 1,
+ msm8916_corner_data + 2,
+ msm8916_corner_data + 3,
+ msm8916_corner_data + 4,
+ msm8916_corner_data + 5,
+ msm8916_corner_data + 6,
+ msm8916_corner_data + 7,
+ msm8916_corner_data + 8,
+ NULL
+ },
+ },
+ },
+};
+
+static const struct acc_desc msm8916_acc_desc = {
+ .settings = (struct reg_sequence[]){
+ { 0xf000, 0 },
+ { 0xf000, 0x100 },
+ { 0xf000, 0x101 }
+ },
+ .override_settings = (struct reg_sequence[]){
+ { 0xf000, 0 },
+ { 0xf000, 0x100 },
+ { 0xf000, 0x100 }
+ },
+ .num_regs_per_fuse = 1,
+ .override = { 6, 1, 4 },
+ .override_value = 1,
+};
+
+static const struct of_device_id cpr_descs[] = {
+ { .compatible = "qcom,qfprom-msm8916", .data = &msm8916_desc },
+ { }
+};
+
+static const struct of_device_id acc_descs[] = {
+ { .compatible = "qcom,tcsr-msm8916", .data = &msm8916_acc_desc },
+ { }
+};
+
+static int cpr_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct device *dev = &pdev->dev;
+ struct cpr_drv *drv;
+ const struct cpr_fuse *cpr_fuses;
+ const struct corner_adjustment *adj;
+ const struct corner_adjustment empty_adj = { };
+ const struct corner_data **plan;
+ size_t len;
+ int irq, ret;
+ const struct cpr_desc *desc;
+ const struct acc_desc *acc_desc;
+ const struct of_device_id *match;
+ struct device_node *np;
+ void __iomem *qfprom;
+ u32 cpr_rev = FUSE_REVISION_UNKNOWN;
+ u32 speed_bin = SPEED_BIN_NONE;
+ u32 pvs_version = 0;
+ struct platform_device *cpufreq_dt_pdev;
+
+ np = of_parse_phandle(dev->of_node, "eeprom", 0);
+ if (!np)
+ return -ENODEV;
+
+ match = of_match_node(cpr_descs, np);
+ of_node_put(np);
+ if (!match)
+ return -EINVAL;
+ desc = match->data;
+
+ /* TODO: Get from eeprom API */
+ qfprom = devm_ioremap(dev, 0x58000, 0x7000);
+ if (!qfprom)
+ return -ENOMEM;
+
+ len = sizeof(*drv) +
+ sizeof(*drv->fuse_corners) * desc->num_fuse_corners +
+ sizeof(*drv->corners) * desc->num_corners;
+
+ drv = devm_kzalloc(dev, len, GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+ drv->dev = dev;
+
+ np = of_parse_phandle(dev->of_node, "acc-syscon", 0);
+ if (!np)
+ return -ENODEV;
+
+ match = of_match_node(acc_descs, np);
+ if (!match) {
+ of_node_put(np);
+ return -EINVAL;
+ }
+
+ acc_desc = match->data;
+ drv->tcsr = syscon_node_to_regmap(np);
+ of_node_put(np);
+ if (IS_ERR(drv->tcsr))
+ return PTR_ERR(drv->tcsr);
+
+ drv->num_fuse_corners = desc->num_fuse_corners;
+ drv->num_corners = desc->num_corners;
+ drv->fuse_corners = (struct fuse_corner *)(drv + 1);
+ drv->corners = (struct corner *)(drv->fuse_corners +
+ drv->num_fuse_corners);
+ mutex_init(&drv->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ drv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(drv->base))
+ return PTR_ERR(drv->base);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -EINVAL;
+
+ ret = cpr_get_cpu_resources(drv, dev->of_node);
+ if (ret)
+ return ret;
+
+ drv->vdd_mx = devm_regulator_get(dev, "vdd-mx");
+ if (IS_ERR(drv->vdd_mx))
+ return PTR_ERR(drv->vdd_mx);
+
+ drv->vdd_mx_vmin_method = desc->vdd_mx_vmin_method;
+
+ if (desc->fuse_revision.width)
+ cpr_rev = cpr_read_efuse(qfprom, &desc->fuse_revision);
+ if (desc->speed_bin.width)
+ speed_bin = cpr_read_efuse(qfprom, &desc->speed_bin);
+ if (desc->pvs_version.width)
+ pvs_version = cpr_read_efuse(qfprom, &desc->pvs_version);
+
+ plan = find_freq_plan(desc, speed_bin, pvs_version);
+ if (!plan)
+ return -EINVAL;
+
+ cpr_fuses = cpr_get_fuses(desc, qfprom);
+ cpr_populate_ring_osc_idx(cpr_fuses, drv, qfprom);
+
+ adj = cpr_find_adjustment(speed_bin, pvs_version, cpr_rev, desc, drv);
+ if (!adj)
+ adj = &empty_adj;
+
+ cpr_fuse_corner_init(drv, desc, qfprom, cpr_fuses, speed_bin, adj,
+ acc_desc);
+ cpr_corner_init(drv, desc, cpr_fuses, speed_bin, pvs_version, qfprom,
+ adj, plan);
+
+ ret = cpr_populate_opps(dev->of_node, drv, plan);
+ if (ret)
+ return ret;
+
+ /* Register cpufreq-dt driver after the OPPs are populated */
+ cpufreq_dt_pdev = platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+ if (IS_ERR(cpufreq_dt_pdev)) {
+ ret = PTR_ERR(cpufreq_dt_pdev);
+ pr_err("%s error registering cpufreq-dt (%d)\n", __func__, ret);
+ return ret;
+ }
+
+ drv->loop_disabled = cpr_is_close_loop_disabled(drv, desc, qfprom,
+ cpr_fuses, adj);
+ dev_dbg(drv->dev, "CPR closed loop is %sabled\n",
+ drv->loop_disabled ? "dis" : "en");
+
+ ret = cpr_init_parameters(pdev, drv);
+ if (ret)
+ return ret;
+
+ /* Configure CPR HW but keep it disabled */
+ ret = cpr_config(drv);
+ if (ret)
+ return ret;
+
+ /* Enable ACC if required */
+ if (acc_desc->enable_mask)
+ regmap_update_bits(drv->tcsr, acc_desc->enable_reg,
+ acc_desc->enable_mask,
+ acc_desc->enable_mask);
+
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ cpr_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_RISING,
+ "cpr", drv);
+ if (ret)
+ return ret;
+
+ ret = cpr_init_and_enable_corner(drv);
+ if (ret)
+ return ret;
+
+ drv->reg_nb.notifier_call = cpr_regulator_notifier;
+ ret = regulator_register_notifier(drv->vdd_apc, &drv->reg_nb);
+ if (ret)
+ return ret;
+
+ drv->cpufreq_nb.notifier_call = cpr_cpufreq_notifier;
+ ret = cpufreq_register_notifier(&drv->cpufreq_nb,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ if (ret) {
+ regulator_unregister_notifier(drv->vdd_apc, &drv->reg_nb);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, drv);
+
+ return 0;
+}
+
+static int cpr_remove(struct platform_device *pdev)
+{
+ struct cpr_drv *drv = platform_get_drvdata(pdev);
+
+ if (cpr_is_allowed(drv)) {
+ cpr_ctl_disable(drv);
+ cpr_irq_set(drv, 0);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id cpr_match_table[] = {
+ { .compatible = "qcom,cpr" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cpr_match_table);
+
+static struct platform_driver cpr_driver = {
+ .probe = cpr_probe,
+ .remove = cpr_remove,
+ .driver = {
+ .name = "qcom-cpr",
+ .of_match_table = cpr_match_table,
+ .pm = &cpr_pm_ops,
+ },
+};
+module_platform_driver(cpr_driver);
+
+MODULE_DESCRIPTION("Core Power Reduction (CPR) driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:qcom-cpr");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 5dbccf5f3037..96b701fdb2ba 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -682,6 +682,15 @@ config REGULATOR_QCOM_RPM
Qualcomm RPM as a module. The module will be named
"qcom_rpm-regulator".
+config REGULATOR_QCOM_RPMH
+ tristate "Qualcomm Technologies, Inc. RPMh regulator driver"
+ depends on QCOM_RPMH || COMPILE_TEST
+ help
+ This driver supports control of PMIC regulators via the RPMh hardware
+ block found on Qualcomm Technologies Inc. SoCs. RPMh regulator
+ control allows for voting on regulator state between multiple
+ processors within the SoC.
+
config REGULATOR_QCOM_SMD_RPM
tristate "Qualcomm SMD based RPM regulator driver"
depends on QCOM_SMD_RPM
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index bd818ceb7c72..06e76a691fa4 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
+obj-$(CONFIG_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SMD_RPM) += qcom_smd-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
new file mode 100644
index 000000000000..6f6162553beb
--- /dev/null
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -0,0 +1,753 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <soc/qcom/cmd-db.h>
+#include <soc/qcom/rpmh.h>
+
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+/**
+ * enum rpmh_regulator_type - supported RPMh accelerator types
+ * %VRM: RPMh VRM accelerator which supports voting on enable, voltage,
+ * and mode of LDO, SMPS, and BOB type PMIC regulators.
+ * %XOB: RPMh XOB accelerator which supports voting on the enable state
+ * of PMIC regulators.
+ */
+enum rpmh_regulator_type {
+ VRM,
+ XOB,
+};
+
+#define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0
+#define RPMH_REGULATOR_REG_ENABLE 0x4
+#define RPMH_REGULATOR_REG_VRM_MODE 0x8
+
+#define RPMH_REGULATOR_MODE_COUNT 4
+
+#define PMIC4_LDO_MODE_RETENTION 4
+#define PMIC4_LDO_MODE_LPM 5
+#define PMIC4_LDO_MODE_HPM 7
+
+#define PMIC4_SMPS_MODE_RETENTION 4
+#define PMIC4_SMPS_MODE_PFM 5
+#define PMIC4_SMPS_MODE_AUTO 6
+#define PMIC4_SMPS_MODE_PWM 7
+
+#define PMIC4_BOB_MODE_PASS 0
+#define PMIC4_BOB_MODE_PFM 1
+#define PMIC4_BOB_MODE_AUTO 2
+#define PMIC4_BOB_MODE_PWM 3
+
+/**
+ * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
+ * @regulator_type: RPMh accelerator type used to manage this
+ * regulator
+ * @ops: Pointer to regulator ops callback structure
+ * @voltage_range: The single range of voltages supported by this
+ * PMIC regulator type
+ * @n_voltages: The number of unique voltage set points defined
+ * by voltage_range
+ * @hpm_min_load_uA: Minimum load current in microamps that requires
+ * high power mode (HPM) operation. This is used
+ * for LDO hardware type regulators only.
+ * @pmic_mode_map: Array indexed by regulator framework mode
+ * containing PMIC hardware modes. Must be large
+ * enough to index all framework modes supported
+ * by this regulator hardware type.
+ * @of_map_mode: Maps an RPMH_REGULATOR_MODE_* mode value defined
+ * in device tree to a regulator framework mode
+ */
+struct rpmh_vreg_hw_data {
+ enum rpmh_regulator_type regulator_type;
+ const struct regulator_ops *ops;
+ const struct regulator_linear_range voltage_range;
+ int n_voltages;
+ int hpm_min_load_uA;
+ const int *pmic_mode_map;
+ unsigned int (*of_map_mode)(unsigned int mode);
+};
+
+/**
+ * struct rpmh_vreg - individual RPMh regulator data structure encapsulating a
+ * single regulator device
+ * @dev: Device pointer for the top-level PMIC RPMh
+ * regulator parent device. This is used as a
+ * handle in RPMh write requests.
+ * @addr: Base address of the regulator resource within
+ * an RPMh accelerator
+ * @rdesc: Regulator descriptor
+ * @hw_data: PMIC regulator configuration data for this RPMh
+ * regulator
+ * @always_wait_for_ack: Boolean flag indicating if a request must always
+ * wait for an ACK from RPMh before continuing even
+ * if it corresponds to a strictly lower power
+ * state (e.g. enabled --> disabled).
+ * @enabled: Flag indicating if the regulator is enabled or
+ * not
+ * @bypassed: Boolean indicating if the regulator is in
+ * bypass (pass-through) mode or not. This is
+ * only used by BOB rpmh-regulator resources.
+ * @voltage_selector: Selector used for get_voltage_sel() and
+ * set_voltage_sel() callbacks
+ * @mode: RPMh VRM regulator current framework mode
+ */
+struct rpmh_vreg {
+ struct device *dev;
+ u32 addr;
+ struct regulator_desc rdesc;
+ const struct rpmh_vreg_hw_data *hw_data;
+ bool always_wait_for_ack;
+
+ int enabled;
+ bool bypassed;
+ int voltage_selector;
+ unsigned int mode;
+};
+
+/**
+ * struct rpmh_vreg_init_data - initialization data for an RPMh regulator
+ * @name: Name for the regulator which also corresponds
+ * to the device tree subnode name of the regulator
+ * @resource_name: RPMh regulator resource name format string.
+ * This must include exactly one field: '%s' which
+ * is filled at run-time with the PMIC ID provided
+ * by device tree property qcom,pmic-id. Example:
+ * "ldo%s1" for RPMh resource "ldoa1".
+ * @supply_name: Parent supply regulator name
+ * @hw_data: Configuration data for this PMIC regulator type
+ */
+struct rpmh_vreg_init_data {
+ const char *name;
+ const char *resource_name;
+ const char *supply_name;
+ const struct rpmh_vreg_hw_data *hw_data;
+};
+
+/**
+ * rpmh_regulator_send_request() - send the request to RPMh
+ * @vreg: Pointer to the RPMh regulator
+ * @cmd: Pointer to the RPMh command to send
+ * @wait_for_ack: Boolean indicating if execution must wait until the
+ * request has been acknowledged as complete
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int rpmh_regulator_send_request(struct rpmh_vreg *vreg,
+ struct tcs_cmd *cmd, bool wait_for_ack)
+{
+ int ret;
+
+ if (wait_for_ack || vreg->always_wait_for_ack)
+ ret = rpmh_write(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd, 1);
+ else
+ ret = rpmh_write_async(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd,
+ 1);
+
+ return ret;
+}
+
+static int _rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector, bool wait_for_ack)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_VOLTAGE,
+ };
+ int ret;
+
+ /* VRM voltage control register is set with voltage in millivolts. */
+ cmd.data = DIV_ROUND_UP(regulator_list_voltage_linear_range(rdev,
+ selector), 1000);
+
+ ret = rpmh_regulator_send_request(vreg, &cmd, wait_for_ack);
+ if (!ret)
+ vreg->voltage_selector = selector;
+
+ return ret;
+}
+
+static int rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ if (vreg->enabled == -EINVAL) {
+ /*
+ * Cache the voltage and send it later when the regulator is
+ * enabled or disabled.
+ */
+ vreg->voltage_selector = selector;
+ return 0;
+ }
+
+ return _rpmh_regulator_vrm_set_voltage_sel(rdev, selector,
+ selector > vreg->voltage_selector);
+}
+
+static int rpmh_regulator_vrm_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->voltage_selector;
+}
+
+static int rpmh_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->enabled;
+}
+
+static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
+ bool enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE,
+ .data = enable,
+ };
+ int ret;
+
+ if (vreg->enabled == -EINVAL &&
+ vreg->voltage_selector != -ENOTRECOVERABLE) {
+ ret = _rpmh_regulator_vrm_set_voltage_sel(rdev,
+ vreg->voltage_selector, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = rpmh_regulator_send_request(vreg, &cmd, enable);
+ if (!ret)
+ vreg->enabled = enable;
+
+ return ret;
+}
+
+static int rpmh_regulator_enable(struct regulator_dev *rdev)
+{
+ return rpmh_regulator_set_enable_state(rdev, true);
+}
+
+static int rpmh_regulator_disable(struct regulator_dev *rdev)
+{
+ return rpmh_regulator_set_enable_state(rdev, false);
+}
+
+static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg,
+ unsigned int mode, bool bypassed)
+{
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE,
+ };
+ int pmic_mode;
+
+ if (mode > REGULATOR_MODE_STANDBY)
+ return -EINVAL;
+
+ pmic_mode = vreg->hw_data->pmic_mode_map[mode];
+ if (pmic_mode < 0)
+ return pmic_mode;
+
+ cmd.data = bypassed ? PMIC4_BOB_MODE_PASS : pmic_mode;
+
+ return rpmh_regulator_send_request(vreg, &cmd, true);
+}
+
+static int rpmh_regulator_vrm_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (mode == vreg->mode)
+ return 0;
+
+ ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed);
+ if (!ret)
+ vreg->mode = mode;
+
+ return ret;
+}
+
+static unsigned int rpmh_regulator_vrm_get_mode(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->mode;
+}
+
+/**
+ * rpmh_regulator_vrm_set_load() - set the regulator mode based upon the load
+ * current requested
+ * @rdev: Regulator device pointer for the rpmh-regulator
+ * @load_uA: Aggregated load current in microamps
+ *
+ * This function is used in the regulator_ops for VRM type RPMh regulator
+ * devices.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int rpmh_regulator_vrm_set_load(struct regulator_dev *rdev, int load_uA)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ unsigned int mode;
+
+ if (load_uA >= vreg->hw_data->hpm_min_load_uA)
+ mode = REGULATOR_MODE_FAST;
+ else
+ mode = REGULATOR_MODE_IDLE;
+
+ return rpmh_regulator_vrm_set_mode(rdev, mode);
+}
+
+static int rpmh_regulator_vrm_set_bypass(struct regulator_dev *rdev,
+ bool enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (vreg->bypassed == enable)
+ return 0;
+
+ ret = rpmh_regulator_vrm_set_mode_bypass(vreg, vreg->mode, enable);
+ if (!ret)
+ vreg->bypassed = enable;
+
+ return ret;
+}
+
+static int rpmh_regulator_vrm_get_bypass(struct regulator_dev *rdev,
+ bool *enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ *enable = vreg->bypassed;
+
+ return 0;
+}
+
+static const struct regulator_ops rpmh_regulator_vrm_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+};
+
+static const struct regulator_ops rpmh_regulator_vrm_drms_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+ .set_load = rpmh_regulator_vrm_set_load,
+};
+
+static const struct regulator_ops rpmh_regulator_vrm_bypass_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+ .set_bypass = rpmh_regulator_vrm_set_bypass,
+ .get_bypass = rpmh_regulator_vrm_get_bypass,
+};
+
+static const struct regulator_ops rpmh_regulator_xob_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+};
+
+/**
+ * rpmh_regulator_init_vreg() - initialize all attributes of an rpmh-regulator
+ * vreg: Pointer to the individual rpmh-regulator resource
+ * dev: Pointer to the top level rpmh-regulator PMIC device
+ * node: Pointer to the individual rpmh-regulator resource
+ * device node
+ * pmic_id: String used to identify the top level rpmh-regulator
+ * PMIC device on the board
+ * pmic_rpmh_data: Pointer to a null-terminated array of rpmh-regulator
+ * resources defined for the top level PMIC device
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
+ struct device_node *node, const char *pmic_id,
+ const struct rpmh_vreg_init_data *pmic_rpmh_data)
+{
+ struct regulator_config reg_config = {};
+ char rpmh_resource_name[20] = "";
+ const struct rpmh_vreg_init_data *rpmh_data;
+ struct regulator_init_data *init_data;
+ struct regulator_dev *rdev;
+ int ret;
+
+ vreg->dev = dev;
+
+ for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++)
+ if (!strcmp(rpmh_data->name, node->name))
+ break;
+
+ if (!rpmh_data->name) {
+ dev_err(dev, "Unknown regulator %s\n", node->name);
+ return -EINVAL;
+ }
+
+ scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name),
+ rpmh_data->resource_name, pmic_id);
+
+ vreg->addr = cmd_db_read_addr(rpmh_resource_name);
+ if (!vreg->addr) {
+ dev_err(dev, "%s: could not find RPMh address for resource %s\n",
+ node->name, rpmh_resource_name);
+ return -ENODEV;
+ }
+
+ vreg->rdesc.name = rpmh_data->name;
+ vreg->rdesc.supply_name = rpmh_data->supply_name;
+ vreg->hw_data = rpmh_data->hw_data;
+
+ vreg->enabled = -EINVAL;
+ vreg->voltage_selector = -ENOTRECOVERABLE;
+ vreg->mode = REGULATOR_MODE_INVALID;
+
+ if (rpmh_data->hw_data->n_voltages) {
+ vreg->rdesc.linear_ranges = &rpmh_data->hw_data->voltage_range;
+ vreg->rdesc.n_linear_ranges = 1;
+ vreg->rdesc.n_voltages = rpmh_data->hw_data->n_voltages;
+ }
+
+ vreg->always_wait_for_ack = of_property_read_bool(node,
+ "qcom,always-wait-for-ack");
+
+ vreg->rdesc.owner = THIS_MODULE;
+ vreg->rdesc.type = REGULATOR_VOLTAGE;
+ vreg->rdesc.ops = vreg->hw_data->ops;
+ vreg->rdesc.of_map_mode = vreg->hw_data->of_map_mode;
+
+ init_data = of_get_regulator_init_data(dev, node, &vreg->rdesc);
+ if (!init_data)
+ return -ENOMEM;
+
+ if (rpmh_data->hw_data->regulator_type == XOB &&
+ init_data->constraints.min_uV &&
+ init_data->constraints.min_uV == init_data->constraints.max_uV) {
+ vreg->rdesc.fixed_uV = init_data->constraints.min_uV;
+ vreg->rdesc.n_voltages = 1;
+ }
+
+ reg_config.dev = dev;
+ reg_config.init_data = init_data;
+ reg_config.of_node = node;
+ reg_config.driver_data = vreg;
+
+ rdev = devm_regulator_register(dev, &vreg->rdesc, &reg_config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "%s: devm_regulator_register() failed, ret=%d\n",
+ node->name, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "%s regulator registered for RPMh resource %s @ 0x%05X\n",
+ node->name, rpmh_resource_name, vreg->addr);
+
+ return 0;
+}
+
+static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC4_LDO_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC4_LDO_MODE_LPM,
+ [REGULATOR_MODE_NORMAL] = -EINVAL,
+ [REGULATOR_MODE_FAST] = PMIC4_LDO_MODE_HPM,
+};
+
+static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int mode)
+{
+ static const unsigned int of_mode_map[RPMH_REGULATOR_MODE_COUNT] = {
+ [RPMH_REGULATOR_MODE_RET] = REGULATOR_MODE_STANDBY,
+ [RPMH_REGULATOR_MODE_LPM] = REGULATOR_MODE_IDLE,
+ [RPMH_REGULATOR_MODE_AUTO] = REGULATOR_MODE_INVALID,
+ [RPMH_REGULATOR_MODE_HPM] = REGULATOR_MODE_FAST,
+ };
+
+ if (mode >= RPMH_REGULATOR_MODE_COUNT)
+ return -EINVAL;
+
+ return of_mode_map[mode];
+}
+
+static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC4_SMPS_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC4_SMPS_MODE_PFM,
+ [REGULATOR_MODE_NORMAL] = PMIC4_SMPS_MODE_AUTO,
+ [REGULATOR_MODE_FAST] = PMIC4_SMPS_MODE_PWM,
+};
+
+static unsigned int rpmh_regulator_pmic4_smps_of_map_mode(unsigned int mode)
+{
+ static const unsigned int of_mode_map[RPMH_REGULATOR_MODE_COUNT] = {
+ [RPMH_REGULATOR_MODE_RET] = REGULATOR_MODE_STANDBY,
+ [RPMH_REGULATOR_MODE_LPM] = REGULATOR_MODE_IDLE,
+ [RPMH_REGULATOR_MODE_AUTO] = REGULATOR_MODE_NORMAL,
+ [RPMH_REGULATOR_MODE_HPM] = REGULATOR_MODE_FAST,
+ };
+
+ if (mode >= RPMH_REGULATOR_MODE_COUNT)
+ return -EINVAL;
+
+ return of_mode_map[mode];
+}
+
+static const int pmic_mode_map_pmic4_bob[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = -EINVAL,
+ [REGULATOR_MODE_IDLE] = PMIC4_BOB_MODE_PFM,
+ [REGULATOR_MODE_NORMAL] = PMIC4_BOB_MODE_AUTO,
+ [REGULATOR_MODE_FAST] = PMIC4_BOB_MODE_PWM,
+};
+
+static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int mode)
+{
+ static const unsigned int of_mode_map[RPMH_REGULATOR_MODE_COUNT] = {
+ [RPMH_REGULATOR_MODE_RET] = REGULATOR_MODE_INVALID,
+ [RPMH_REGULATOR_MODE_LPM] = REGULATOR_MODE_IDLE,
+ [RPMH_REGULATOR_MODE_AUTO] = REGULATOR_MODE_NORMAL,
+ [RPMH_REGULATOR_MODE_HPM] = REGULATOR_MODE_FAST,
+ };
+
+ if (mode >= RPMH_REGULATOR_MODE_COUNT)
+ return -EINVAL;
+
+ return of_mode_map[mode];
+}
+
+static const struct rpmh_vreg_hw_data pmic4_pldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1664000, 0, 255, 8000),
+ .n_voltages = 256,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_pldo_lv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1256000, 0, 127, 8000),
+ .n_voltages = 128,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_nldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+ .n_voltages = 128,
+ .hpm_min_load_uA = 30000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_hfsmps3 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ .n_voltages = 216,
+ .pmic_mode_map = pmic_mode_map_pmic4_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_ftsmps426 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 258, 4000),
+ .n_voltages = 259,
+ .pmic_mode_map = pmic_mode_map_pmic4_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_bob = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_bypass_ops,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1824000, 0, 83, 32000),
+ .n_voltages = 84,
+ .pmic_mode_map = pmic_mode_map_pmic4_bob,
+ .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_lvs = {
+ .regulator_type = XOB,
+ .ops = &rpmh_regulator_xob_ops,
+ /* LVS hardware does not support voltage or mode configuration. */
+};
+
+#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
+{ \
+ .name = _name, \
+ .resource_name = _resource_name, \
+ .hw_data = _hw_data, \
+ .supply_name = _supply_name, \
+}
+
+static const struct rpmh_vreg_init_data pm8998_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic4_hfsmps3, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic4_ftsmps426, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic4_ftsmps426, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic4_ftsmps426, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic4_ftsmps426, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic4_ftsmps426, "vdd-s10"),
+ RPMH_VREG("smps11", "smp%s11", &pmic4_ftsmps426, "vdd-s11"),
+ RPMH_VREG("smps12", "smp%s12", &pmic4_ftsmps426, "vdd-s12"),
+ RPMH_VREG("smps13", "smp%s13", &pmic4_ftsmps426, "vdd-s13"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l27"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l3-l11"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic4_nldo, "vdd-l4-l5"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l4-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo, "vdd-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic4_nldo, "vdd-l3-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l16-l28"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l18-l22"),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo20", "ldo%s20", &pmic4_pldo, "vdd-l20-l24"),
+ RPMH_VREG("ldo21", "ldo%s21", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo22", "ldo%s22", &pmic4_pldo, "vdd-l18-l22"),
+ RPMH_VREG("ldo23", "ldo%s23", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo24", "ldo%s24", &pmic4_pldo, "vdd-l20-l24"),
+ RPMH_VREG("ldo25", "ldo%s25", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo26", "ldo%s26", &pmic4_nldo, "vdd-l26"),
+ RPMH_VREG("ldo27", "ldo%s27", &pmic4_nldo, "vdd-l1-l27"),
+ RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"),
+ RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"),
+ RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"),
+ {},
+};
+
+static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
+ RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
+ {},
+};
+
+static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"),
+ {},
+};
+
+static int rpmh_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct rpmh_vreg_init_data *vreg_data;
+ struct device_node *node;
+ struct rpmh_vreg *vreg;
+ const char *pmic_id;
+ int ret;
+
+ ret = cmd_db_ready();
+ if (ret < 0) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Command DB not available, ret=%d\n", ret);
+ return ret;
+ }
+
+ vreg_data = of_device_get_match_data(dev);
+ if (!vreg_data)
+ return -ENODEV;
+
+ ret = of_property_read_string(dev->of_node, "qcom,pmic-id", &pmic_id);
+ if (ret < 0) {
+ dev_err(dev, "qcom,pmic-id missing in DT node\n");
+ return ret;
+ }
+
+ for_each_available_child_of_node(dev->of_node, node) {
+ vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+ if (!vreg) {
+ of_node_put(node);
+ return -ENOMEM;
+ }
+
+ ret = rpmh_regulator_init_vreg(vreg, dev, node, pmic_id,
+ vreg_data);
+ if (ret < 0) {
+ of_node_put(node);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id rpmh_regulator_match_table[] = {
+ {
+ .compatible = "qcom,pm8998-rpmh-regulators",
+ .data = pm8998_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmi8998-rpmh-regulators",
+ .data = pmi8998_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8005-rpmh-regulators",
+ .data = pm8005_vreg_data,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table);
+
+static struct platform_driver rpmh_regulator_driver = {
+ .driver = {
+ .name = "qcom-rpmh-regulator",
+ .of_match_table = of_match_ptr(rpmh_regulator_match_table),
+ },
+ .probe = rpmh_regulator_probe,
+};
+module_platform_driver(rpmh_regulator_driver);
+
+MODULE_DESCRIPTION("Qualcomm RPMh regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
index fe2fb36803e0..758812de2a50 100644
--- a/drivers/regulator/qcom_smd-regulator.c
+++ b/drivers/regulator/qcom_smd-regulator.c
@@ -18,6 +18,9 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/soc/qcom/smd-rpm.h>
+#include <linux/regulator/qcom_smd-regulator.h>
+
+#include "internal.h"
struct qcom_rpm_reg {
struct device *dev;
@@ -42,6 +45,11 @@ struct rpm_regulator_req {
#define RPM_KEY_SWEN 0x6e657773 /* "swen" */
#define RPM_KEY_UV 0x00007675 /* "uv" */
#define RPM_KEY_MA 0x0000616d /* "ma" */
+#define RPM_KEY_FLOOR 0x00636676 /* "vfc" */
+#define RPM_KEY_CORNER 0x6e726f63 /* "corn" */
+
+#define RPM_MIN_FLOOR_CORNER 0
+#define RPM_MAX_FLOOR_CORNER 6
static int rpm_reg_write_active(struct qcom_rpm_reg *vreg,
struct rpm_regulator_req *req,
@@ -54,6 +62,50 @@ static int rpm_reg_write_active(struct qcom_rpm_reg *vreg,
req, size);
}
+int qcom_rpm_set_floor(struct regulator *regulator, int floor)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ struct rpm_regulator_req req;
+ int ret;
+
+ req.key = RPM_KEY_FLOOR;
+ req.nbytes = sizeof(u32);
+ req.value = floor;
+
+ if (floor < RPM_MIN_FLOOR_CORNER || floor > RPM_MAX_FLOOR_CORNER)
+ return -EINVAL;
+
+ ret = rpm_reg_write_active(vreg, &req, sizeof(req));
+ if (ret)
+ dev_err(rdev_get_dev(rdev), "Failed to set floor %d\n", floor);
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_rpm_set_floor);
+
+int qcom_rpm_set_corner(struct regulator *regulator, int corner)
+{
+ struct regulator_dev *rdev = regulator->rdev;
+ struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
+ struct rpm_regulator_req req;
+ int ret;
+
+ req.key = RPM_KEY_CORNER;
+ req.nbytes = sizeof(u32);
+ req.value = corner;
+
+ if (corner < RPM_MIN_FLOOR_CORNER || corner > RPM_MAX_FLOOR_CORNER)
+ return -EINVAL;
+
+ ret = rpm_reg_write_active(vreg, &req, sizeof(req));
+ if (ret)
+ dev_err(rdev_get_dev(rdev), "Failed to set corner %d\n", corner);
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_rpm_set_corner);
+
static int rpm_reg_enable(struct regulator_dev *rdev)
{
struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c
index 89a86ce07f99..a65964671e79 100644
--- a/drivers/remoteproc/qcom_adsp_pil.c
+++ b/drivers/remoteproc/qcom_adsp_pil.c
@@ -444,6 +444,16 @@ static const struct adsp_data adsp_resource_init = {
.ssctl_id = 0x14,
};
+static const struct adsp_data cdsp_resource_init = {
+ .crash_reason_smem = 601,
+ .firmware_name = "cdsp.mdt",
+ .pas_id = 18,
+ .has_aggre2_clk = false,
+ .ssr_name = "cdsp",
+ .sysmon_name = "cdsp",
+ .ssctl_id = 0x17,
+};
+
static const struct adsp_data slpi_resource_init = {
.crash_reason_smem = 424,
.firmware_name = "slpi.mdt",
@@ -457,6 +467,8 @@ static const struct adsp_data slpi_resource_init = {
static const struct of_device_id adsp_of_match[] = {
{ .compatible = "qcom,msm8974-adsp-pil", .data = &adsp_resource_init},
{ .compatible = "qcom,msm8996-adsp-pil", .data = &adsp_resource_init},
+ { .compatible = "qcom,sdm845-adsp-pas", .data = &adsp_resource_init},
+ { .compatible = "qcom,sdm845-cdsp-pas", .data = &cdsp_resource_init},
{ .compatible = "qcom,msm8996-slpi-pil", .data = &slpi_resource_init},
{ },
};
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index c0b292be1b72..756ad2b27d0f 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -82,6 +82,15 @@ config RESET_PISTACHIO
help
This enables the reset driver for ImgTec Pistachio SoCs.
+config RESET_QCOM_AOSS
+ bool "Qcom AOSS Reset Driver"
+ depends on ARCH_QCOM || COMPILE_TEST
+ help
+ This enables the AOSS (always on subsystem) reset driver
+ for Qualcomm SDM845 SoCs. Say Y if you want to control
+ reset signals provided by AOSS for Modem, Venus, ADSP,
+ GPU, Camera, Wireless, Display subsystem. Otherwise, say N.
+
config RESET_SIMPLE
bool "Simple Reset Controller Driver" if COMPILE_TEST
default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index c1261dcfe9ad..6881e4d287f0 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
+obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
diff --git a/drivers/reset/reset-qcom-aoss.c b/drivers/reset/reset-qcom-aoss.c
new file mode 100644
index 000000000000..d9ca7339c434
--- /dev/null
+++ b/drivers/reset/reset-qcom-aoss.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <dt-bindings/reset/qcom,sdm845-aoss.h>
+
+struct qcom_aoss_reset_map {
+ unsigned int reg;
+};
+
+struct qcom_aoss_desc {
+ const struct qcom_aoss_reset_map *resets;
+ size_t num_resets;
+};
+
+struct qcom_aoss_reset_data {
+ struct reset_controller_dev rcdev;
+ void __iomem *base;
+ const struct qcom_aoss_desc *desc;
+};
+
+static const struct qcom_aoss_reset_map sdm845_aoss_resets[] = {
+ [AOSS_CC_MSS_RESTART] = {0x0},
+ [AOSS_CC_CAMSS_RESTART] = {0x1000},
+ [AOSS_CC_VENUS_RESTART] = {0x2000},
+ [AOSS_CC_GPU_RESTART] = {0x3000},
+ [AOSS_CC_DISPSS_RESTART] = {0x4000},
+ [AOSS_CC_WCSS_RESTART] = {0x10000},
+ [AOSS_CC_LPASS_RESTART] = {0x20000},
+};
+
+static const struct qcom_aoss_desc sdm845_aoss_desc = {
+ .resets = sdm845_aoss_resets,
+ .num_resets = ARRAY_SIZE(sdm845_aoss_resets),
+};
+
+static inline struct qcom_aoss_reset_data *to_qcom_aoss_reset_data(
+ struct reset_controller_dev *rcdev)
+{
+ return container_of(rcdev, struct qcom_aoss_reset_data, rcdev);
+}
+
+static int qcom_aoss_control_assert(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev);
+ const struct qcom_aoss_reset_map *map = &data->desc->resets[idx];
+
+ writel(1, data->base + map->reg);
+ /* Wait 6 32kHz sleep cycles for reset */
+ usleep_range(200, 300);
+ return 0;
+}
+
+static int qcom_aoss_control_deassert(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev);
+ const struct qcom_aoss_reset_map *map = &data->desc->resets[idx];
+
+ writel(0, data->base + map->reg);
+ /* Wait 6 32kHz sleep cycles for reset */
+ usleep_range(200, 300);
+ return 0;
+}
+
+static int qcom_aoss_control_reset(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ qcom_aoss_control_assert(rcdev, idx);
+
+ return qcom_aoss_control_deassert(rcdev, idx);
+}
+
+static const struct reset_control_ops qcom_aoss_reset_ops = {
+ .reset = qcom_aoss_control_reset,
+ .assert = qcom_aoss_control_assert,
+ .deassert = qcom_aoss_control_deassert,
+};
+
+static int qcom_aoss_reset_probe(struct platform_device *pdev)
+{
+ struct qcom_aoss_reset_data *data;
+ struct device *dev = &pdev->dev;
+ const struct qcom_aoss_desc *desc;
+ struct resource *res;
+
+ desc = of_device_get_match_data(dev);
+ if (!desc)
+ return -EINVAL;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->desc = desc;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.ops = &qcom_aoss_reset_ops;
+ data->rcdev.nr_resets = desc->num_resets;
+ data->rcdev.of_node = dev->of_node;
+
+ return devm_reset_controller_register(dev, &data->rcdev);
+}
+
+static const struct of_device_id qcom_aoss_reset_of_match[] = {
+ { .compatible = "qcom,sdm845-aoss-reset", .data = &sdm845_aoss_desc },
+ {}
+};
+
+static struct platform_driver qcom_aoss_reset_driver = {
+ .probe = qcom_aoss_reset_probe,
+ .driver = {
+ .name = "qcom_aoss_reset",
+ .of_match_table = qcom_aoss_reset_of_match,
+ },
+};
+
+builtin_platform_driver(qcom_aoss_reset_driver);
+
+MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c
index b714a543a91d..8122807db380 100644
--- a/drivers/rpmsg/rpmsg_core.c
+++ b/drivers/rpmsg/rpmsg_core.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/rpmsg.h>
#include <linux/of_device.h>
+#include <linux/pm_domain.h>
#include <linux/slab.h>
#include "rpmsg_internal.h"
@@ -449,6 +450,10 @@ static int rpmsg_dev_probe(struct device *dev)
struct rpmsg_endpoint *ept = NULL;
int err;
+ err = dev_pm_domain_attach(dev, true);
+ if (err)
+ goto out;
+
if (rpdrv->callback) {
strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
chinfo.src = rpdev->src;
@@ -490,6 +495,8 @@ static int rpmsg_dev_remove(struct device *dev)
rpdrv->remove(rpdev);
+ dev_pm_domain_detach(dev, true);
+
if (rpdev->ept)
rpmsg_destroy_ept(rpdev->ept);
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index ba729c7bc33a..1abbe2130a78 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -17,7 +17,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
-#include <linux/phy/phy-qcom-ufs.h>
#include "ufshcd.h"
#include "ufshcd-pltfrm.h"
@@ -114,10 +113,10 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
if (!host->is_lane_clks_enabled)
return;
- if (host->hba->lanes_per_direction > 1)
+ if (host->tx_l1_sync_clk)
clk_disable_unprepare(host->tx_l1_sync_clk);
clk_disable_unprepare(host->tx_l0_sync_clk);
- if (host->hba->lanes_per_direction > 1)
+ if (host->rx_l1_sync_clk)
clk_disable_unprepare(host->rx_l1_sync_clk);
clk_disable_unprepare(host->rx_l0_sync_clk);
@@ -148,18 +147,15 @@ static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
if (err)
goto disable_tx_l0;
- err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
- host->tx_l1_sync_clk);
- if (err)
- goto disable_rx_l1;
+ /* The tx lane1 clk could be muxed, hence keep this optional */
+ if (host->tx_l1_sync_clk)
+ ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+ host->tx_l1_sync_clk);
}
host->is_lane_clks_enabled = true;
goto out;
-disable_rx_l1:
- if (host->hba->lanes_per_direction > 1)
- clk_disable_unprepare(host->rx_l1_sync_clk);
disable_tx_l0:
clk_disable_unprepare(host->tx_l0_sync_clk);
disable_rx_l0:
@@ -190,8 +186,9 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
if (err)
goto out;
- err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
- &host->tx_l1_sync_clk);
+ /* The tx lane1 clk could be muxed, hence keep this optional */
+ ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
+ &host->tx_l1_sync_clk);
}
out:
return err;
@@ -199,21 +196,11 @@ out:
static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
u32 tx_lanes;
int err = 0;
err = ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes);
- if (err)
- goto out;
- err = ufs_qcom_phy_set_tx_lane_enable(phy, tx_lanes);
- if (err)
- dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable failed\n",
- __func__);
-
-out:
return err;
}
@@ -269,13 +256,16 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host)
static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
+ struct phy *phy_lane0 = host->phy_lane0;
+ struct phy *phy_lane1 = host->phy_lane1;
int ret = 0;
bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
? true : false;
- if (is_rate_B)
- phy_set_mode(phy, PHY_MODE_UFS_HS_B);
+ if (is_rate_B) {
+ phy_set_mode(phy_lane0, PHY_MODE_UFS_HS_B);
+ phy_set_mode(phy_lane1, PHY_MODE_UFS_HS_B);
+ }
/* Assert PHY reset and apply PHY calibration values */
ufs_qcom_assert_reset(hba);
@@ -283,9 +273,16 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
usleep_range(1000, 1100);
/* phy initialization - calibrate the phy */
- ret = phy_init(phy);
+ ret = phy_init(phy_lane0);
if (ret) {
- dev_err(hba->dev, "%s: phy init failed, ret = %d\n",
+ dev_err(hba->dev, "%s: phy lane0 init failed, ret = %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ ret = phy_init(phy_lane1);
+ if (ret) {
+ dev_err(hba->dev, "%s: phy lane1 init failed, ret = %d\n",
__func__, ret);
goto out;
}
@@ -300,9 +297,16 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
usleep_range(1000, 1100);
/* power on phy - start serdes and phy's power and clocks */
- ret = phy_power_on(phy);
+ ret = phy_power_on(phy_lane0);
+ if (ret) {
+ dev_err(hba->dev, "%s: phy lane0 power on failed, ret = %d\n",
+ __func__, ret);
+ goto out_disable_phy;
+ }
+
+ ret = phy_power_on(phy_lane1);
if (ret) {
- dev_err(hba->dev, "%s: phy power on failed, ret = %d\n",
+ dev_err(hba->dev, "%s: phy lane1 power on failed, ret = %d\n",
__func__, ret);
goto out_disable_phy;
}
@@ -313,7 +317,8 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
out_disable_phy:
ufs_qcom_assert_reset(hba);
- phy_exit(phy);
+ phy_exit(phy_lane0);
+ phy_exit(phy_lane1);
out:
return ret;
}
@@ -564,7 +569,8 @@ out:
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;
+ struct phy *phy_lane0 = host->phy_lane0;
+ struct phy *phy_lane1 = host->phy_lane1;
int ret = 0;
if (ufs_qcom_is_link_off(hba)) {
@@ -574,7 +580,8 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
* after downstream clocks are disabled.
*/
ufs_qcom_disable_lane_clks(host);
- phy_power_off(phy);
+ phy_power_off(phy_lane0);
+ phy_power_off(phy_lane1);
/* Assert PHY soft reset */
ufs_qcom_assert_reset(hba);
@@ -587,7 +594,8 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
*/
if (!ufs_qcom_is_link_active(hba)) {
ufs_qcom_disable_lane_clks(host);
- phy_power_off(phy);
+ phy_power_off(phy_lane0);
+ phy_power_off(phy_lane1);
}
out:
@@ -597,12 +605,20 @@ out:
static int ufs_qcom_resume(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;
+ struct phy *phy_lane0 = host->phy_lane0;
+ struct phy *phy_lane1 = host->phy_lane1;
int err;
- err = phy_power_on(phy);
+ err = phy_power_on(phy_lane0);
+ if (err) {
+ dev_err(hba->dev, "%s: failed enabling phy lane0 regs, err = %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ err = phy_power_on(phy_lane1);
if (err) {
- dev_err(hba->dev, "%s: failed enabling regs, err = %d\n",
+ dev_err(hba->dev, "%s: failed enabling phy lane1 regs, err = %d\n",
__func__, err);
goto out;
}
@@ -941,12 +957,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
- u32 val;
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- struct phy *phy = host->generic_phy;
struct ufs_qcom_dev_params ufs_qcom_cap;
int ret = 0;
- int res = 0;
if (!dev_req_params) {
pr_err("%s: incoming dev_req_params is NULL\n", __func__);
@@ -1012,14 +1025,6 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
ret = -EINVAL;
}
- val = ~(MAX_U32 << dev_req_params->lane_tx);
- res = ufs_qcom_phy_set_tx_lane_enable(phy, val);
- if (res) {
- dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable() failed res = %d\n",
- __func__, res);
- ret = res;
- }
-
/* cache the power mode parameters to use internally */
memcpy(&host->dev_req_params,
dev_req_params, sizeof(*dev_req_params));
@@ -1089,12 +1094,12 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
{
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- if (host->hw_ver.major == 0x01) {
+ if (host->hw_ver.major == 0x1) {
hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
| UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP
| UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE;
- if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001)
+ if (host->hw_ver.minor == 0x001 && host->hw_ver.step == 0x0001)
hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR;
hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
@@ -1149,7 +1154,8 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
return 0;
if (on && (status == POST_CHANGE)) {
- phy_power_on(host->generic_phy);
+ phy_power_on(host->phy_lane0);
+ phy_power_on(host->phy_lane1);
/* enable the device ref clock for HS mode*/
if (ufshcd_is_hs_mode(&hba->pwr_info))
@@ -1164,7 +1170,8 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on,
ufs_qcom_dev_ref_clk_ctrl(host, false);
/* powering off PHY during aggressive clk gating */
- phy_power_off(host->generic_phy);
+ phy_power_off(host->phy_lane0);
+ phy_power_off(host->phy_lane1);
}
vote = host->bus_vote.min_bw_vote;
@@ -1227,21 +1234,49 @@ static int ufs_qcom_init(struct ufs_hba *hba)
* skip devoting it during aggressive clock gating. This clock
* will still be gated off during runtime suspend.
*/
- host->generic_phy = devm_phy_get(dev, "ufsphy");
+ host->phy_lane0 = devm_phy_get(dev, "ufsphy_0");
+ if (IS_ERR(host->phy_lane0) && PTR_ERR(host->phy_lane0) == -ENODEV)
+ host->phy_lane0 = devm_phy_get(dev, "ufsphy");
+
+ if (IS_ERR(host->phy_lane0)) {
+ err = PTR_ERR(host->phy_lane0);
+ if (err == -ENODEV) {
+ host->phy_lane0 = NULL;
+ } else if (err == -EPROBE_DEFER) {
+ /*
+ * UFS driver might be probed before the phy driver
+ * does. In that case we would like to return
+ * EPROBE_DEFER code.
+ */
+ dev_warn(dev, "%s: required ufsphy_0 device. hasn't probed yet. err = %d\n",
+ __func__, err);
+ goto out_variant_clear;
+ } else {
+ dev_err(dev, "%s: ufsphy_0 get failed %d\n",
+ __func__, err);
+ goto out;
+ }
+ }
- if (host->generic_phy == ERR_PTR(-EPROBE_DEFER)) {
- /*
- * UFS driver might be probed before the phy driver does.
- * In that case we would like to return EPROBE_DEFER code.
- */
- err = -EPROBE_DEFER;
- dev_warn(dev, "%s: required phy device. hasn't probed yet. err = %d\n",
- __func__, err);
- goto out_variant_clear;
- } else if (IS_ERR(host->generic_phy)) {
- err = PTR_ERR(host->generic_phy);
- dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
- goto out_variant_clear;
+ host->phy_lane1 = devm_phy_get(dev, "ufsphy_1");
+ if (IS_ERR(host->phy_lane1)) {
+ err = PTR_ERR(host->phy_lane1);
+ if (err == -ENODEV) {
+ host->phy_lane1 = NULL;
+ } else if (err == -EPROBE_DEFER) {
+ /*
+ * UFS driver might be probed before the phy driver
+ * does. In that case we would like to return
+ * EPROBE_DEFER code.
+ */
+ dev_warn(dev, "%s: required ufsphy_1 device. hasn't probed yet. err = %d\n",
+ __func__, err);
+ goto out_variant_clear;
+ } else {
+ dev_err(dev, "%s: ufsphy_1 get failed %d\n",
+ __func__, err);
+ goto out;
+ }
}
err = ufs_qcom_bus_register(host);
@@ -1275,10 +1310,6 @@ static int ufs_qcom_init(struct ufs_hba *hba)
}
}
- /* update phy revision information before calling phy_init() */
- ufs_qcom_phy_save_controller_version(host->generic_phy,
- host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
-
err = ufs_qcom_init_lane_clks(host);
if (err)
goto out_variant_clear;
@@ -1313,8 +1344,10 @@ static void ufs_qcom_exit(struct ufs_hba *hba)
struct ufs_qcom_host *host = ufshcd_get_variant(hba);
ufs_qcom_disable_lane_clks(host);
- phy_power_off(host->generic_phy);
- phy_exit(host->generic_phy);
+ phy_power_off(host->phy_lane0);
+ phy_power_off(host->phy_lane1);
+ phy_exit(host->phy_lane0);
+ phy_exit(host->phy_lane1);
}
static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index 295f4bef6a0e..06b744c8af1d 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015,2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -223,7 +223,8 @@ struct ufs_qcom_host {
#define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE 0x2
u32 caps;
- struct phy *generic_phy;
+ struct phy *phy_lane0;
+ struct phy *phy_lane1;
struct ufs_hba *hba;
struct ufs_qcom_bus_vote bus_vote;
struct ufs_pa_layer_attr dev_req_params;
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 397081d320b1..7bd5a086793b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6734,6 +6734,7 @@ static struct scsi_host_template ufshcd_driver_template = {
.max_host_blocked = 1,
.track_queue_depth = 1,
.sdev_groups = ufshcd_driver_groups,
+ .no_write_same = 1,
};
static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index f51758f1e5cc..9f68b85538c1 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-2018, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -72,6 +72,8 @@
#define UFSHCD "ufshcd"
#define UFSHCD_DRIVER_VERSION "0.2"
+#define UFS_BIT(x) BIT(x)
+
struct ufs_hba;
enum dev_cmd_type {
@@ -865,6 +867,15 @@ static inline bool ufshcd_is_hs_mode(struct ufs_pa_layer_attr *pwr_info)
pwr_info->pwr_tx == FASTAUTO_MODE);
}
+/* variant specific ops structures */
+#ifdef CONFIG_SCSI_UFS_MSM
+extern const struct ufs_hba_variant_ops ufs_hba_msm_vops;
+#else
+static const struct ufs_hba_variant_ops ufs_hba_msm_vops = {
+ .name = "msm",
+};
+#endif
+
/* Expose Query-Request API */
int ufshcd_query_descriptor_retry(struct ufs_hba *hba,
enum query_opcode opcode,
diff --git a/drivers/slimbus/Kconfig b/drivers/slimbus/Kconfig
index 1a632fad597e..9d73ad806698 100644
--- a/drivers/slimbus/Kconfig
+++ b/drivers/slimbus/Kconfig
@@ -15,10 +15,20 @@ if SLIMBUS
# SLIMbus controllers
config SLIM_QCOM_CTRL
tristate "Qualcomm SLIMbus Manager Component"
- depends on SLIMBUS
depends on HAS_IOMEM
help
Select driver if Qualcomm's SLIMbus Manager Component is
programmed using Linux kernel.
+config SLIM_QCOM_NGD_CTRL
+ tristate "Qualcomm SLIMbus Satellite Non-Generic Device Component"
+ depends on QCOM_QMI_HELPERS
+ depends on HAS_IOMEM && DMA_ENGINE
+ help
+ Select driver if Qualcomm's SLIMbus Satellite Non-Generic Device
+ Component is programmed using Linux kernel.
+ This is light-weight slimbus controller driver responsible for
+ communicating with slave HW directly over the bus using messaging
+ interface, and communicating with master component residing on ADSP
+ for bandwidth and data-channel management.
endif
diff --git a/drivers/slimbus/Makefile b/drivers/slimbus/Makefile
index a35a3da4eb78..d9aa011b6804 100644
--- a/drivers/slimbus/Makefile
+++ b/drivers/slimbus/Makefile
@@ -3,8 +3,11 @@
# Makefile for kernel SLIMbus framework.
#
obj-$(CONFIG_SLIMBUS) += slimbus.o
-slimbus-y := core.o messaging.o sched.o
+slimbus-y := core.o messaging.o sched.o stream.o
#Controllers
obj-$(CONFIG_SLIM_QCOM_CTRL) += slim-qcom-ctrl.o
slim-qcom-ctrl-y := qcom-ctrl.o
+
+obj-$(CONFIG_SLIM_QCOM_NGD_CTRL) += slim-qcom-ngd-ctrl.o
+slim-qcom-ngd-ctrl-y := qcom-ngd-ctrl.o
diff --git a/drivers/slimbus/core.c b/drivers/slimbus/core.c
index 7ddfc675b131..88248a4ecad9 100644
--- a/drivers/slimbus/core.c
+++ b/drivers/slimbus/core.c
@@ -356,6 +356,45 @@ struct slim_device *slim_get_device(struct slim_controller *ctrl,
}
EXPORT_SYMBOL_GPL(slim_get_device);
+static int of_slim_match_dev(struct device *dev, void *data)
+{
+ struct device_node *np = data;
+ struct slim_device *sbdev = to_slim_device(dev);
+
+ return (sbdev->dev.of_node == np);
+}
+
+static struct slim_device *of_find_slim_device(struct slim_controller *ctrl,
+ struct device_node *np)
+{
+ struct slim_device *sbdev;
+ struct device *dev;
+
+ dev = device_find_child(ctrl->dev, np, of_slim_match_dev);
+ if (dev) {
+ sbdev = to_slim_device(dev);
+ return sbdev;
+ }
+
+ return NULL;
+}
+
+/**
+ * of_slim_get_device() - get handle to a device using dt node.
+ *
+ * @ctrl: Controller on which this device will be added/queried
+ * @np: node pointer to device
+ *
+ * Return: pointer to a device if it has already reported. Creates a new
+ * device and returns pointer to it if the device has not yet enumerated.
+ */
+struct slim_device *of_slim_get_device(struct slim_controller *ctrl,
+ struct device_node *np)
+{
+ return of_find_slim_device(ctrl, np);
+}
+EXPORT_SYMBOL_GPL(of_slim_get_device);
+
static int slim_device_alloc_laddr(struct slim_device *sbdev,
bool report_present)
{
diff --git a/drivers/slimbus/messaging.c b/drivers/slimbus/messaging.c
index 457ea1f8db30..9608f6309f9e 100644
--- a/drivers/slimbus/messaging.c
+++ b/drivers/slimbus/messaging.c
@@ -7,6 +7,70 @@
#include <linux/pm_runtime.h>
#include "slimbus.h"
+static char *mc_strs[] = {
+[0x0] ="SLIM_USR_MC_MASTER_CAPABILITY",
+[0x1] ="SLIM_MSG_MC_REPORT_PRESENT",
+[0x2] ="SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS",
+[0x4] ="SLIM_MSG_MC_RESET_DEVICE",
+[0x8] ="SLIM_MSG_MC_CHANGE_LOGICAL_ADDRESS",
+[0x9] ="SLIM_MSG_MC_CHANGE_ARBITRATION_PRIORITY",
+[0xC] ="SLIM_MSG_MC_REQUEST_SELF_ANNOUNCEMENT",
+[0xD] ="SLIM_USR_MC_ADDR_QUERY",
+[0xE] ="SLIM_USR_MC_ADDR_REPLY",
+[0xF] ="SLIM_MSG_MC_REPORT_ABSENT",
+[0x10] ="SLIM_MSG_MC_CONNECT_SOURCE",
+[0x11] ="SLIM_MSG_MC_CONNECT_SINK",
+[0x14] ="SLIM_MSG_MC_DISCONNECT_PORT",
+[0x18] ="SLIM_MSG_MC_CHANGE_CONTENT",
+[0x20] ="SLIM_MSG_MC_REQUEST_INFORMATION",
+[0x21] ="SLIM_MSG_MC_REQUEST_CLEAR_INFORMATION",
+[0x24] ="SLIM_MSG_MC_REPLY_INFORMATION",
+[0x28] ="SLIM_MSG_MC_CLEAR_INFORMATION",
+[0x29] ="SLIM_MSG_MC_REPORT_INFORMATION",
+[0x40] ="SLIM_MSG_MC_BEGIN_RECONFIGURATION",
+[0x44] ="SLIM_MSG_MC_NEXT_ACTIVE_FRAMER",
+[0x45] ="SLIM_MSG_MC_NEXT_SUBFRAME_MODE",
+[0x46] ="SLIM_MSG_MC_NEXT_CLOCK_GEAR",
+[0x47] ="SLIM_MSG_MC_NEXT_ROOT_FREQUENCY",
+[0x4A] ="SLIM_MSG_MC_NEXT_PAUSE_CLOCK",
+[0x4B] ="SLIM_MSG_MC_NEXT_RESET_BUS",
+[0x4C] ="SLIM_MSG_MC_NEXT_SHUTDOWN_BUS",
+[0x50] ="SLIM_MSG_MC_NEXT_DEFINE_CHANNEL",
+[0x51] ="SLIM_MSG_MC_NEXT_DEFINE_CONTENT",
+[0x54] ="SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL",
+[0x55] ="SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL",
+[0x58] ="SLIM_MSG_MC_NEXT_REMOVE_CHANNEL",
+[0x5F] ="SLIM_MSG_MC_RECONFIGURE_NOW",
+[0x60] ="SLIM_MSG_MC_REQUEST_VALUE",
+[0x61] ="SLIM_MSG_MC_REQUEST_CHANGE_VALUE",
+[0x64] ="SLIM_MSG_MC_REPLY_VALUE",
+[0x68] ="SLIM_MSG_MC_CHANGE_VALUE",
+[0x25] = "SLIM_USR_MC_GENERIC_ACK",
+[0x0] = "SLIM_USR_MC_MASTER_CAPABILITY",
+[0x1] = "SLIM_USR_MC_REPORT_SATELLITE",
+[0xD] = "SLIM_USR_MC_ADDR_QUERY",
+[0xE] = "SLIM_USR_MC_ADDR_REPLY",
+[0x20] = "SLIM_USR_MC_DEFINE_CHAN",
+[0x21] = "SLIM_USR_MC_DEF_ACT_CHAN",
+[0x23] = "SLIM_USR_MC_CHAN_CTRL",
+[0x24] = "SLIM_USR_MC_RECONFIG_NOW",
+[0x28] = "SLIM_USR_MC_REQ_BW",
+[0x2C] = "SLIM_USR_MC_CONNECT_SRC",
+[0x2D] = "SLIM_USR_MC_CONNECT_SINK",
+[0x2E] = "SLIM_USR_MC_DISCONNECT_PORT",
+};
+
+char * get_mc_name(int mc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mc_strs); i++)
+ if (i == mc)
+ return mc_strs[i];
+
+ return "NULL";
+}
+EXPORT_SYMBOL_GPL(get_mc_name);
/**
* slim_msg_response() - Deliver Message response received from a device to the
* framework.
@@ -56,6 +120,69 @@ void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 len)
EXPORT_SYMBOL_GPL(slim_msg_response);
/**
+ * slim_alloc_tid() - Allocate a tid to txn
+ *
+ * @ctrl: Controller handle
+ * @txn: transaction to be allocated with tid.
+ *
+ * Called by controller to assign a tid totransaction
+ *
+ * Return: zero on success with valid txn->tid and error code on failures.
+ */
+int slim_alloc_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&ctrl->txn_lock, flags);
+ ret = idr_alloc_cyclic(&ctrl->tid_idr, txn, 0, SLIM_MAX_TIDS, GFP_ATOMIC);
+ if (ret < 0) {
+ spin_unlock_irqrestore(&ctrl->txn_lock, flags);
+ return ret;
+ }
+ txn->tid = ret;
+ spin_unlock_irqrestore(&ctrl->txn_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(slim_alloc_tid);
+
+/**
+ * slim_prepare_txn() - Prepare a transaction
+ *
+ * @ctrl: Controller handle
+ * @txn: transaction to be prepared
+ * @done: completion for transaction if msg does not have completion
+ * @need_tid: flag to indicate if tid is required for this txn
+ * note, user defined commands would need tid.
+ *
+ * Called by controller to prepare a transaction
+ *
+ * Return: zero on success and error code on failures.
+ */
+int slim_prepare_txn(struct slim_controller *ctrl, struct slim_msg_txn *txn,
+ struct completion *done, bool need_tid)
+{
+ int ret;
+
+ txn->need_tid = need_tid;
+ if (!need_tid)
+ return 0;
+
+ ret = slim_alloc_tid(ctrl, txn);
+ if (ret < 0)
+ return ret;
+
+ if (!txn->msg->comp)
+ txn->comp = done;
+ else
+ txn->comp = txn->msg->comp;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(slim_prepare_txn);
+
+
+/**
* slim_do_transfer() - Process a SLIMbus-messaging transaction
*
* @ctrl: Controller handle
@@ -70,10 +197,9 @@ EXPORT_SYMBOL_GPL(slim_msg_response);
*/
int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn)
{
- DECLARE_COMPLETION_ONSTACK(done);
- bool need_tid = false, clk_pause_msg = false;
+ bool clk_pause_msg = false;
unsigned long flags;
- int ret, tid, timeout;
+ int ret, timeout;
/*
* do not vote for runtime-PM if the transactions are part of clock
@@ -94,28 +220,8 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn)
}
}
- need_tid = slim_tid_txn(txn->mt, txn->mc);
-
- if (need_tid) {
- spin_lock_irqsave(&ctrl->txn_lock, flags);
- tid = idr_alloc(&ctrl->tid_idr, txn, 0,
- SLIM_MAX_TIDS, GFP_ATOMIC);
- txn->tid = tid;
-
- if (!txn->msg->comp)
- txn->comp = &done;
- else
- txn->comp = txn->comp;
-
- spin_unlock_irqrestore(&ctrl->txn_lock, flags);
-
- if (tid < 0)
- return tid;
- }
-
ret = ctrl->xfer_msg(ctrl, txn);
-
- if (ret && need_tid && !txn->msg->comp) {
+ if (!ret && txn->need_tid && !txn->msg->comp) {
unsigned long ms = txn->rl + HZ;
timeout = wait_for_completion_timeout(txn->comp,
@@ -123,7 +229,7 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn)
if (!timeout) {
ret = -ETIMEDOUT;
spin_lock_irqsave(&ctrl->txn_lock, flags);
- idr_remove(&ctrl->tid_idr, tid);
+ idr_remove(&ctrl->tid_idr, txn->tid);
spin_unlock_irqrestore(&ctrl->txn_lock, flags);
}
}
@@ -133,13 +239,14 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn)
txn->mt, txn->mc, txn->la, ret);
slim_xfer_err:
- if (!clk_pause_msg && (!need_tid || ret == -ETIMEDOUT)) {
+ if (!clk_pause_msg && (!txn->need_tid || ret == -ETIMEDOUT)) {
/*
* remove runtime-pm vote if this was TX only, or
* if there was error during this transaction
*/
pm_runtime_mark_last_busy(ctrl->dev);
- pm_runtime_mark_last_busy(ctrl->dev);
+ pm_runtime_put_autosuspend(ctrl->dev);
+
}
return ret;
}
@@ -205,6 +312,8 @@ int slim_xfer_msg(struct slim_device *sbdev, struct slim_val_inf *msg,
DEFINE_SLIM_LDEST_TXN(txn_stack, mc, 6, sbdev->laddr, msg);
struct slim_msg_txn *txn = &txn_stack;
struct slim_controller *ctrl = sbdev->ctrl;
+ DECLARE_COMPLETION_ONSTACK(done);
+ bool need_tid = false;
int ret;
u16 sl;
@@ -232,10 +341,16 @@ int slim_xfer_msg(struct slim_device *sbdev, struct slim_val_inf *msg,
break;
}
- if (slim_tid_txn(txn->mt, txn->mc))
+ if (slim_tid_txn(txn->mt, txn->mc)) {
txn->rl++;
+ need_tid = true;
+ }
+
+ ret = slim_prepare_txn(ctrl, txn, &done, need_tid);
+ if (!ret)
+ return slim_do_transfer(ctrl, txn);
- return slim_do_transfer(ctrl, txn);
+ return ret;
}
EXPORT_SYMBOL_GPL(slim_xfer_msg);
@@ -246,6 +361,7 @@ static void slim_fill_msg(struct slim_val_inf *msg, u32 addr,
msg->num_bytes = count;
msg->rbuf = rbuf;
msg->wbuf = wbuf;
+ msg->comp = NULL;
}
/**
@@ -307,7 +423,7 @@ int slim_write(struct slim_device *sdev, u32 addr, size_t count, u8 *val)
{
struct slim_val_inf msg;
- slim_fill_msg(&msg, addr, count, val, NULL);
+ slim_fill_msg(&msg, addr, count, NULL, val);
return slim_xfer_msg(sdev, &msg, SLIM_MSG_MC_CHANGE_VALUE);
}
diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c
new file mode 100644
index 000000000000..6d70fadcc7d8
--- /dev/null
+++ b/drivers/slimbus/qcom-ngd-ctrl.c
@@ -0,0 +1,1489 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+// Copyright (c) 2018, Linaro Limited
+//TODO:
+// Bandwidth Mangement
+//
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/slimbus.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/soc/qcom/qmi.h>
+#include <net/sock.h>
+#include "slimbus.h"
+
+/* NGD (Non-ported Generic Device) registers */
+#define NGD_CFG 0x0
+#define NGD_CFG_ENABLE BIT(0)
+#define NGD_CFG_RX_MSGQ_EN BIT(1)
+#define NGD_CFG_TX_MSGQ_EN BIT(2)
+#define NGD_STATUS 0x4
+#define NGD_LADDR BIT(1)
+#define NGD_RX_MSGQ_CFG 0x8
+#define NGD_INT_EN 0x10
+#define NGD_INT_RECFG_DONE BIT(24)
+#define NGD_INT_TX_NACKED_2 BIT(25)
+#define NGD_INT_MSG_BUF_CONTE BIT(26)
+#define NGD_INT_MSG_TX_INVAL BIT(27)
+#define NGD_INT_IE_VE_CHG BIT(28)
+#define NGD_INT_DEV_ERR BIT(29)
+#define NGD_INT_RX_MSG_RCVD BIT(30)
+#define NGD_INT_TX_MSG_SENT BIT(31)
+#define NGD_INT_STAT 0x14
+#define NGD_INT_CLR 0x18
+#define DEF_NGD_INT_MASK (NGD_INT_TX_NACKED_2 | NGD_INT_MSG_BUF_CONTE | \
+ NGD_INT_MSG_TX_INVAL | NGD_INT_IE_VE_CHG | \
+ NGD_INT_DEV_ERR | NGD_INT_TX_MSG_SENT | \
+ NGD_INT_RX_MSG_RCVD)
+
+/* Slimbus QMI service */
+#define SLIMBUS_QMI_SVC_ID 0x0301
+#define SLIMBUS_QMI_SVC_V1 1
+#define SLIMBUS_QMI_INS_ID 0
+#define SLIMBUS_QMI_SELECT_INSTANCE_REQ_V01 0x0020
+#define SLIMBUS_QMI_SELECT_INSTANCE_RESP_V01 0x0020
+#define SLIMBUS_QMI_POWER_REQ_V01 0x0021
+#define SLIMBUS_QMI_POWER_RESP_V01 0x0021
+#define SLIMBUS_QMI_CHECK_FRAMER_STATUS_REQ 0x0022
+#define SLIMBUS_QMI_CHECK_FRAMER_STATUS_RESP 0x0022
+#define SLIMBUS_QMI_POWER_REQ_MAX_MSG_LEN 14
+#define SLIMBUS_QMI_POWER_RESP_MAX_MSG_LEN 7
+#define SLIMBUS_QMI_SELECT_INSTANCE_REQ_MAX_MSG_LEN 14
+#define SLIMBUS_QMI_SELECT_INSTANCE_RESP_MAX_MSG_LEN 7
+#define SLIMBUS_QMI_CHECK_FRAMER_STAT_RESP_MAX_MSG_LEN 7
+/* QMI response timeout of 500ms */
+#define SLIMBUS_QMI_RESP_TOUT 1000
+
+/* User defined commands */
+#define SLIM_USR_MC_GENERIC_ACK 0x25
+#define SLIM_USR_MC_MASTER_CAPABILITY 0x0
+#define SLIM_USR_MC_REPORT_SATELLITE 0x1
+#define SLIM_USR_MC_ADDR_QUERY 0xD
+#define SLIM_USR_MC_ADDR_REPLY 0xE
+#define SLIM_USR_MC_DEFINE_CHAN 0x20
+#define SLIM_USR_MC_DEF_ACT_CHAN 0x21
+#define SLIM_USR_MC_CHAN_CTRL 0x23
+#define SLIM_USR_MC_RECONFIG_NOW 0x24
+#define SLIM_USR_MC_REQ_BW 0x28
+#define SLIM_USR_MC_CONNECT_SRC 0x2C
+#define SLIM_USR_MC_CONNECT_SINK 0x2D
+#define SLIM_USR_MC_DISCONNECT_PORT 0x2E
+#define SLIM_USR_MC_REPEAT_CHANGE_VALUE 0x0
+
+#define QCOM_SLIM_NGD_AUTOSUSPEND MSEC_PER_SEC
+#define SLIM_RX_MSGQ_TIMEOUT_VAL 0x10000
+
+#define SLIM_LA_MGR 0xFF
+#define SLIM_ROOT_FREQ 24576000
+#define LADDR_RETRY 5
+
+/* Per spec.max 40 bytes per received message */
+#define SLIM_MSGQ_BUF_LEN 40
+#define QCOM_SLIM_NGD_DESC_NUM 32
+
+#define SLIM_MSG_ASM_FIRST_WORD(l, mt, mc, dt, ad) \
+ ((l) | ((mt) << 5) | ((mc) << 8) | ((dt) << 15) | ((ad) << 16))
+
+#define INIT_MX_RETRIES 10
+#define DEF_RETRY_MS 10
+#define SAT_MAGIC_LSB 0xD9
+#define SAT_MAGIC_MSB 0xC5
+#define SAT_MSG_VER 0x1
+#define SAT_MSG_PROT 0x1
+#define to_ngd(d) container_of(d, struct qcom_slim_ngd, dev)
+
+struct ngd_reg_offset_data {
+ u32 offset, size;
+};
+
+static const struct ngd_reg_offset_data ngd_v1_5_offset_info = {
+ .offset = 0x1000,
+ .size = 0x1000,
+};
+
+enum qcom_slim_ngd_state {
+ QCOM_SLIM_NGD_CTRL_AWAKE,
+ QCOM_SLIM_NGD_CTRL_IDLE,
+ QCOM_SLIM_NGD_CTRL_ASLEEP,
+ QCOM_SLIM_NGD_CTRL_DOWN,
+};
+
+struct qcom_slim_ngd_qmi {
+ struct qmi_handle qmi;
+ struct sockaddr_qrtr svc_info;
+ struct qmi_handle svc_event_hdl;
+ struct qmi_response_type_v01 resp;
+ struct qmi_handle *handle;
+ struct completion qmi_comp;
+};
+
+struct qcom_slim_ngd_ctrl;
+struct qcom_slim_ngd;
+
+struct qcom_slim_ngd_dma_desc {
+ struct dma_async_tx_descriptor *desc;
+ struct qcom_slim_ngd_ctrl *ctrl;
+ struct completion *comp;
+ dma_cookie_t cookie;
+ dma_addr_t phys;
+ void *base;
+};
+
+struct qcom_slim_ngd {
+ struct platform_device *pdev;
+ void __iomem *base;
+ int id;
+};
+
+struct qcom_slim_ngd_ctrl {
+ struct slim_framer framer;
+ struct slim_controller ctrl;
+ struct qcom_slim_ngd_qmi qmi;
+ struct qcom_slim_ngd *ngd;
+ struct device *dev;
+ void __iomem *base;
+ struct dma_chan *dma_rx_channel;
+ struct dma_chan *dma_tx_channel;
+ struct qcom_slim_ngd_dma_desc rx_desc[QCOM_SLIM_NGD_DESC_NUM];
+ struct qcom_slim_ngd_dma_desc txdesc[QCOM_SLIM_NGD_DESC_NUM];
+ struct completion reconf;
+ struct work_struct m_work;
+ struct workqueue_struct *mwq;
+ spinlock_t tx_buf_lock;
+ enum qcom_slim_ngd_state state;
+ dma_addr_t rx_phys_base;
+ dma_addr_t tx_phys_base;
+ void *rx_base;
+ void *tx_base;
+ int tx_tail;
+ int tx_head;
+ u32 ver;
+};
+
+enum slimbus_mode_enum_type_v01 {
+ /* To force a 32 bit signed enum. Do not change or use*/
+ SLIMBUS_MODE_ENUM_TYPE_MIN_ENUM_VAL_V01 = INT_MIN,
+ SLIMBUS_MODE_SATELLITE_V01 = 1,
+ SLIMBUS_MODE_MASTER_V01 = 2,
+ SLIMBUS_MODE_ENUM_TYPE_MAX_ENUM_VAL_V01 = INT_MAX,
+};
+
+enum slimbus_pm_enum_type_v01 {
+ /* To force a 32 bit signed enum. Do not change or use*/
+ SLIMBUS_PM_ENUM_TYPE_MIN_ENUM_VAL_V01 = INT_MIN,
+ SLIMBUS_PM_INACTIVE_V01 = 1,
+ SLIMBUS_PM_ACTIVE_V01 = 2,
+ SLIMBUS_PM_ENUM_TYPE_MAX_ENUM_VAL_V01 = INT_MAX,
+};
+
+enum slimbus_resp_enum_type_v01 {
+ SLIMBUS_RESP_ENUM_TYPE_MIN_VAL_V01 = INT_MIN,
+ SLIMBUS_RESP_SYNCHRONOUS_V01 = 1,
+ SLIMBUS_RESP_ENUM_TYPE_MAX_VAL_V01 = INT_MAX,
+};
+
+struct slimbus_select_inst_req_msg_v01 {
+ uint32_t instance;
+ uint8_t mode_valid;
+ enum slimbus_mode_enum_type_v01 mode;
+};
+
+struct slimbus_select_inst_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+struct slimbus_power_req_msg_v01 {
+ enum slimbus_pm_enum_type_v01 pm_req;
+ uint8_t resp_type_valid;
+ enum slimbus_resp_enum_type_v01 resp_type;
+};
+
+struct slimbus_power_resp_msg_v01 {
+ struct qmi_response_type_v01 resp;
+};
+
+static struct qmi_elem_info slimbus_select_inst_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(uint32_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct slimbus_select_inst_req_msg_v01,
+ instance),
+ .ei_array = NULL,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct slimbus_select_inst_req_msg_v01,
+ mode_valid),
+ .ei_array = NULL,
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(enum slimbus_mode_enum_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct slimbus_select_inst_req_msg_v01,
+ mode),
+ .ei_array = NULL,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .elem_len = 0,
+ .elem_size = 0,
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x00,
+ .offset = 0,
+ .ei_array = NULL,
+ },
+};
+
+static struct qmi_elem_info slimbus_select_inst_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct slimbus_select_inst_resp_msg_v01,
+ resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .elem_len = 0,
+ .elem_size = 0,
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x00,
+ .offset = 0,
+ .ei_array = NULL,
+ },
+};
+
+static struct qmi_elem_info slimbus_power_req_msg_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(enum slimbus_pm_enum_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct slimbus_power_req_msg_v01,
+ pm_req),
+ .ei_array = NULL,
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(uint8_t),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct slimbus_power_req_msg_v01,
+ resp_type_valid),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum slimbus_resp_enum_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x10,
+ .offset = offsetof(struct slimbus_power_req_msg_v01,
+ resp_type),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .elem_len = 0,
+ .elem_size = 0,
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x00,
+ .offset = 0,
+ .ei_array = NULL,
+ },
+};
+
+static struct qmi_elem_info slimbus_power_resp_msg_v01_ei[] = {
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = 1,
+ .elem_size = sizeof(struct qmi_response_type_v01),
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x02,
+ .offset = offsetof(struct slimbus_power_resp_msg_v01, resp),
+ .ei_array = qmi_response_type_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .elem_len = 0,
+ .elem_size = 0,
+ .array_type = NO_ARRAY,
+ .tlv_type = 0x00,
+ .offset = 0,
+ .ei_array = NULL,
+ },
+};
+
+static int qcom_slim_qmi_send_select_inst_req(struct qcom_slim_ngd_ctrl *ctrl,
+ struct slimbus_select_inst_req_msg_v01 *req)
+{
+ struct slimbus_select_inst_resp_msg_v01 resp = { { 0, 0 } };
+ struct qmi_txn txn;
+ int rc;
+
+ rc = qmi_txn_init(ctrl->qmi.handle, &txn,
+ slimbus_select_inst_resp_msg_v01_ei, &resp);
+ if (rc < 0) {
+ dev_err(ctrl->dev, "QMI TXN init fail: %d\n", rc);
+ return rc;
+ }
+
+ rc = qmi_send_request(ctrl->qmi.handle, NULL, &txn,
+ SLIMBUS_QMI_SELECT_INSTANCE_REQ_V01,
+ SLIMBUS_QMI_SELECT_INSTANCE_REQ_MAX_MSG_LEN,
+ slimbus_select_inst_req_msg_v01_ei, req);
+ if (rc < 0) {
+ dev_err(ctrl->dev, "QMI send req fail %d\n", rc);
+ qmi_txn_cancel(&txn);
+ return rc;
+ }
+
+ rc = qmi_txn_wait(&txn, SLIMBUS_QMI_RESP_TOUT);
+ if (rc < 0) {
+ dev_err(ctrl->dev, "QMI TXN wait fail: %d\n", rc);
+ return rc;
+ }
+ /* Check the response */
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ dev_err(ctrl->dev, "QMI request failed 0x%x\n",
+ resp.resp.result);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static void qcom_slim_qmi_power_resp_cb(struct qmi_handle *handle,
+ struct sockaddr_qrtr *sq,
+ struct qmi_txn *txn, const void *data)
+{
+ struct slimbus_power_resp_msg_v01 *resp;
+
+ resp = (struct slimbus_power_resp_msg_v01 *)data;
+ if (resp->resp.result != QMI_RESULT_SUCCESS_V01)
+ pr_err("QMI power request failed 0x%x\n",
+ resp->resp.result);
+
+ complete(&txn->completion);
+}
+
+static int qcom_slim_qmi_send_power_request(struct qcom_slim_ngd_ctrl *ctrl,
+ struct slimbus_power_req_msg_v01 *req)
+{
+ struct slimbus_power_resp_msg_v01 resp = { { 0, 0 } };
+ struct qmi_txn txn;
+ int rc;
+
+ rc = qmi_txn_init(ctrl->qmi.handle, &txn,
+ slimbus_power_resp_msg_v01_ei, &resp);
+
+ rc = qmi_send_request(ctrl->qmi.handle, NULL, &txn,
+ SLIMBUS_QMI_POWER_REQ_V01,
+ SLIMBUS_QMI_POWER_REQ_MAX_MSG_LEN,
+ slimbus_power_req_msg_v01_ei, req);
+ if (rc < 0) {
+ dev_err(ctrl->dev, "QMI send req fail %d\n", rc);
+ qmi_txn_cancel(&txn);
+ return rc;
+ }
+
+ rc = qmi_txn_wait(&txn, SLIMBUS_QMI_RESP_TOUT);
+ if (rc < 0) {
+ dev_err(ctrl->dev, "QMI TXN wait fail: %d\n", rc);
+ return rc;
+ }
+
+ /* Check the response */
+ if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ dev_err(ctrl->dev, "QMI request failed 0x%x\n",
+ resp.resp.result);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static struct qmi_msg_handler qcom_slim_qmi_msg_handlers[] = {
+ {
+ .type = QMI_RESPONSE,
+ .msg_id = SLIMBUS_QMI_POWER_RESP_V01,
+ .ei = slimbus_power_resp_msg_v01_ei,
+ .decoded_size = sizeof(struct slimbus_power_resp_msg_v01),
+ .fn = qcom_slim_qmi_power_resp_cb,
+ },
+ {}
+};
+
+static int qcom_slim_qmi_init(struct qcom_slim_ngd_ctrl *ctrl,
+ bool apps_is_master)
+{
+ struct slimbus_select_inst_req_msg_v01 req;
+ struct qmi_handle *handle;
+ int rc;
+
+ handle = devm_kzalloc(ctrl->dev, sizeof(*handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ rc = qmi_handle_init(handle, SLIMBUS_QMI_POWER_REQ_MAX_MSG_LEN,
+ NULL, qcom_slim_qmi_msg_handlers);
+ if (rc < 0) {
+ dev_err(ctrl->dev, "QMI client init failed: %d\n", rc);
+ goto qmi_handle_init_failed;
+ }
+
+ rc = kernel_connect(handle->sock,
+ (struct sockaddr *)&ctrl->qmi.svc_info,
+ sizeof(ctrl->qmi.svc_info), 0);
+ if (rc < 0) {
+ dev_err(ctrl->dev, "Remote Service connect failed: %d\n", rc);
+ goto qmi_connect_to_service_failed;
+ }
+
+ /* Instance is 0 based */
+ req.instance = (ctrl->ngd->id >> 1);
+ req.mode_valid = 1;
+
+ /* Mode indicates the role of the ADSP */
+ if (apps_is_master)
+ req.mode = SLIMBUS_MODE_SATELLITE_V01;
+ else
+ req.mode = SLIMBUS_MODE_MASTER_V01;
+
+ ctrl->qmi.handle = handle;
+
+ rc = qcom_slim_qmi_send_select_inst_req(ctrl, &req);
+ if (rc) {
+ dev_err(ctrl->dev, "failed to select h/w instance\n");
+ goto qmi_select_instance_failed;
+ }
+
+ return 0;
+
+qmi_select_instance_failed:
+ ctrl->qmi.handle = NULL;
+qmi_connect_to_service_failed:
+ qmi_handle_release(handle);
+qmi_handle_init_failed:
+ devm_kfree(ctrl->dev, handle);
+ return rc;
+}
+
+static void qcom_slim_qmi_exit(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ if (!ctrl->qmi.handle)
+ return;
+
+ qmi_handle_release(ctrl->qmi.handle);
+ devm_kfree(ctrl->dev, ctrl->qmi.handle);
+ ctrl->qmi.handle = NULL;
+}
+
+static int qcom_slim_qmi_power_request(struct qcom_slim_ngd_ctrl *ctrl,
+ bool active)
+{
+ struct slimbus_power_req_msg_v01 req;
+
+ if (active)
+ req.pm_req = SLIMBUS_PM_ACTIVE_V01;
+ else
+ req.pm_req = SLIMBUS_PM_INACTIVE_V01;
+
+ req.resp_type_valid = 0;
+
+ return qcom_slim_qmi_send_power_request(ctrl, &req);
+}
+
+static u32 *qcom_slim_ngd_tx_msg_get(struct qcom_slim_ngd_ctrl *ctrl, int len,
+ struct completion *comp)
+{
+ struct qcom_slim_ngd_dma_desc *desc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->tx_buf_lock, flags);
+
+ if ((ctrl->tx_tail + 1) % QCOM_SLIM_NGD_DESC_NUM == ctrl->tx_head) {
+ spin_unlock_irqrestore(&ctrl->tx_buf_lock, flags);
+ return NULL;
+ }
+ desc = &ctrl->txdesc[ctrl->tx_tail];
+ desc->base = ctrl->tx_base + ctrl->tx_tail * SLIM_MSGQ_BUF_LEN;
+ desc->comp = comp;
+ ctrl->tx_tail = (ctrl->tx_tail + 1) % QCOM_SLIM_NGD_DESC_NUM;
+
+ spin_unlock_irqrestore(&ctrl->tx_buf_lock, flags);
+
+ return desc->base;
+}
+
+static void qcom_slim_ngd_tx_msg_dma_cb(void *args)
+{
+ struct qcom_slim_ngd_dma_desc *desc = args;
+ struct qcom_slim_ngd_ctrl *ctrl = desc->ctrl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrl->tx_buf_lock, flags);
+
+ if (desc->comp) {
+ complete(desc->comp);
+ desc->comp = NULL;
+ }
+
+ ctrl->tx_head = (ctrl->tx_head + 1) % QCOM_SLIM_NGD_DESC_NUM;
+ spin_unlock_irqrestore(&ctrl->tx_buf_lock, flags);
+}
+
+static int qcom_slim_ngd_tx_msg_post(struct qcom_slim_ngd_ctrl *ctrl,
+ void *buf, int len)
+{
+ struct qcom_slim_ngd_dma_desc *desc;
+ unsigned long flags;
+ int index, offset;
+
+ spin_lock_irqsave(&ctrl->tx_buf_lock, flags);
+ offset = buf - ctrl->tx_base;
+ index = offset/SLIM_MSGQ_BUF_LEN;
+
+ desc = &ctrl->txdesc[index];
+ desc->phys = ctrl->tx_phys_base + offset;
+ desc->base = ctrl->tx_base + offset;
+ desc->ctrl = ctrl;
+ len = (len + 3) & 0xfc;
+
+ desc->desc = dmaengine_prep_slave_single(ctrl->dma_tx_channel,
+ desc->phys, len,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT);
+ if (!desc->desc) {
+ dev_err(ctrl->dev, "unable to prepare channel\n");
+ spin_unlock_irqrestore(&ctrl->tx_buf_lock, flags);
+ return -EINVAL;
+ }
+
+ desc->desc->callback = qcom_slim_ngd_tx_msg_dma_cb;
+ desc->desc->callback_param = desc;
+ desc->desc->cookie = dmaengine_submit(desc->desc);
+ dma_async_issue_pending(ctrl->dma_tx_channel);
+ spin_unlock_irqrestore(&ctrl->tx_buf_lock, flags);
+
+ return 0;
+}
+
+static void qcom_slim_ngd_rx(struct qcom_slim_ngd_ctrl *ctrl, u8 *buf)
+{
+ u8 mc, mt, len;
+
+ mt = SLIM_HEADER_GET_MT(buf[0]);
+ len = SLIM_HEADER_GET_RL(buf[0]);
+ mc = SLIM_HEADER_GET_MC(buf[1]);
+
+ if (mc == SLIM_USR_MC_MASTER_CAPABILITY &&
+ mt == SLIM_MSG_MT_SRC_REFERRED_USER)
+ queue_work(ctrl->mwq, &ctrl->m_work);
+
+ if (mc == SLIM_MSG_MC_REPLY_INFORMATION ||
+ mc == SLIM_MSG_MC_REPLY_VALUE || (mc == SLIM_USR_MC_ADDR_REPLY &&
+ mt == SLIM_MSG_MT_SRC_REFERRED_USER) ||
+ (mc == SLIM_USR_MC_GENERIC_ACK && mt == SLIM_MSG_MT_SRC_REFERRED_USER)) {
+ slim_msg_response(&ctrl->ctrl, &buf[4], buf[3], len - 4);
+ pm_runtime_mark_last_busy(ctrl->dev);
+ }
+}
+
+static void qcom_slim_ngd_rx_msgq_cb(void *args)
+{
+ struct qcom_slim_ngd_dma_desc *desc = args;
+ struct qcom_slim_ngd_ctrl *ctrl = desc->ctrl;
+
+ qcom_slim_ngd_rx(ctrl, (u8 *)desc->base);
+ /* Add descriptor back to the queue */
+ desc->desc = dmaengine_prep_slave_single(ctrl->dma_rx_channel,
+ desc->phys, SLIM_MSGQ_BUF_LEN,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!desc->desc) {
+ dev_err(ctrl->dev, "Unable to prepare rx channel\n");
+ return;
+ }
+
+ desc->desc->callback = qcom_slim_ngd_rx_msgq_cb;
+ desc->desc->callback_param = desc;
+ desc->desc->cookie = dmaengine_submit(desc->desc);
+ dma_async_issue_pending(ctrl->dma_rx_channel);
+}
+
+static int qcom_slim_ngd_post_rx_msgq(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ struct qcom_slim_ngd_dma_desc *desc;
+ int i;
+
+ for (i = 0; i < QCOM_SLIM_NGD_DESC_NUM; i++) {
+ desc = &ctrl->rx_desc[i];
+ desc->phys = ctrl->rx_phys_base + i * SLIM_MSGQ_BUF_LEN;
+ desc->ctrl = ctrl;
+ desc->base = ctrl->rx_base + i * SLIM_MSGQ_BUF_LEN;
+ desc->desc = dmaengine_prep_slave_single(ctrl->dma_rx_channel,
+ desc->phys, SLIM_MSGQ_BUF_LEN,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!desc->desc) {
+ dev_err(ctrl->dev, "Unable to prepare rx channel\n");
+ return -EINVAL;
+ }
+
+ desc->desc->callback = qcom_slim_ngd_rx_msgq_cb;
+ desc->desc->callback_param = desc;
+ desc->desc->cookie = dmaengine_submit(desc->desc);
+ }
+ dma_async_issue_pending(ctrl->dma_rx_channel);
+
+ return 0;
+}
+
+static int qcom_slim_ngd_init_rx_msgq(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ struct device *dev = ctrl->dev;
+ int ret, size;
+
+ ctrl->dma_rx_channel = dma_request_slave_channel(dev, "rx");
+ if (!ctrl->dma_rx_channel) {
+ dev_err(dev, "Failed to request dma channels");
+ return -EINVAL;
+ }
+
+ size = QCOM_SLIM_NGD_DESC_NUM * SLIM_MSGQ_BUF_LEN;
+ ctrl->rx_base = dma_alloc_coherent(dev, size, &ctrl->rx_phys_base,
+ GFP_KERNEL);
+ if (!ctrl->rx_base) {
+ dev_err(dev, "dma_alloc_coherent failed\n");
+ ret = -ENOMEM;
+ goto rel_rx;
+ }
+
+ ret = qcom_slim_ngd_post_rx_msgq(ctrl);
+ if (ret) {
+ dev_err(dev, "post_rx_msgq() failed 0x%x\n", ret);
+ goto rx_post_err;
+ }
+
+ return 0;
+
+rx_post_err:
+ dma_free_coherent(dev, size, ctrl->rx_base, ctrl->rx_phys_base);
+rel_rx:
+ dma_release_channel(ctrl->dma_rx_channel);
+ return ret;
+}
+
+static int qcom_slim_ngd_init_tx_msgq(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ struct device *dev = ctrl->dev;
+ unsigned long flags;
+ int ret = 0;
+ int size;
+
+ ctrl->dma_tx_channel = dma_request_slave_channel(dev, "tx");
+ if (!ctrl->dma_tx_channel) {
+ dev_err(dev, "Failed to request dma channels");
+ return -EINVAL;
+ }
+
+ size = ((QCOM_SLIM_NGD_DESC_NUM + 1) * SLIM_MSGQ_BUF_LEN);
+ ctrl->tx_base = dma_alloc_coherent(dev, size, &ctrl->tx_phys_base,
+ GFP_KERNEL);
+ if (!ctrl->tx_base) {
+ dev_err(dev, "dma_alloc_coherent failed\n");
+ ret = -EINVAL;
+ goto rel_tx;
+ }
+
+ spin_lock_irqsave(&ctrl->tx_buf_lock, flags);
+ ctrl->tx_tail = 0;
+ ctrl->tx_head = 0;
+ spin_unlock_irqrestore(&ctrl->tx_buf_lock, flags);
+
+ return 0;
+rel_tx:
+ dma_release_channel(ctrl->dma_tx_channel);
+ return ret;
+}
+
+static int qcom_slim_ngd_init_dma(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ int ret = 0;
+
+ ret = qcom_slim_ngd_init_rx_msgq(ctrl);
+ if (ret) {
+ dev_err(ctrl->dev, "rx dma init failed\n");
+ return ret;
+ }
+
+ ret = qcom_slim_ngd_init_tx_msgq(ctrl);
+ if (ret)
+ dev_err(ctrl->dev, "tx dma init failed\n");
+
+ return ret;
+}
+
+static irqreturn_t qcom_slim_ngd_interrupt(int irq, void *d)
+{
+ struct qcom_slim_ngd_ctrl *ctrl = d;
+ void __iomem *base = ctrl->ngd->base;
+ u32 stat = readl(base + NGD_INT_STAT);
+
+ if ((stat & NGD_INT_MSG_BUF_CONTE) ||
+ (stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
+ (stat & NGD_INT_TX_NACKED_2)) {
+ dev_err(ctrl->dev, "Error Interrupt received 0x%x\n", stat);
+ }
+
+ writel(stat, base + NGD_INT_CLR);
+
+ return IRQ_HANDLED;
+}
+
+static int qcom_slim_ngd_xfer_msg(struct slim_controller *sctrl,
+ struct slim_msg_txn *txn)
+{
+ struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(sctrl->dev);
+ DECLARE_COMPLETION_ONSTACK(tx_sent);
+ DECLARE_COMPLETION_ONSTACK(done);
+ int ret, timeout, i;
+ u8 wbuf[SLIM_MSGQ_BUF_LEN];
+ u8 rbuf[SLIM_MSGQ_BUF_LEN];
+ u32 *pbuf;
+ u8 *puc;
+ u8 la = txn->la;
+
+ if (txn->mc & SLIM_MSG_CLK_PAUSE_SEQ_FLG)
+ return -EPROTONOSUPPORT;
+
+ if (txn->mt == SLIM_MSG_MT_CORE &&
+ (txn->mc >= SLIM_MSG_MC_BEGIN_RECONFIGURATION &&
+ txn->mc <= SLIM_MSG_MC_RECONFIGURE_NOW))
+ return 0;
+
+ if (txn->dt == SLIM_MSG_DEST_ENUMADDR)
+ return -EPROTONOSUPPORT;
+
+ if (txn->msg->num_bytes > SLIM_MSGQ_BUF_LEN ||
+ txn->rl > SLIM_MSGQ_BUF_LEN) {
+ dev_err(ctrl->dev, "msg exeeds HW limit\n");
+ return -EINVAL;
+ }
+
+ pbuf = qcom_slim_ngd_tx_msg_get(ctrl, txn->rl, &tx_sent);
+ if (!pbuf) {
+ dev_err(ctrl->dev, "Message buffer unavailable\n");
+ return -ENOMEM;
+ }
+
+ if (txn->mt == SLIM_MSG_MT_CORE &&
+ (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE ||
+ txn->mc == SLIM_MSG_MC_CONNECT_SINK ||
+ txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)) {
+
+ txn->mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+ if (txn->mc == SLIM_MSG_MC_CONNECT_SOURCE)
+ txn->mc = SLIM_USR_MC_CONNECT_SRC;
+ else if (txn->mc == SLIM_MSG_MC_CONNECT_SINK)
+ txn->mc = SLIM_USR_MC_CONNECT_SINK;
+ else if (txn->mc == SLIM_MSG_MC_DISCONNECT_PORT)
+ txn->mc = SLIM_USR_MC_DISCONNECT_PORT;
+ i = 0;
+ wbuf[i++] = txn->la;
+ la = SLIM_LA_MGR;
+ wbuf[i++] = txn->msg->wbuf[0];
+ if (txn->mc != SLIM_USR_MC_DISCONNECT_PORT)
+ wbuf[i++] = txn->msg->wbuf[1];
+
+ txn->comp = &done;
+ ret = slim_alloc_tid(sctrl, txn);
+ if (ret) {
+ dev_err(ctrl->dev, "Unable to allocate TID\n");
+ return ret;
+ }
+
+ wbuf[i++] = txn->tid;
+
+ txn->msg->num_bytes = i;
+ txn->msg->wbuf = wbuf;
+ txn->msg->rbuf = rbuf;
+ txn->rl = txn->msg->num_bytes + 4;
+ }
+
+ /* HW expects length field to be excluded */
+ txn->rl--;
+ puc = (u8 *)pbuf;
+ *pbuf = 0;
+ if (txn->dt == SLIM_MSG_DEST_LOGICALADDR) {
+ *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 0,
+ la);
+ puc += 3;
+ } else {
+ *pbuf = SLIM_MSG_ASM_FIRST_WORD(txn->rl, txn->mt, txn->mc, 1,
+ la);
+ puc += 2;
+ }
+
+ if (txn->mc != SLIM_USR_MC_ADDR_QUERY && slim_tid_txn(txn->mt, txn->mc))
+ *(puc++) = txn->tid;
+
+ if (slim_ec_txn(txn->mt, txn->mc)) {
+ *(puc++) = (txn->ec & 0xFF);
+ *(puc++) = (txn->ec >> 8) & 0xFF;
+ }
+
+ if (txn->msg && txn->msg->wbuf)
+ memcpy(puc, txn->msg->wbuf, txn->msg->num_bytes);
+
+ ret = qcom_slim_ngd_tx_msg_post(ctrl, pbuf, txn->rl);
+ if (ret)
+ return ret;
+
+ timeout = wait_for_completion_timeout(&tx_sent, HZ);
+ if (!timeout) {
+ dev_err(sctrl->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc,
+ txn->mt);
+ return -ETIMEDOUT;
+ }
+
+ if (txn->mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
+ (txn->mc == SLIM_USR_MC_CONNECT_SRC ||
+ txn->mc == SLIM_USR_MC_CONNECT_SINK ||
+ txn->mc == SLIM_USR_MC_DISCONNECT_PORT)) {
+ timeout = wait_for_completion_timeout(&done, HZ);
+ if (!timeout) {
+ dev_err(sctrl->dev, "TX timed out:MC:0x%x,mt:0x%x", txn->mc,
+ txn->mt);
+ //FIXME purge all the transactions if they are failed...
+ return -ETIMEDOUT;
+ }
+
+ }
+
+ return 0;
+}
+
+static int qcom_slim_ngd_enable_stream(struct slim_stream_runtime *rt)
+{
+ struct slim_device *sdev = rt->dev;
+ struct slim_controller *ctrl = sdev->ctrl;
+ struct slim_val_inf msg = {0};
+ u8 wbuf[SLIM_MSGQ_BUF_LEN];
+ u8 rbuf[SLIM_MSGQ_BUF_LEN];
+ DECLARE_COMPLETION_ONSTACK(done);
+ struct slim_msg_txn txn = {0,};
+ int i, timeout, ret;
+
+ txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.la = SLIM_LA_MGR;
+ txn.ec = 0;
+ txn.msg = &msg;
+ txn.msg->num_bytes = 0;
+ txn.msg->wbuf = wbuf;
+ txn.msg->rbuf = rbuf;
+
+ for (i = 0; i < rt->num_ports; i++) {
+ struct slim_port *port = &rt->ports[i];
+ if (txn.msg->num_bytes == 0) {
+ int fl = 1; /* Frequency Locked for ISO Protocol */
+ int segrate = rt->ratem;//rt->rate/ctrl->a_framer->superfreq;
+ int segint = SLIM_SLOTS_PER_SUPERFRAME/segrate;
+ int pprate, exp;
+
+ /* Per protocol, only last 5 bits for client no. */
+ wbuf[txn.msg->num_bytes++] = (u8) (0 << 5) | (sdev->laddr & 0x1f);
+
+ wbuf[txn.msg->num_bytes] = rt->bps >> 2;
+ exp = segint % 3;
+ if (exp)
+ wbuf[txn.msg->num_bytes] |= 1 << 5;
+
+ txn.msg->num_bytes++;
+ wbuf[txn.msg->num_bytes++] = exp << 4 | rt->prot;
+ pprate = slim_find_prrate(rt->rate);
+ wbuf[txn.msg->num_bytes++] = pprate | (fl << 7);
+ txn.comp = &done;
+ ret = slim_alloc_tid(ctrl, &txn);
+ if (ret) {
+ pr_err("no tid for channel define?\n");
+ return -ENXIO;
+ }
+ wbuf[txn.msg->num_bytes++] = txn.tid;
+ }
+ wbuf[txn.msg->num_bytes++] = port->ch.id;
+ }
+
+ txn.mc = SLIM_USR_MC_DEF_ACT_CHAN;
+ txn.rl = txn.msg->num_bytes + 4;
+ ret = qcom_slim_ngd_xfer_msg(ctrl, &txn);
+
+ timeout = wait_for_completion_timeout(&done, HZ);
+ if (!timeout) {
+ dev_err(&sdev->dev, "TX timed out:MC:0x%x,mt:0x%x", txn.mc,
+ txn.mt);
+ }
+
+ txn.mc = SLIM_USR_MC_RECONFIG_NOW;
+ txn.msg->num_bytes = 2;
+ wbuf[1] = sdev->laddr;
+ txn.rl = txn.msg->num_bytes + 4;
+
+ txn.comp = &done;
+ ret = slim_alloc_tid(ctrl, &txn);
+ if (ret)
+ return ret;
+ wbuf[0] = txn.tid;
+ ret = qcom_slim_ngd_xfer_msg(ctrl, &txn);
+ timeout = wait_for_completion_timeout(&done, HZ);
+ if (!timeout) {
+ dev_err(&sdev->dev, "TX timed out:MC:0x%x,mt:0x%x", txn.mc,
+ txn.mt);
+ }
+
+ return 0;
+}
+
+static int qcom_slim_ngd_get_laddr(struct slim_controller *sctrl,
+ struct slim_eaddr *ea, u8 *laddr)
+{
+ DECLARE_COMPLETION_ONSTACK(done);
+ struct slim_val_inf msg = {0};
+ struct slim_msg_txn txn;
+ u8 wbuf[10] = {0};
+ u8 rbuf[10] = {0};
+ int ret;
+
+ txn.mt = SLIM_MSG_MT_DEST_REFERRED_USER;
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.la = SLIM_LA_MGR;
+ txn.ec = 0;
+
+ txn.mc = SLIM_USR_MC_ADDR_QUERY;
+ txn.rl = 11;
+ txn.msg = &msg;
+ txn.msg->num_bytes = 7;
+ txn.msg->wbuf = wbuf;
+ txn.msg->rbuf = rbuf;
+
+ ret = slim_prepare_txn(sctrl, &txn, &done, true);
+ if (ret)
+ return ret;
+
+ wbuf[0] = (u8)txn.tid;
+ memcpy(&wbuf[1], ea, sizeof(*ea));
+ ret = slim_do_transfer(sctrl, &txn);
+
+ *laddr = rbuf[6];
+
+ return ret;
+}
+
+static int qcom_slim_ngd_exit_dma(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ if (ctrl->dma_rx_channel) {
+ dmaengine_terminate_sync(ctrl->dma_rx_channel);
+ dma_release_channel(ctrl->dma_rx_channel);
+ }
+
+ if (ctrl->dma_tx_channel) {
+ dmaengine_terminate_sync(ctrl->dma_tx_channel);
+ dma_release_channel(ctrl->dma_tx_channel);
+ }
+
+ ctrl->dma_tx_channel = ctrl->dma_rx_channel = NULL;
+
+ return 0;
+}
+
+static void qcom_slim_ngd_setup(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ u32 cfg = readl_relaxed(ctrl->ngd->base);
+
+ if (ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN)
+ qcom_slim_ngd_init_dma(ctrl);
+
+ /* By default enable message queues */
+ cfg |= NGD_CFG_RX_MSGQ_EN;
+ cfg |= NGD_CFG_TX_MSGQ_EN;
+
+ /* Enable NGD if it's not already enabled*/
+ if (!(cfg & NGD_CFG_ENABLE))
+ cfg |= NGD_CFG_ENABLE;
+
+ writel_relaxed(cfg, ctrl->ngd->base);
+}
+
+static int qcom_slim_ngd_power_up(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ enum qcom_slim_ngd_state cur_state = ctrl->state;
+ struct qcom_slim_ngd *ngd = ctrl->ngd;
+ u32 laddr, rx_msgq;
+ int timeout, ret = 0;
+
+ if (ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN) {
+ timeout = wait_for_completion_timeout(&ctrl->qmi.qmi_comp, HZ);
+ if (!timeout)
+ return -EREMOTEIO;
+ }
+
+ if (ctrl->state == QCOM_SLIM_NGD_CTRL_ASLEEP ||
+ ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN) {
+ ret = qcom_slim_qmi_power_request(ctrl, true);
+ if (ret) {
+ dev_err(ctrl->dev, "SLIM QMI power request failed:%d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ ctrl->ver = readl_relaxed(ctrl->base);
+ /* Version info in 16 MSbits */
+ ctrl->ver >>= 16;
+
+ laddr = readl_relaxed(ngd->base + NGD_STATUS);
+ if (laddr & NGD_LADDR) {
+ /*
+ * external MDM restart case where ADSP itself was active framer
+ * For example, modem restarted when playback was active
+ */
+ if (cur_state == QCOM_SLIM_NGD_CTRL_AWAKE) {
+ dev_info(ctrl->dev, "Subsys restart: ADSP active framer\n");
+ return 0;
+ }
+ return 0;
+ }
+
+ writel_relaxed(DEF_NGD_INT_MASK, ngd->base + NGD_INT_EN);
+ rx_msgq = readl_relaxed(ngd->base + NGD_RX_MSGQ_CFG);
+
+ writel_relaxed(rx_msgq|SLIM_RX_MSGQ_TIMEOUT_VAL,
+ ngd->base + NGD_RX_MSGQ_CFG);
+ qcom_slim_ngd_setup(ctrl);
+
+ timeout = wait_for_completion_timeout(&ctrl->reconf, HZ);
+ if (!timeout) {
+ dev_err(ctrl->dev, "capability exchange timed-out\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void qcom_slim_ngd_notify_slaves(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ struct slim_device *sbdev;
+ struct device_node *node;
+
+ for_each_child_of_node(ctrl->ngd->pdev->dev.of_node, node) {
+ sbdev = of_slim_get_device(&ctrl->ctrl, node);
+ if (!sbdev)
+ continue;
+
+ if (slim_get_logical_addr(sbdev))
+ dev_err(ctrl->dev, "Failed to get logical address\n");
+ }
+}
+
+static void qcom_slim_ngd_master_worker(struct work_struct *work)
+{
+ struct qcom_slim_ngd_ctrl *ctrl;
+ struct slim_msg_txn txn;
+ struct slim_val_inf msg = {0};
+ int retries = 0;
+ u8 wbuf[8];
+ int ret = 0;
+
+ ctrl = container_of(work, struct qcom_slim_ngd_ctrl, m_work);
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.ec = 0;
+ txn.mc = SLIM_USR_MC_REPORT_SATELLITE;
+ txn.mt = SLIM_MSG_MT_SRC_REFERRED_USER;
+ txn.la = SLIM_LA_MGR;
+ wbuf[0] = SAT_MAGIC_LSB;
+ wbuf[1] = SAT_MAGIC_MSB;
+ wbuf[2] = SAT_MSG_VER;
+ wbuf[3] = SAT_MSG_PROT;
+ txn.msg = &msg;
+ txn.msg->wbuf = wbuf;
+ txn.msg->num_bytes = 4;
+ txn.rl = 8;
+
+ dev_info(ctrl->dev, "SLIM SAT: Rcvd master capability\n");
+
+capability_retry:
+ ret = qcom_slim_ngd_xfer_msg(&ctrl->ctrl, &txn);
+ if (!ret) {
+ if (ctrl->state >= QCOM_SLIM_NGD_CTRL_ASLEEP)
+ complete(&ctrl->reconf);
+ else
+ dev_err(ctrl->dev, "unexpected state:%d\n",
+ ctrl->state);
+
+ if (ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN)
+ qcom_slim_ngd_notify_slaves(ctrl);
+
+ } else if (ret == -EIO) {
+ dev_err(ctrl->dev, "capability message NACKed, retrying\n");
+ if (retries < INIT_MX_RETRIES) {
+ msleep(DEF_RETRY_MS);
+ retries++;
+ goto capability_retry;
+ }
+ } else {
+ dev_err(ctrl->dev, "SLIM: capability TX failed:%d\n", ret);
+ }
+}
+
+static int qcom_slim_ngd_runtime_resume(struct device *dev)
+{
+ struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (ctrl->state >= QCOM_SLIM_NGD_CTRL_ASLEEP)
+ ret = qcom_slim_ngd_power_up(ctrl);
+ if (ret) {
+ /* Did SSR cause this power up failure */
+ if (ctrl->state != QCOM_SLIM_NGD_CTRL_DOWN)
+ ctrl->state = QCOM_SLIM_NGD_CTRL_ASLEEP;
+ else
+ dev_err(ctrl->dev, "HW wakeup attempt during SSR\n");
+ } else {
+ ctrl->state = QCOM_SLIM_NGD_CTRL_AWAKE;
+ }
+
+ return 0;
+}
+
+static int qcom_slim_ngd_enable(struct qcom_slim_ngd_ctrl *ctrl, bool enable)
+{
+ if (enable) {
+ int ret = qcom_slim_qmi_init(ctrl, false);
+
+ if (ret) {
+ dev_err(ctrl->dev, "qmi init fail, ret:%d, state:%d\n",
+ ret, ctrl->state);
+ return ret;
+ }
+ /* controller state should be in sync with framework state */
+ complete(&ctrl->qmi.qmi_comp);
+ if (!pm_runtime_enabled(ctrl->dev) ||
+ !pm_runtime_suspended(ctrl->dev))
+ qcom_slim_ngd_runtime_resume(ctrl->dev);
+ else
+ pm_runtime_resume(ctrl->dev);
+ pm_runtime_mark_last_busy(ctrl->dev);
+ pm_runtime_put(ctrl->dev);
+ } else {
+ qcom_slim_qmi_exit(ctrl);
+ }
+
+ return 0;
+}
+
+static int qcom_slim_ngd_qmi_new_server(struct qmi_handle *hdl,
+ struct qmi_service *service)
+{
+ struct qcom_slim_ngd_qmi *qmi =
+ container_of(hdl, struct qcom_slim_ngd_qmi, svc_event_hdl);
+ struct qcom_slim_ngd_ctrl *ctrl =
+ container_of(qmi, struct qcom_slim_ngd_ctrl, qmi);
+
+ qmi->svc_info.sq_family = AF_QIPCRTR;
+ qmi->svc_info.sq_node = service->node;
+ qmi->svc_info.sq_port = service->port;
+
+ qcom_slim_ngd_enable(ctrl, true);
+
+ return 0;
+}
+
+static void qcom_slim_ngd_qmi_del_server(struct qmi_handle *hdl,
+ struct qmi_service *service)
+{
+ struct qcom_slim_ngd_qmi *qmi =
+ container_of(hdl, struct qcom_slim_ngd_qmi, svc_event_hdl);
+
+ qmi->svc_info.sq_node = 0;
+ qmi->svc_info.sq_port = 0;
+}
+
+static struct qmi_ops qcom_slim_ngd_qmi_svc_event_ops = {
+ .new_server = qcom_slim_ngd_qmi_new_server,
+ .del_server = qcom_slim_ngd_qmi_del_server,
+};
+
+static int qcom_slim_ngd_qmi_svc_event_init(struct qcom_slim_ngd_ctrl *ctrl)
+{
+ struct qcom_slim_ngd_qmi *qmi = &ctrl->qmi;
+ int ret;
+
+ ret = qmi_handle_init(&qmi->svc_event_hdl, 0,
+ &qcom_slim_ngd_qmi_svc_event_ops, NULL);
+ if (ret < 0) {
+ dev_err(ctrl->dev, "qmi_handle_init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = qmi_add_lookup(&qmi->svc_event_hdl, SLIMBUS_QMI_SVC_ID,
+ SLIMBUS_QMI_SVC_V1, SLIMBUS_QMI_INS_ID);
+ if (ret < 0) {
+ dev_err(ctrl->dev, "qmi_add_lookup failed: %d\n", ret);
+ qmi_handle_release(&qmi->svc_event_hdl);
+ }
+ return ret;
+}
+
+static void qcom_slim_ngd_qmi_svc_event_deinit(struct qcom_slim_ngd_qmi *qmi)
+{
+ qmi_handle_release(&qmi->svc_event_hdl);
+}
+
+static struct platform_driver qcom_slim_ngd_driver;
+#define QCOM_SLIM_NGD_DRV_NAME "qcom,slim-ngd"
+
+static const struct of_device_id qcom_slim_ngd_dt_match[] = {
+ {
+ .compatible = "qcom,slim-ngd-v1.5.0",
+ .data = &ngd_v1_5_offset_info,
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, qcom_slim_ngd_dt_match);
+
+static int of_qcom_slim_ngd_register(struct device *parent,
+ struct qcom_slim_ngd_ctrl *ctrl)
+{
+ const struct ngd_reg_offset_data *data;
+ struct qcom_slim_ngd *ngd;
+ struct device_node *node;
+ u32 id;
+
+ for_each_available_child_of_node(parent->of_node, node) {
+ if (of_property_read_u32(node, "reg", &id))
+ continue;
+
+ ngd = kzalloc(sizeof(*ngd), GFP_KERNEL);
+ if (!ngd)
+ return -ENOMEM;
+
+ ngd->pdev = platform_device_alloc(QCOM_SLIM_NGD_DRV_NAME, id);
+ ngd->id = id;
+ ngd->pdev->dev.parent = parent;
+ ngd->pdev->driver_override = QCOM_SLIM_NGD_DRV_NAME;
+ ngd->pdev->dev.of_node = node;
+ ctrl->ngd = ngd;
+ platform_set_drvdata(ngd->pdev, ctrl);
+
+ platform_device_add(ngd->pdev);
+ data = of_match_node(qcom_slim_ngd_dt_match, parent->of_node)->data;
+ ngd->base = ctrl->base + ngd->id * data->offset + (ngd->id - 1) * data->size;
+ ctrl->ngd = ngd;
+ platform_driver_register(&qcom_slim_ngd_driver);
+
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+
+static int qcom_slim_ngd_probe(struct platform_device *pdev)
+{
+ struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+ int ret;
+
+ ctrl->ctrl.dev = dev;
+ ret = slim_register_controller(&ctrl->ctrl);
+ if (ret) {
+ dev_err(dev, "error adding slim controller\n");
+ return ret;
+ }
+
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_autosuspend_delay(dev, QCOM_SLIM_NGD_AUTOSUSPEND);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+ pm_runtime_get_noresume(dev);
+ ret = qcom_slim_ngd_qmi_svc_event_init(ctrl);
+ if (ret) {
+ dev_err(&pdev->dev, "QMI service registration failed:%d", ret);
+ goto err;
+ }
+
+ INIT_WORK(&ctrl->m_work, qcom_slim_ngd_master_worker);
+ ctrl->mwq = create_singlethread_workqueue("ngd_master");
+ if (!ctrl->mwq) {
+ dev_err(&pdev->dev, "Failed to start master worker\n");
+ ret = -ENOMEM;
+ goto wq_err;
+ }
+
+ return 0;
+err:
+ slim_unregister_controller(&ctrl->ctrl);
+wq_err:
+ qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
+ if (ctrl->mwq)
+ destroy_workqueue(ctrl->mwq);
+
+ return 0;
+}
+
+static int qcom_slim_ngd_ctrl_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct qcom_slim_ngd_ctrl *ctrl;
+ struct resource *res;
+ int ret;
+
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, ctrl);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ctrl->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ctrl->base))
+ return PTR_ERR(ctrl->base);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no slimbus IRQ resource\n");
+ return -ENODEV;
+ }
+
+ ret = devm_request_irq(dev, res->start, qcom_slim_ngd_interrupt,
+ IRQF_TRIGGER_HIGH, "slim-ngd", ctrl);
+ if (ret) {
+ dev_err(&pdev->dev, "request IRQ failed\n");
+ return ret;
+ }
+
+ ctrl->dev = dev;
+ ctrl->framer.rootfreq = SLIM_ROOT_FREQ >> 3;
+ ctrl->framer.superfreq =
+ ctrl->framer.rootfreq / SLIM_CL_PER_SUPERFRAME_DIV8;
+
+ ctrl->ctrl.a_framer = &ctrl->framer;
+ ctrl->ctrl.clkgear = SLIM_MAX_CLK_GEAR;
+ ctrl->ctrl.get_laddr = qcom_slim_ngd_get_laddr;
+ ctrl->ctrl.enable_stream = qcom_slim_ngd_enable_stream;
+ ctrl->ctrl.xfer_msg = qcom_slim_ngd_xfer_msg;
+ ctrl->ctrl.wakeup = NULL;
+ ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN;
+
+ spin_lock_init(&ctrl->tx_buf_lock);
+ init_completion(&ctrl->reconf);
+ init_completion(&ctrl->qmi.qmi_comp);
+
+ return of_qcom_slim_ngd_register(dev, ctrl);
+}
+
+static int qcom_slim_ngd_ctrl_remove(struct platform_device *pdev)
+{
+ platform_driver_unregister(&qcom_slim_ngd_driver);
+
+ return 0;
+}
+
+static int qcom_slim_ngd_remove(struct platform_device *pdev)
+{
+ struct qcom_slim_ngd_ctrl *ctrl = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ slim_unregister_controller(&ctrl->ctrl);
+ qcom_slim_ngd_exit_dma(ctrl);
+ qcom_slim_ngd_qmi_svc_event_deinit(&ctrl->qmi);
+ if (ctrl->mwq)
+ destroy_workqueue(ctrl->mwq);
+
+ kfree(ctrl->ngd);
+ ctrl->ngd = NULL;
+ return 0;
+}
+
+static int qcom_slim_ngd_runtime_idle(struct device *dev)
+{
+ struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev);
+
+ if (ctrl->state == QCOM_SLIM_NGD_CTRL_AWAKE)
+ ctrl->state = QCOM_SLIM_NGD_CTRL_IDLE;
+ pm_request_autosuspend(dev);
+ return -EAGAIN;
+}
+
+#ifdef CONFIG_PM
+static int qcom_slim_ngd_runtime_suspend(struct device *dev)
+{
+ struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = qcom_slim_qmi_power_request(ctrl, false);
+ if (ret && ret != -EBUSY)
+ dev_info(ctrl->dev, "slim resource not idle:%d\n", ret);
+ if (!ret || ret == -ETIMEDOUT)
+ ctrl->state = QCOM_SLIM_NGD_CTRL_ASLEEP;
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops qcom_slim_ngd_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(
+ qcom_slim_ngd_runtime_suspend,
+ qcom_slim_ngd_runtime_resume,
+ qcom_slim_ngd_runtime_idle
+ )
+};
+
+static struct platform_driver qcom_slim_ngd_ctrl_driver = {
+ .probe = qcom_slim_ngd_ctrl_probe,
+ .remove = qcom_slim_ngd_ctrl_remove,
+ .driver = {
+ .name = "qcom,slim-ngd-ctrl",
+ .of_match_table = qcom_slim_ngd_dt_match,
+ },
+};
+
+static struct platform_driver qcom_slim_ngd_driver = {
+ .probe = qcom_slim_ngd_probe,
+ .remove = qcom_slim_ngd_remove,
+ .driver = {
+ .name = QCOM_SLIM_NGD_DRV_NAME,
+ .pm = &qcom_slim_ngd_dev_pm_ops,
+ },
+};
+
+module_platform_driver(qcom_slim_ngd_ctrl_driver);
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Qualcomm SLIMBus NGD controller");
diff --git a/drivers/slimbus/slimbus.h b/drivers/slimbus/slimbus.h
index 79f8e05d92dd..1d5017b50a5c 100644
--- a/drivers/slimbus/slimbus.h
+++ b/drivers/slimbus/slimbus.h
@@ -17,6 +17,8 @@
/* SLIMbus message types. Related to interpretation of message code. */
#define SLIM_MSG_MT_CORE 0x0
+#define SLIM_MSG_MT_DEST_REFERRED_USER 0x2
+#define SLIM_MSG_MT_SRC_REFERRED_USER 0x6
/*
* SLIM Broadcast header format
@@ -43,11 +45,28 @@
#define SLIM_MSG_MC_ASSIGN_LOGICAL_ADDRESS 0x2
#define SLIM_MSG_MC_REPORT_ABSENT 0xF
+/* Data channel management messages */
+#define SLIM_MSG_MC_CONNECT_SOURCE 0x10
+#define SLIM_MSG_MC_CONNECT_SINK 0x11
+#define SLIM_MSG_MC_DISCONNECT_PORT 0x14
+#define SLIM_MSG_MC_CHANGE_CONTENT 0x18
+
/* Clock pause Reconfiguration messages */
#define SLIM_MSG_MC_BEGIN_RECONFIGURATION 0x40
#define SLIM_MSG_MC_NEXT_PAUSE_CLOCK 0x4A
+#define SLIM_MSG_MC_NEXT_DEFINE_CHANNEL 0x50
+#define SLIM_MSG_MC_NEXT_DEFINE_CONTENT 0x51
+#define SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL 0x54
+#define SLIM_MSG_MC_NEXT_DEACTIVATE_CHANNEL 0x55
+#define SLIM_MSG_MC_NEXT_REMOVE_CHANNEL 0x58
#define SLIM_MSG_MC_RECONFIGURE_NOW 0x5F
+/*
+ * Clock pause flag to indicate that the reconfig message
+ * corresponds to clock pause sequence
+ */
+#define SLIM_MSG_CLK_PAUSE_SEQ_FLG (1U << 8)
+
/* Clock pause values per SLIMbus spec */
#define SLIM_CLK_FAST 0
#define SLIM_CLK_CONST_PHASE 1
@@ -61,7 +80,16 @@
/* Standard values per SLIMbus spec needed by controllers and devices */
#define SLIM_MAX_CLK_GEAR 10
#define SLIM_MIN_CLK_GEAR 1
+#define SLIM_SLOT_LEN_BITS 4
+/* Standard values per SLIMbus spec needed by controllers and devices */
+#define SLIM_CL_PER_SUPERFRAME 6144
+#define SLIM_CL_PER_SUPERFRAME_DIV8 (SLIM_CL_PER_SUPERFRAME >> 3)
+#define SLIM_SLOTS_PER_SUPERFRAME (SLIM_CL_PER_SUPERFRAME >> 2)
+#define SLIM_MAX_TXNS 256
+#define SLIM_SL_PER_SUPERFRAME (SLIM_CL_PER_SUPERFRAME >> 2)
+#define SLIM_FRM_SLOTS_PER_SUPERFRAME 16
+#define SLIM_GDE_SLOTS_PER_SUPERFRAME 2
/* Manager's logical address is set to 0xFF per spec */
#define SLIM_LA_MANAGER 0xFF
@@ -102,6 +130,7 @@ struct slim_framer {
* @msg: Elemental access message to be read/written
* @comp: completion if read/write is synchronous, used internally
* for tid based transactions.
+ * @need_tid: flag indicating if a tid is required for this txn
*/
struct slim_msg_txn {
u8 rl;
@@ -113,6 +142,7 @@ struct slim_msg_txn {
u8 la;
struct slim_val_inf *msg;
struct completion *comp;
+ bool need_tid;
};
/* Frequently used message transaction structures */
@@ -159,6 +189,88 @@ struct slim_sched {
struct mutex m_reconf;
};
+enum slim_port_direction {
+ SLIM_PORT_DIRECTION_INVALID = 0, //FIXME
+ SLIM_PORT_SOURCE = 1,
+ SLIM_PORT_SINK = 2,
+};
+
+enum slim_port_state {
+ SLIM_PORT_DISCONNECTED = 0,
+ SLIM_PORT_UNCONFIGURED, /* EP in Port is connected to Channel, No data trasnmission*/
+ SLIM_PORT_CONFIGURED, /* after DEFINE_CH/CONTENT/ACTIVE */
+};
+
+enum slim_channel_state {
+ SLIM_CH_INACTIVE = 0, /* After reset or after DEACTIVATE or REMOVE CHANNEL */
+ SLIM_CH_ALLOCATED, /* A Channel Number is allocated */
+ SLIM_CH_ASSOCIATED, /* Channel and EP are associated with Port CONNECT_SOURCE/SINK*/
+ SLIM_CH_DEFINED, /* DEFINE CHANNEL */
+ SLIM_CH_ACTIVE, /* NEXT_ACTIVE_CHANNEL */
+ SLIM_CH_CONENT_DEFINED, /* DEFINE CONENT */
+};
+
+#define SLIM_MAX_PORTS 32
+
+struct slim_port_config {
+ int num;
+// int ch_mask;
+ enum slim_port_direction dir;
+ int port_mask; /* A SLIMBus Device may have frmo 0 to 31 Ports (inclusive) */
+};
+
+struct slim_channel_config {
+ int num;
+ int tx_ch_mask;
+ int rx_ch_mask;
+};
+
+struct slim_channel {
+ int id;
+ int ratem;
+ int seg_dist;
+ int data_len;
+ int proto;
+ int prrate;
+ enum slim_channel_state state;
+};
+
+struct slim_port {
+ int id;
+ enum slim_port_direction direction;
+ enum slim_port_state state;
+ struct slim_channel ch;
+};
+
+/*
+ * enum slim_ch_rate: Most commonly used frequency rate families.
+ * Use 1HZ for push-pull transport.
+ * 4KHz and 11.025KHz are most commonly used in audio applications.
+ * Typically, slimbus runs at frequencies to support channels running at 4KHz
+ * and/or 11.025KHz isochronously.
+ */
+enum slim_ch_rate {
+ SLIM_RATE_1HZ,
+ SLIM_RATE_4000HZ,
+ SLIM_RATE_11025HZ,
+};
+
+struct slim_stream_runtime {
+ struct slim_device *dev;
+ unsigned int rate;
+ unsigned int bps;
+ enum slim_stream_direction direction;
+ enum slim_channel_proto prot;
+
+ //??? FIXME
+ unsigned int ratem;
+ unsigned int baser;
+
+ int num_ports;
+ struct slim_port ports[];
+};
+
+
/**
* struct slim_controller - Controls every instance of SLIMbus
* (similar to 'master' on SPI)
@@ -229,6 +341,12 @@ struct slim_controller {
struct slim_eaddr *ea, u8 laddr);
int (*get_laddr)(struct slim_controller *ctrl,
struct slim_eaddr *ea, u8 *laddr);
+ int (*alloc_bandwidth)(struct slim_stream_runtime *rt);
+ int (*enable_stream)(struct slim_stream_runtime *rt);
+ int (*disable_stream)(struct slim_stream_runtime *rt);
+ int (*prepare_msg)(struct slim_controller *ctrl,
+ struct slim_msg_txn *tx,
+ struct completion *done);
int (*wakeup)(struct slim_controller *ctrl);
};
@@ -240,6 +358,10 @@ int slim_unregister_controller(struct slim_controller *ctrl);
void slim_msg_response(struct slim_controller *ctrl, u8 *reply, u8 tid, u8 l);
int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn);
int slim_ctrl_clk_pause(struct slim_controller *ctrl, bool wakeup, u8 restart);
+int slim_prepare_txn(struct slim_controller *ctrl, struct slim_msg_txn *txn,
+ struct completion *done, bool need_tid);
+int slim_alloc_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn);
+int slim_find_prrate(int rate);
static inline bool slim_tid_txn(u8 mt, u8 mc)
{
@@ -258,4 +380,6 @@ static inline bool slim_ec_txn(u8 mt, u8 mc)
(mc >= SLIM_MSG_MC_REQUEST_VALUE &&
mc <= SLIM_MSG_MC_CHANGE_VALUE)));
}
+
+extern char * get_mc_name(int mc);
#endif /* _LINUX_SLIMBUS_H */
diff --git a/drivers/slimbus/stream.c b/drivers/slimbus/stream.c
new file mode 100644
index 000000000000..5e045fe2d6ed
--- /dev/null
+++ b/drivers/slimbus/stream.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018, Linaro Limited
+// TODO:
+// Add support to natural frequencies like 11.025KHz and 44.1KHz.
+// Add support to PUSH/PULL transport protocol
+// Bandwidth Management
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+#include <linux/of.h>
+#include <linux/slimbus.h>
+#include "slimbus.h"
+
+struct slim_stream_runtime *slim_stream_allocate(struct slim_device *dev,
+ struct slim_stream_config *cfg)
+{
+ struct slim_stream_runtime *rt;
+ struct slim_controller *ctrl = dev->ctrl;
+ int num_ports, i, port_id;
+
+ num_ports = hweight32(cfg->port_mask);
+ rt = kzalloc(sizeof(*rt) + num_ports * sizeof(*rt->ports), GFP_KERNEL);
+ if (!rt)
+ return ERR_PTR(-ENOMEM);
+
+ rt->dev = dev;
+ rt->num_ports = num_ports;
+ rt->rate = cfg->rate;
+ rt->prot = cfg->prot;
+ rt->bps = cfg->bps;
+ rt->direction = cfg->direction;
+
+ i = 0;
+ //FIXME ONLY Natural frequencies of 8KHz to 48KHz are supported!!
+ rt->ratem = cfg->rate/ctrl->a_framer->superfreq;
+
+ for_each_set_bit(port_id, &cfg->port_mask, SLIM_MAX_PORTS) {
+ rt->ports[i].state = SLIM_PORT_DISCONNECTED;
+ rt->ports[i].id = port_id;
+ rt->ports[i].direction = SLIM_PORT_SINK;
+ rt->ports[i].ch.id = cfg->chs[i];
+ rt->ports[i].ch.state = SLIM_CH_ALLOCATED;
+
+ i++;
+ }
+
+ return rt;
+}
+EXPORT_SYMBOL_GPL(slim_stream_allocate);
+
+static int slim_connect_sink(struct slim_stream_runtime *stream,
+ struct slim_port *port)
+{
+ struct slim_device *sdev = stream->dev;
+ struct slim_val_inf msg = {0, 0, NULL, NULL};
+ struct slim_msg_txn txn = {0,};
+ u8 wbuf[2];
+
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.la = stream->dev->laddr;
+ txn.ec = 0;
+ txn.mc = SLIM_MSG_MC_CONNECT_SINK;
+ txn.rl = 6;
+ txn.msg = &msg;
+ txn.msg->num_bytes = 2;
+ txn.msg->wbuf = wbuf;
+
+ wbuf[0] = port->id;
+ wbuf[1] = port->ch.id;
+
+ return slim_do_transfer(sdev->ctrl, &txn);
+}
+
+static int slim_connect_source(struct slim_stream_runtime *stream,
+ struct slim_port *port)
+{
+ struct slim_device *sdev = stream->dev;
+ struct slim_val_inf msg = {0, 0, NULL, NULL};
+ struct slim_msg_txn txn = {0,};
+ u8 wbuf[2];
+
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.la = stream->dev->laddr;
+ txn.ec = 0;
+ txn.mc = SLIM_MSG_MC_CONNECT_SOURCE;
+ txn.rl = 6;
+ txn.msg = &msg;
+ txn.msg->num_bytes = 2;
+ txn.msg->wbuf = wbuf;
+
+ wbuf[0] = port->id;
+ wbuf[1] = port->ch.id;
+
+ return slim_do_transfer(sdev->ctrl, &txn);
+}
+
+static int slim_disconnect_port(struct slim_stream_runtime *stream,
+ struct slim_port *port)
+{
+ struct slim_device *sdev = stream->dev;
+ struct slim_val_inf msg = {0, 0, NULL, NULL};
+ struct slim_msg_txn txn = {0,};
+ u8 wbuf[1];
+
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.la = stream->dev->laddr;
+ txn.ec = 0;
+ txn.mc = SLIM_MSG_MC_DISCONNECT_PORT;
+ txn.rl = 5;
+ txn.msg = &msg;
+ txn.msg->num_bytes = 1;
+ txn.msg->wbuf = wbuf;
+ wbuf[0] = port->id;
+ return slim_do_transfer(sdev->ctrl, &txn);
+}
+
+int slim_stream_prepare(struct slim_stream_runtime *stream)
+{
+ int i;
+
+ for (i = 0; i < stream->num_ports; i++) {
+ if (stream->direction == SLIM_STREAM_PLAYBACK)
+ slim_connect_sink(stream, &stream->ports[i]);
+ else if (stream->direction == SLIM_STREAM_CAPTURE)
+ slim_connect_source(stream, &stream->ports[i]);
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(slim_stream_prepare);
+
+/*
+ * Presense Rate
+ * Table 66 from SLIMbus 2.0 Specs
+ */
+static int prrate_table[] =
+{
+ 12000, 0x01,
+ 24000, 0x02,
+ 48000, 0x03,
+ 96000, 0x04,
+ 192000, 0x05,
+ 384000, 0x06,
+ 768000, 0x07,
+ 110250, 0x09,
+ 220500, 0x0a,
+ 441000, 0x0b,
+ 882000, 0x0c,
+ 176400, 0x0d,
+ 352800, 0x0e,
+ 705600, 0x0f,
+ 4000, 0x10,
+ 8000, 0x11,
+ 16000, 0x12,
+ 32000, 0x13,
+ 64000, 0x14,
+ 128000, 0x15,
+ 256000, 0x16,
+ 512000, 0x17,
+};
+
+int slim_find_prrate(int rate)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(prrate_table);) {
+ if (rate == prrate_table[i])
+ return prrate_table[i+1];
+ i += 2;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(slim_find_prrate);
+
+static int slim_define_channel_content(struct slim_stream_runtime *stream,
+ struct slim_port *port)
+{
+ struct slim_device *sdev = stream->dev;
+ struct slim_val_inf msg = {0, 0, NULL, NULL};
+ struct slim_msg_txn txn = {0,};
+ u8 wbuf[4];
+ int prrate;
+ int fl = 1; /* Frequency Locked for ISO Protocol */
+ prrate = slim_find_prrate(stream->rate);
+
+ port->ch.prrate = prrate;
+
+ txn.dt = SLIM_MSG_DEST_LOGICALADDR;
+ txn.la = stream->dev->laddr;
+ txn.ec = 0;
+ txn.mc = SLIM_MSG_MC_NEXT_DEFINE_CONTENT;
+ txn.rl = 8;
+ txn.msg = &msg;
+ txn.msg->num_bytes = 4;
+ txn.msg->wbuf = wbuf;
+ wbuf[0] = port->ch.id;
+ wbuf[1] = prrate | (fl << 7);
+ wbuf[2] = 0;
+ // FIXME.. slc->prop.dataf | (slc->prop.auxf << 4);
+ wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS;
+
+ return slim_do_transfer(sdev->ctrl, &txn);
+}
+
+struct segdist_code {
+ /* Channel rate multiplier */
+ int ratem;
+ int segdist_code;
+ u32 seg_offset_mask;
+
+};
+
+/* Table 20 from SLIMbus Specs Version 2.0 */
+static struct segdist_code segdist_codes[] = {
+ {1, 0x200, 0xdff},
+ {2, 0x100, 0xcff},
+ {4, 0x080, 0xc7f},
+ {8, 0x040, 0xc3f},
+ {16, 0x020, 0xc1f},
+ {32, 0x010, 0xc0f},
+ {64, 0x008, 0xc07},
+ {128, 0x004, 0xc03},
+ {256, 0x002, 0xc01},
+ {512, 0x001, 0xc00},
+ {3, 0xe00, 0x1ff},
+ {6, 0xd00, 0x0ff},
+ {12, 0xc80, 0x07f},
+ {24, 0xc40, 0x03f},
+ {48, 0xc20, 0x01f},
+ {96, 0xc10, 0x00f},
+ {192, 0xc08, 0x007},
+ {364, 0xc04, 0x003},
+ {768, 0xc02, 0x001},
+};
+
+static int slim_get_segdist_code(int ratem)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(segdist_codes); i++) {
+ if (segdist_codes[i].ratem == ratem)
+ return segdist_codes[i].segdist_code;
+ }
+
+ return -EINVAL;
+}
+
+static int slim_define_channel(struct slim_stream_runtime *stream,
+ struct slim_port *port)
+{
+ struct slim_device *sdev = stream->dev;
+ struct slim_val_inf msg = {0, 0, NULL, NULL};
+ struct slim_msg_txn txn = {0,};
+ u8 wbuf[4];
+ int sd;
+ int tp = 0;
+
+ txn.dt = SLIM_MSG_DEST_BROADCAST;
+ txn.la = stream->dev->laddr;
+ txn.ec = 0;
+ txn.mc = SLIM_MSG_MC_NEXT_DEFINE_CHANNEL;
+ txn.rl = 8;
+ txn.msg = &msg;
+ txn.msg->num_bytes = 4;
+ txn.msg->wbuf = wbuf;
+ sd = slim_get_segdist_code(stream->ratem);
+ wbuf[0] = port->ch.id;
+
+ port->ch.seg_dist = sd;
+ wbuf[1] = sd & 0xFF;
+ /* Only Isochronous Protocol supported */
+ wbuf[2] = tp | ((sd & 0xF00) >> 8);
+
+ /* Only one data line is supported */
+ wbuf[3] = stream->bps/SLIM_SLOT_LEN_BITS;
+
+
+ return slim_do_transfer(sdev->ctrl, &txn);
+}
+
+static int slim_activate_channel(struct slim_stream_runtime *stream,
+ struct slim_port *port)
+{
+ struct slim_device *sdev = stream->dev;
+ struct slim_val_inf msg = {0, 0, NULL, NULL};
+ struct slim_msg_txn txn = {0,};
+ u8 wbuf[1];
+
+ txn.dt = SLIM_MSG_DEST_BROADCAST;
+ txn.la = stream->dev->laddr;
+ txn.ec = 0;
+ txn.mc = SLIM_MSG_MC_NEXT_ACTIVATE_CHANNEL;
+ txn.rl = 5;
+ txn.msg = &msg;
+ txn.msg->num_bytes = 1;
+ txn.msg->wbuf = wbuf;
+ wbuf[0] = port->ch.id;
+
+ return slim_do_transfer(sdev->ctrl, &txn);
+}
+
+int slim_stream_enable(struct slim_stream_runtime *stream)
+{
+ DEFINE_SLIM_BCAST_TXN(txn, SLIM_MSG_MC_BEGIN_RECONFIGURATION,
+ 3, SLIM_LA_MANAGER, NULL);
+ struct slim_controller *ctrl = stream->dev->ctrl;
+ int ret, i;
+
+ if (ctrl->enable_stream)
+ return ctrl->enable_stream(stream);
+
+ ret = slim_do_transfer(ctrl, &txn);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < stream->num_ports; i++) {
+ struct slim_port *port = &stream->ports[i];
+ slim_define_channel(stream, port);
+ slim_define_channel_content(stream, port);
+ }
+
+ for (i = 0; i < stream->num_ports; i++) {
+ struct slim_port *port = &stream->ports[i];
+ slim_activate_channel(stream, port);
+ }
+ txn.mc = SLIM_MSG_MC_RECONFIGURE_NOW;
+ txn.rl = 3;
+
+ return slim_do_transfer(ctrl, &txn);
+}
+EXPORT_SYMBOL_GPL(slim_stream_enable);
+
+int slim_stream_disable(struct slim_stream_runtime *stream)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(slim_stream_disable);
+
+int slim_stream_unprepare(struct slim_stream_runtime *stream)
+{
+ int i;
+ for (i = 0; i < stream->num_ports; i++)
+ slim_disconnect_port(stream, &stream->ports[i]);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(slim_stream_unprepare);
+
+int slim_stream_free(struct slim_stream_runtime *stream)
+{
+ kfree(stream);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(slim_stream_free);
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 5856e792d09c..32230841c2a3 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -75,6 +75,16 @@ config QCOM_RMTFS_MEM
Say y here if you intend to boot the modem remoteproc.
+config QCOM_RPMH
+ bool "Qualcomm RPM-Hardened (RPMH) Communication"
+ depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST
+ help
+ Support for communication with the hardened-RPM blocks in
+ Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
+ internal bus to transmit state requests for shared resources. A set
+ of hardware components aggregate requests for these resources and
+ help apply the aggregated state on the resource.
+
config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 19dcf957cb3a..aeeab0a11abe 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
+CFLAGS_rpmh-rsc.o := -I$(src)
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o
@@ -8,10 +9,14 @@ obj-$(CONFIG_QCOM_PM) += spm.o
obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o
qmi_helpers-y += qmi_encdec.o qmi_interface.o
obj-$(CONFIG_QCOM_RMTFS_MEM) += rmtfs_mem.o
+obj-$(CONFIG_QCOM_RPMH) += qcom_rpmh.o
+qcom_rpmh-y += rpmh-rsc.o
+qcom_rpmh-y += rpmh.o
obj-$(CONFIG_QCOM_SMD_RPM) += smd-rpm.o
obj-$(CONFIG_QCOM_SMEM) += smem.o
obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
+obj-$(CONFIG_ARCH_MSM8996) += kryo-l2-accessors.o
obj-$(CONFIG_QCOM_APR) += apr.o
diff --git a/drivers/soc/qcom/kryo-l2-accessors.c b/drivers/soc/qcom/kryo-l2-accessors.c
new file mode 100644
index 000000000000..6743848d9a1f
--- /dev/null
+++ b/drivers/soc/qcom/kryo-l2-accessors.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This 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/spinlock.h>
+#include <asm/sysreg.h>
+#include <soc/qcom/kryo-l2-accessors.h>
+
+#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
+#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
+
+static DEFINE_RAW_SPINLOCK(l2_access_lock);
+
+/**
+ * set_l2_indirect_reg: write value to an L2 register
+ * @reg: Address of L2 register.
+ * @value: Value to be written to register.
+ *
+ * Use architecturally required barriers for ordering between system register
+ * accesses, and system registers with respect to device memory
+ */
+void set_l2_indirect_reg(u64 reg, u64 val)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2_access_lock, flags);
+ write_sysreg_s(reg, L2CPUSRSELR_EL1);
+ isb();
+ write_sysreg_s(val, L2CPUSRDR_EL1);
+ isb();
+ raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+}
+EXPORT_SYMBOL(set_l2_indirect_reg);
+
+/**
+ * get_l2_indirect_reg: read an L2 register value
+ * @reg: Address of L2 register.
+ *
+ * Use architecturally required barriers for ordering between system register
+ * accesses, and system registers with respect to device memory
+ */
+u64 get_l2_indirect_reg(u64 reg)
+{
+ u64 val;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2_access_lock, flags);
+ write_sysreg_s(reg, L2CPUSRSELR_EL1);
+ isb();
+ val = read_sysreg_s(L2CPUSRDR_EL1);
+ raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+
+ return val;
+}
+EXPORT_SYMBOL(get_l2_indirect_reg);
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c
index c8999e38b005..7ffbfcea7d55 100644
--- a/drivers/soc/qcom/rmtfs_mem.c
+++ b/drivers/soc/qcom/rmtfs_mem.c
@@ -213,6 +213,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
goto remove_cdev;
} else if (!ret) {
+ if (!qcom_scm_is_available()) {
+ ret = -EPROBE_DEFER;
+ goto remove_cdev;
+ }
+
perms[0].vmid = QCOM_SCM_VMID_HLOS;
perms[0].perm = QCOM_SCM_PERM_RW;
perms[1].vmid = vmid;
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
new file mode 100644
index 000000000000..e0411d9f98f7
--- /dev/null
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -0,0 +1,114 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+
+#ifndef __RPM_INTERNAL_H__
+#define __RPM_INTERNAL_H__
+
+#include <linux/bitmap.h>
+#include <soc/qcom/tcs.h>
+
+#define TCS_TYPE_NR 4
+#define MAX_CMDS_PER_TCS 16
+#define MAX_TCS_PER_TYPE 3
+#define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR)
+#define MAX_TCS_SLOTS (MAX_CMDS_PER_TCS * MAX_TCS_PER_TYPE)
+
+struct rsc_drv;
+
+/**
+ * struct tcs_group: group of Trigger Command Sets (TCS) to send state requests
+ * to the controller
+ *
+ * @drv: the controller
+ * @type: type of the TCS in this group - active, sleep, wake
+ * @mask: mask of the TCSes relative to all the TCSes in the RSC
+ * @offset: start of the TCS group relative to the TCSes in the RSC
+ * @num_tcs: number of TCSes in this type
+ * @ncpt: number of commands in each TCS
+ * @lock: lock for synchronizing this TCS writes
+ * @req: requests that are sent from the TCS
+ * @cmd_cache: flattened cache of cmds in sleep/wake TCS
+ * @slots: indicates which of @cmd_addr are occupied
+ */
+struct tcs_group {
+ struct rsc_drv *drv;
+ int type;
+ u32 mask;
+ u32 offset;
+ int num_tcs;
+ int ncpt;
+ spinlock_t lock;
+ const struct tcs_request *req[MAX_TCS_PER_TYPE];
+ u32 *cmd_cache;
+ DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
+};
+
+/**
+ * struct rpmh_request: the message to be sent to rpmh-rsc
+ *
+ * @msg: the request
+ * @cmd: the payload that will be part of the @msg
+ * @completion: triggered when request is done
+ * @dev: the device making the request
+ * @err: err return from the controller
+ * @needs_free: check to free dynamically allocated request object
+ */
+struct rpmh_request {
+ struct tcs_request msg;
+ struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
+ struct completion *completion;
+ const struct device *dev;
+ int err;
+ bool needs_free;
+};
+
+/**
+ * struct rpmh_ctrlr: our representation of the controller
+ *
+ * @cache: the list of cached requests
+ * @cache_lock: synchronize access to the cache data
+ * @dirty: was the cache updated since flush
+ * @batch_cache: Cache sleep and wake requests sent as batch
+ */
+struct rpmh_ctrlr {
+ struct list_head cache;
+ spinlock_t cache_lock;
+ bool dirty;
+ struct list_head batch_cache;
+};
+
+/**
+ * struct rsc_drv: the Direct Resource Voter (DRV) of the
+ * Resource State Coordinator controller (RSC)
+ *
+ * @name: controller identifier
+ * @tcs_base: start address of the TCS registers in this controller
+ * @id: instance id in the controller (Direct Resource Voter)
+ * @num_tcs: number of TCSes in this DRV
+ * @tcs: TCS groups
+ * @tcs_in_use: s/w state of the TCS
+ * @lock: synchronize state of the controller
+ * @ctrl: controller to handle cases like batch requests
+ */
+struct rsc_drv {
+ const char *name;
+ void __iomem *tcs_base;
+ int id;
+ int num_tcs;
+ struct tcs_group tcs[TCS_TYPE_NR];
+ DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
+ spinlock_t lock;
+ struct rpmh_ctrlr ctrlr;
+};
+
+int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
+int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
+ const struct tcs_request *msg);
+int rpmh_rsc_invalidate(struct rsc_drv *drv);
+
+void rpmh_tx_done(const struct tcs_request *msg, int r);
+
+#endif /* __RPM_INTERNAL_H__ */
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
new file mode 100644
index 000000000000..144a058407c0
--- /dev/null
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME
+
+#include <linux/atomic.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <soc/qcom/tcs.h>
+#include <dt-bindings/soc/qcom,rpmh-rsc.h>
+
+#include "rpmh-internal.h"
+
+#define CREATE_TRACE_POINTS
+#include "trace-rpmh.h"
+
+#define RSC_DRV_TCS_OFFSET 672
+#define RSC_DRV_CMD_OFFSET 20
+
+/* DRV Configuration Information Register */
+#define DRV_PRNT_CHLD_CONFIG 0x0C
+#define DRV_NUM_TCS_MASK 0x3F
+#define DRV_NUM_TCS_SHIFT 6
+#define DRV_NCPT_MASK 0x1F
+#define DRV_NCPT_SHIFT 27
+
+/* Register offsets */
+#define RSC_DRV_IRQ_ENABLE 0x00
+#define RSC_DRV_IRQ_STATUS 0x04
+#define RSC_DRV_IRQ_CLEAR 0x08
+#define RSC_DRV_CMD_WAIT_FOR_CMPL 0x10
+#define RSC_DRV_CONTROL 0x14
+#define RSC_DRV_STATUS 0x18
+#define RSC_DRV_CMD_ENABLE 0x1C
+#define RSC_DRV_CMD_MSGID 0x30
+#define RSC_DRV_CMD_ADDR 0x34
+#define RSC_DRV_CMD_DATA 0x38
+#define RSC_DRV_CMD_STATUS 0x3C
+#define RSC_DRV_CMD_RESP_DATA 0x40
+
+#define TCS_AMC_MODE_ENABLE BIT(16)
+#define TCS_AMC_MODE_TRIGGER BIT(24)
+
+/* TCS CMD register bit mask */
+#define CMD_MSGID_LEN 8
+#define CMD_MSGID_RESP_REQ BIT(8)
+#define CMD_MSGID_WRITE BIT(16)
+#define CMD_STATUS_ISSUED BIT(8)
+#define CMD_STATUS_COMPL BIT(16)
+
+static u32 read_tcs_reg(struct rsc_drv *drv, int reg, int tcs_id, int cmd_id)
+{
+ return readl_relaxed(drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id +
+ RSC_DRV_CMD_OFFSET * cmd_id);
+}
+
+static void write_tcs_cmd(struct rsc_drv *drv, int reg, int tcs_id, int cmd_id,
+ u32 data)
+{
+ writel_relaxed(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id +
+ RSC_DRV_CMD_OFFSET * cmd_id);
+}
+
+static void write_tcs_reg(struct rsc_drv *drv, int reg, int tcs_id, u32 data)
+{
+ writel_relaxed(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id);
+}
+
+static void write_tcs_reg_sync(struct rsc_drv *drv, int reg, int tcs_id,
+ u32 data)
+{
+ writel(data, drv->tcs_base + reg + RSC_DRV_TCS_OFFSET * tcs_id);
+ for (;;) {
+ if (data == readl(drv->tcs_base + reg +
+ RSC_DRV_TCS_OFFSET * tcs_id))
+ break;
+ udelay(1);
+ }
+}
+
+static bool tcs_is_free(struct rsc_drv *drv, int tcs_id)
+{
+ return !test_bit(tcs_id, drv->tcs_in_use) &&
+ read_tcs_reg(drv, RSC_DRV_STATUS, tcs_id, 0);
+}
+
+static struct tcs_group *get_tcs_of_type(struct rsc_drv *drv, int type)
+{
+ return &drv->tcs[type];
+}
+
+static int tcs_invalidate(struct rsc_drv *drv, int type)
+{
+ int m;
+ struct tcs_group *tcs;
+
+ tcs = get_tcs_of_type(drv, type);
+ if (IS_ERR(tcs))
+ return PTR_ERR(tcs);
+
+ spin_lock(&tcs->lock);
+ if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS)) {
+ spin_unlock(&tcs->lock);
+ return 0;
+ }
+
+ for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++) {
+ if (!tcs_is_free(drv, m)) {
+ spin_unlock(&tcs->lock);
+ return -EAGAIN;
+ }
+ write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
+ }
+ bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
+ spin_unlock(&tcs->lock);
+
+ return 0;
+}
+
+/**
+ * rpmh_rsc_invalidate - Invalidate sleep and wake TCSes
+ *
+ * @drv: the RSC controller
+ */
+int rpmh_rsc_invalidate(struct rsc_drv *drv)
+{
+ int ret;
+
+ ret = tcs_invalidate(drv, SLEEP_TCS);
+ if (!ret)
+ ret = tcs_invalidate(drv, WAKE_TCS);
+
+ return ret;
+}
+
+static struct tcs_group *get_tcs_for_msg(struct rsc_drv *drv,
+ const struct tcs_request *msg)
+{
+ int type, ret;
+ struct tcs_group *tcs;
+
+ switch (msg->state) {
+ case RPMH_ACTIVE_ONLY_STATE:
+ type = ACTIVE_TCS;
+ break;
+ case RPMH_WAKE_ONLY_STATE:
+ type = WAKE_TCS;
+ break;
+ case RPMH_SLEEP_STATE:
+ type = SLEEP_TCS;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ /*
+ * If we are making an active request on a RSC that does not have a
+ * dedicated TCS for active state use, then re-purpose a wake TCS to
+ * send active votes.
+ * NOTE: The driver must be aware that this RSC does not have a
+ * dedicated AMC, and therefore would invalidate the sleep and wake
+ * TCSes before making an active state request.
+ */
+ tcs = get_tcs_of_type(drv, type);
+ if (msg->state == RPMH_ACTIVE_ONLY_STATE && IS_ERR(tcs)) {
+ tcs = get_tcs_of_type(drv, WAKE_TCS);
+ if (!IS_ERR(tcs)) {
+ ret = rpmh_rsc_invalidate(drv);
+ if (ret)
+ return ERR_PTR(ret);
+ }
+ }
+
+ return tcs;
+}
+
+static const struct tcs_request *get_req_from_tcs(struct rsc_drv *drv,
+ int tcs_id)
+{
+ struct tcs_group *tcs;
+ int i;
+
+ for (i = 0; i < drv->num_tcs; i++) {
+ tcs = &drv->tcs[i];
+ if (tcs->mask & BIT(tcs_id))
+ return tcs->req[tcs_id - tcs->offset];
+ }
+
+ return NULL;
+}
+
+/**
+ * tcs_tx_done: TX Done interrupt handler
+ */
+static irqreturn_t tcs_tx_done(int irq, void *p)
+{
+ struct rsc_drv *drv = p;
+ int i, j, err;
+ unsigned long irq_status;
+ const struct tcs_request *req;
+ struct tcs_cmd *cmd;
+
+ irq_status = read_tcs_reg(drv, RSC_DRV_IRQ_STATUS, 0, 0);
+
+ for_each_set_bit(i, &irq_status, BITS_PER_LONG) {
+ req = get_req_from_tcs(drv, i);
+ if (!req) {
+ WARN_ON(1);
+ goto skip;
+ }
+
+ err = 0;
+ for (j = 0; j < req->num_cmds; j++) {
+ u32 sts;
+
+ cmd = &req->cmds[j];
+ sts = read_tcs_reg(drv, RSC_DRV_CMD_STATUS, i, j);
+ if (!(sts & CMD_STATUS_ISSUED) ||
+ ((req->wait_for_compl || cmd->wait) &&
+ !(sts & CMD_STATUS_COMPL))) {
+ pr_err("Incomplete request: %s: addr=%#x data=%#x",
+ drv->name, cmd->addr, cmd->data);
+ err = -EIO;
+ }
+ }
+
+ trace_rpmh_tx_done(drv, i, req, err);
+skip:
+ /* Reclaim the TCS */
+ write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
+ write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
+ spin_lock(&drv->lock);
+ clear_bit(i, drv->tcs_in_use);
+ spin_unlock(&drv->lock);
+ if (req)
+ rpmh_tx_done(req, err);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
+ const struct tcs_request *msg)
+{
+ u32 msgid, cmd_msgid;
+ u32 cmd_enable = 0;
+ u32 cmd_complete;
+ struct tcs_cmd *cmd;
+ int i, j;
+
+ cmd_msgid = CMD_MSGID_LEN;
+ cmd_msgid |= msg->wait_for_compl ? CMD_MSGID_RESP_REQ : 0;
+ cmd_msgid |= CMD_MSGID_WRITE;
+
+ cmd_complete = read_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0);
+
+ for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) {
+ cmd = &msg->cmds[i];
+ cmd_enable |= BIT(j);
+ cmd_complete |= cmd->wait << j;
+ msgid = cmd_msgid;
+ msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;
+
+ write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid);
+ write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr);
+ write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data);
+ trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd);
+ }
+
+ write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, cmd_complete);
+ cmd_enable |= read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
+ write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, cmd_enable);
+}
+
+static void __tcs_trigger(struct rsc_drv *drv, int tcs_id)
+{
+ u32 enable;
+
+ /*
+ * HW req: Clear the DRV_CONTROL and enable TCS again
+ * While clearing ensure that the AMC mode trigger is cleared
+ * and then the mode enable is cleared.
+ */
+ enable = read_tcs_reg(drv, RSC_DRV_CONTROL, tcs_id, 0);
+ enable &= ~TCS_AMC_MODE_TRIGGER;
+ write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+ enable &= ~TCS_AMC_MODE_ENABLE;
+ write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+
+ /* Enable the AMC mode on the TCS and then trigger the TCS */
+ enable = TCS_AMC_MODE_ENABLE;
+ write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+ enable |= TCS_AMC_MODE_TRIGGER;
+ write_tcs_reg_sync(drv, RSC_DRV_CONTROL, tcs_id, enable);
+}
+
+static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
+ const struct tcs_request *msg)
+{
+ unsigned long curr_enabled;
+ u32 addr;
+ int i, j, k;
+ int tcs_id = tcs->offset;
+
+ for (i = 0; i < tcs->num_tcs; i++, tcs_id++) {
+ if (tcs_is_free(drv, tcs_id))
+ continue;
+
+ curr_enabled = read_tcs_reg(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0);
+
+ for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) {
+ addr = read_tcs_reg(drv, RSC_DRV_CMD_ADDR, tcs_id, j);
+ for (k = 0; k < msg->num_cmds; k++) {
+ if (addr == msg->cmds[k].addr)
+ return -EBUSY;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int find_free_tcs(struct tcs_group *tcs)
+{
+ int i;
+
+ for (i = 0; i < tcs->num_tcs; i++) {
+ if (tcs_is_free(tcs->drv, tcs->offset + i))
+ return tcs->offset + i;
+ }
+
+ return -EBUSY;
+}
+
+static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg)
+{
+ struct tcs_group *tcs;
+ int tcs_id;
+ unsigned long flags;
+ int ret;
+
+ tcs = get_tcs_for_msg(drv, msg);
+ if (IS_ERR(tcs))
+ return PTR_ERR(tcs);
+
+ spin_lock_irqsave(&tcs->lock, flags);
+ spin_lock(&drv->lock);
+ /*
+ * The h/w does not like if we send a request to the same address,
+ * when one is already in-flight or being processed.
+ */
+ ret = check_for_req_inflight(drv, tcs, msg);
+ if (ret) {
+ spin_unlock(&drv->lock);
+ goto done_write;
+ }
+
+ tcs_id = find_free_tcs(tcs);
+ if (tcs_id < 0) {
+ ret = tcs_id;
+ spin_unlock(&drv->lock);
+ goto done_write;
+ }
+
+ tcs->req[tcs_id - tcs->offset] = msg;
+ set_bit(tcs_id, drv->tcs_in_use);
+ spin_unlock(&drv->lock);
+
+ __tcs_buffer_write(drv, tcs_id, 0, msg);
+ __tcs_trigger(drv, tcs_id);
+
+done_write:
+ spin_unlock_irqrestore(&tcs->lock, flags);
+ return ret;
+}
+
+/**
+ * rpmh_rsc_send_data: Validate the incoming message and write to the
+ * appropriate TCS block.
+ *
+ * @drv: the controller
+ * @msg: the data to be sent
+ *
+ * Return: 0 on success, -EINVAL on error.
+ * Note: This call blocks until a valid data is written to the TCS.
+ */
+int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
+{
+ int ret;
+
+ if (!msg || !msg->cmds || !msg->num_cmds ||
+ msg->num_cmds > MAX_RPMH_PAYLOAD) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ do {
+ ret = tcs_write(drv, msg);
+ if (ret == -EBUSY) {
+ pr_info_ratelimited("TCS Busy, retrying RPMH message send: addr=%#x\n",
+ msg->cmds[0].addr);
+ udelay(10);
+ }
+ } while (ret == -EBUSY);
+
+ return ret;
+}
+
+static int find_match(const struct tcs_group *tcs, const struct tcs_cmd *cmd,
+ int len)
+{
+ int i, j;
+
+ /* Check for already cached commands */
+ for_each_set_bit(i, tcs->slots, MAX_TCS_SLOTS) {
+ if (tcs->cmd_cache[i] != cmd[0].addr)
+ continue;
+ if (i + len >= tcs->num_tcs * tcs->ncpt)
+ goto seq_err;
+ for (j = 0; j < len; j++) {
+ if (tcs->cmd_cache[i + j] != cmd[j].addr)
+ goto seq_err;
+ }
+ return i;
+ }
+
+ return -ENODATA;
+
+seq_err:
+ WARN(1, "Message does not match previous sequence.\n");
+ return -EINVAL;
+}
+
+static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
+ int *tcs_id, int *cmd_id)
+{
+ int slot, offset;
+ int i = 0;
+
+ /* Find if we already have the msg in our TCS */
+ slot = find_match(tcs, msg->cmds, msg->num_cmds);
+ if (slot >= 0)
+ goto copy_data;
+
+ /* Do over, until we can fit the full payload in a TCS */
+ do {
+ slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS,
+ i, msg->num_cmds, 0);
+ if (slot == tcs->num_tcs * tcs->ncpt)
+ return -ENOMEM;
+ i += tcs->ncpt;
+ } while (slot + msg->num_cmds - 1 >= i);
+
+copy_data:
+ bitmap_set(tcs->slots, slot, msg->num_cmds);
+ /* Copy the addresses of the resources over to the slots */
+ for (i = 0; i < msg->num_cmds; i++)
+ tcs->cmd_cache[slot + i] = msg->cmds[i].addr;
+
+ offset = slot / tcs->ncpt;
+ *tcs_id = offset + tcs->offset;
+ *cmd_id = slot % tcs->ncpt;
+
+ return 0;
+}
+
+static int tcs_ctrl_write(struct rsc_drv *drv, const struct tcs_request *msg)
+{
+ struct tcs_group *tcs;
+ int tcs_id = 0, cmd_id = 0;
+ unsigned long flags;
+ int ret;
+
+ tcs = get_tcs_for_msg(drv, msg);
+ if (IS_ERR(tcs))
+ return PTR_ERR(tcs);
+
+ spin_lock_irqsave(&tcs->lock, flags);
+ /* find the TCS id and the command in the TCS to write to */
+ ret = find_slots(tcs, msg, &tcs_id, &cmd_id);
+ if (!ret)
+ __tcs_buffer_write(drv, tcs_id, cmd_id, msg);
+ spin_unlock_irqrestore(&tcs->lock, flags);
+
+ return ret;
+}
+
+/**
+ * rpmh_rsc_write_ctrl_data: Write request to the controller
+ *
+ * @drv: the controller
+ * @msg: the data to be written to the controller
+ *
+ * There is no response returned for writing the request to the controller.
+ */
+int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg)
+{
+ if (!msg || !msg->cmds || !msg->num_cmds ||
+ msg->num_cmds > MAX_RPMH_PAYLOAD) {
+ pr_err("Payload error\n");
+ return -EINVAL;
+ }
+
+ /* Data sent to this API will not be sent immediately */
+ if (msg->state == RPMH_ACTIVE_ONLY_STATE)
+ return -EINVAL;
+
+ return tcs_ctrl_write(drv, msg);
+}
+
+static int rpmh_probe_tcs_config(struct platform_device *pdev,
+ struct rsc_drv *drv)
+{
+ struct tcs_type_config {
+ u32 type;
+ u32 n;
+ } tcs_cfg[TCS_TYPE_NR] = { { 0 } };
+ struct device_node *dn = pdev->dev.of_node;
+ u32 config, max_tcs, ncpt, offset;
+ int i, ret, n, st = 0;
+ struct tcs_group *tcs;
+ struct resource *res;
+ void __iomem *base;
+ char drv_id[10] = {0};
+
+ snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, drv_id);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset);
+ if (ret)
+ return ret;
+ drv->tcs_base = base + offset;
+
+ config = readl_relaxed(base + DRV_PRNT_CHLD_CONFIG);
+
+ max_tcs = config;
+ max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id);
+ max_tcs = max_tcs >> (DRV_NUM_TCS_SHIFT * drv->id);
+
+ ncpt = config & (DRV_NCPT_MASK << DRV_NCPT_SHIFT);
+ ncpt = ncpt >> DRV_NCPT_SHIFT;
+
+ n = of_property_count_u32_elems(dn, "qcom,tcs-config");
+ if (n != 2 * TCS_TYPE_NR)
+ return -EINVAL;
+
+ for (i = 0; i < TCS_TYPE_NR; i++) {
+ ret = of_property_read_u32_index(dn, "qcom,tcs-config",
+ i * 2, &tcs_cfg[i].type);
+ if (ret)
+ return ret;
+ if (tcs_cfg[i].type >= TCS_TYPE_NR)
+ return -EINVAL;
+
+ ret = of_property_read_u32_index(dn, "qcom,tcs-config",
+ i * 2 + 1, &tcs_cfg[i].n);
+ if (ret)
+ return ret;
+ if (tcs_cfg[i].n > MAX_TCS_PER_TYPE)
+ return -EINVAL;
+ }
+
+ for (i = 0; i < TCS_TYPE_NR; i++) {
+ tcs = &drv->tcs[tcs_cfg[i].type];
+ if (tcs->drv)
+ return -EINVAL;
+ tcs->drv = drv;
+ tcs->type = tcs_cfg[i].type;
+ tcs->num_tcs = tcs_cfg[i].n;
+ tcs->ncpt = ncpt;
+ spin_lock_init(&tcs->lock);
+
+ if (!tcs->num_tcs || tcs->type == CONTROL_TCS)
+ continue;
+
+ if (st + tcs->num_tcs > max_tcs ||
+ st + tcs->num_tcs >= BITS_PER_BYTE * sizeof(tcs->mask))
+ return -EINVAL;
+
+ tcs->mask = ((1 << tcs->num_tcs) - 1) << st;
+ tcs->offset = st;
+ st += tcs->num_tcs;
+
+ /*
+ * Allocate memory to cache sleep and wake requests to
+ * avoid reading TCS register memory.
+ */
+ if (tcs->type == ACTIVE_TCS)
+ continue;
+
+ tcs->cmd_cache = devm_kcalloc(&pdev->dev,
+ tcs->num_tcs * ncpt, sizeof(u32),
+ GFP_KERNEL);
+ if (!tcs->cmd_cache)
+ return -ENOMEM;
+ }
+
+ drv->num_tcs = st;
+
+ return 0;
+}
+
+static int rpmh_rsc_probe(struct platform_device *pdev)
+{
+ struct device_node *dn = pdev->dev.of_node;
+ struct rsc_drv *drv;
+ int ret, irq;
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(dn, "qcom,drv-id", &drv->id);
+ if (ret)
+ return ret;
+
+ drv->name = of_get_property(dn, "label", NULL);
+ if (!drv->name)
+ drv->name = dev_name(&pdev->dev);
+
+ ret = rpmh_probe_tcs_config(pdev, drv);
+ if (ret)
+ return ret;
+
+ spin_lock_init(&drv->lock);
+ bitmap_zero(drv->tcs_in_use, MAX_TCS_NR);
+
+ irq = platform_get_irq(pdev, drv->id);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, tcs_tx_done,
+ IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
+ drv->name, drv);
+ if (ret)
+ return ret;
+
+ /* Enable the active TCS to send requests immediately */
+ write_tcs_reg(drv, RSC_DRV_IRQ_ENABLE, 0, drv->tcs[ACTIVE_TCS].mask);
+
+ spin_lock_init(&drv->ctrlr.cache_lock);
+ INIT_LIST_HEAD(&drv->ctrlr.cache);
+ INIT_LIST_HEAD(&drv->ctrlr.batch_cache);
+
+ dev_set_drvdata(&pdev->dev, drv);
+
+ return devm_of_platform_populate(&pdev->dev);
+}
+
+static const struct of_device_id rpmh_drv_match[] = {
+ { .compatible = "qcom,rpmh-rsc", },
+ { }
+};
+
+static struct platform_driver rpmh_driver = {
+ .probe = rpmh_rsc_probe,
+ .driver = {
+ .name = "rpmh",
+ .of_match_table = rpmh_drv_match,
+ },
+};
+
+static int __init rpmh_driver_init(void)
+{
+ return platform_driver_register(&rpmh_driver);
+}
+arch_initcall(rpmh_driver_init);
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
new file mode 100644
index 000000000000..63ed7777f98a
--- /dev/null
+++ b/drivers/soc/qcom/rpmh.c
@@ -0,0 +1,512 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <soc/qcom/rpmh.h>
+
+#include "rpmh-internal.h"
+
+#define RPMH_TIMEOUT_MS msecs_to_jiffies(10000)
+
+#define DEFINE_RPMH_MSG_ONSTACK(dev, s, q, name) \
+ struct rpmh_request name = { \
+ .msg = { \
+ .state = s, \
+ .cmds = name.cmd, \
+ .num_cmds = 0, \
+ .wait_for_compl = true, \
+ }, \
+ .cmd = { { 0 } }, \
+ .completion = q, \
+ .dev = dev, \
+ .needs_free = false, \
+ }
+
+#define ctrlr_to_drv(ctrlr) container_of(ctrlr, struct rsc_drv, ctrlr)
+
+/**
+ * struct cache_req: the request object for caching
+ *
+ * @addr: the address of the resource
+ * @sleep_val: the sleep vote
+ * @wake_val: the wake vote
+ * @list: linked list obj
+ */
+struct cache_req {
+ u32 addr;
+ u32 sleep_val;
+ u32 wake_val;
+ struct list_head list;
+};
+
+/**
+ * struct batch_cache_req - An entry in our batch catch
+ *
+ * @list: linked list obj
+ * @count: number of messages
+ * @rpm_msgs: the messages
+ */
+
+struct batch_cache_req {
+ struct list_head list;
+ int count;
+ struct rpmh_request rpm_msgs[];
+};
+
+static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
+{
+ struct rsc_drv *drv = dev_get_drvdata(dev->parent);
+
+ return &drv->ctrlr;
+}
+
+void rpmh_tx_done(const struct tcs_request *msg, int r)
+{
+ struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
+ msg);
+ struct completion *compl = rpm_msg->completion;
+
+ rpm_msg->err = r;
+
+ if (r)
+ dev_err(rpm_msg->dev, "RPMH TX fail in msg addr=%#x, err=%d\n",
+ rpm_msg->msg.cmds[0].addr, r);
+
+ if (!compl)
+ goto exit;
+
+ /* Signal the blocking thread we are done */
+ complete(compl);
+
+exit:
+ if (rpm_msg->needs_free)
+ kfree(rpm_msg);
+}
+
+static struct cache_req *__find_req(struct rpmh_ctrlr *ctrlr, u32 addr)
+{
+ struct cache_req *p, *req = NULL;
+
+ list_for_each_entry(p, &ctrlr->cache, list) {
+ if (p->addr == addr) {
+ req = p;
+ break;
+ }
+ }
+
+ return req;
+}
+
+static struct cache_req *cache_rpm_request(struct rpmh_ctrlr *ctrlr,
+ enum rpmh_state state,
+ struct tcs_cmd *cmd)
+{
+ struct cache_req *req;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrlr->cache_lock, flags);
+ req = __find_req(ctrlr, cmd->addr);
+ if (req)
+ goto existing;
+
+ req = kzalloc(sizeof(*req), GFP_ATOMIC);
+ if (!req) {
+ req = ERR_PTR(-ENOMEM);
+ goto unlock;
+ }
+
+ req->addr = cmd->addr;
+ req->sleep_val = req->wake_val = UINT_MAX;
+ INIT_LIST_HEAD(&req->list);
+ list_add_tail(&req->list, &ctrlr->cache);
+
+existing:
+ switch (state) {
+ case RPMH_ACTIVE_ONLY_STATE:
+ if (req->sleep_val != UINT_MAX)
+ req->wake_val = cmd->data;
+ break;
+ case RPMH_WAKE_ONLY_STATE:
+ req->wake_val = cmd->data;
+ break;
+ case RPMH_SLEEP_STATE:
+ req->sleep_val = cmd->data;
+ break;
+ default:
+ break;
+ };
+
+ ctrlr->dirty = true;
+unlock:
+ spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
+
+ return req;
+}
+
+/**
+ * __rpmh_write: Cache and send the RPMH request
+ *
+ * @dev: The device making the request
+ * @state: Active/Sleep request type
+ * @rpm_msg: The data that needs to be sent (cmds).
+ *
+ * Cache the RPMH request and send if the state is ACTIVE_ONLY.
+ * SLEEP/WAKE_ONLY requests are not sent to the controller at
+ * this time. Use rpmh_flush() to send them to the controller.
+ */
+static int __rpmh_write(const struct device *dev, enum rpmh_state state,
+ struct rpmh_request *rpm_msg)
+{
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+ int ret = -EINVAL;
+ struct cache_req *req;
+ int i;
+
+ rpm_msg->msg.state = state;
+
+ /* Cache the request in our store and link the payload */
+ for (i = 0; i < rpm_msg->msg.num_cmds; i++) {
+ req = cache_rpm_request(ctrlr, state, &rpm_msg->msg.cmds[i]);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ }
+
+ rpm_msg->msg.state = state;
+
+ if (state == RPMH_ACTIVE_ONLY_STATE) {
+ WARN_ON(irqs_disabled());
+ ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg);
+ } else {
+ ret = rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg);
+ /* Clean up our call by spoofing tx_done */
+ rpmh_tx_done(&rpm_msg->msg, ret);
+ }
+
+ return ret;
+}
+
+static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{
+ if (!cmd || !n || n > MAX_RPMH_PAYLOAD)
+ return -EINVAL;
+
+ memcpy(req->cmd, cmd, n * sizeof(*cmd));
+
+ req->msg.state = state;
+ req->msg.cmds = req->cmd;
+ req->msg.num_cmds = n;
+
+ return 0;
+}
+
+/**
+ * rpmh_write_async: Write a set of RPMH commands
+ *
+ * @dev: The device making the request
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The number of elements in payload
+ *
+ * Write a set of RPMH commands, the order of commands is maintained
+ * and will be sent as a single shot.
+ */
+int rpmh_write_async(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{
+ struct rpmh_request *rpm_msg;
+ int ret;
+
+ rpm_msg = kzalloc(sizeof(*rpm_msg), GFP_ATOMIC);
+ if (!rpm_msg)
+ return -ENOMEM;
+ rpm_msg->needs_free = true;
+
+ ret = __fill_rpmh_msg(rpm_msg, state, cmd, n);
+ if (ret) {
+ kfree(rpm_msg);
+ return ret;
+ }
+
+ return __rpmh_write(dev, state, rpm_msg);
+}
+EXPORT_SYMBOL(rpmh_write_async);
+
+/**
+ * rpmh_write: Write a set of RPMH commands and block until response
+ *
+ * @rc: The RPMH handle got from rpmh_get_client
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The number of elements in @cmd
+ *
+ * May sleep. Do not call from atomic contexts.
+ */
+int rpmh_write(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{
+ DECLARE_COMPLETION_ONSTACK(compl);
+ DEFINE_RPMH_MSG_ONSTACK(dev, state, &compl, rpm_msg);
+ int ret;
+
+ if (!cmd || !n || n > MAX_RPMH_PAYLOAD)
+ return -EINVAL;
+
+ memcpy(rpm_msg.cmd, cmd, n * sizeof(*cmd));
+ rpm_msg.msg.num_cmds = n;
+
+ ret = __rpmh_write(dev, state, &rpm_msg);
+ if (ret)
+ return ret;
+
+ ret = wait_for_completion_timeout(&compl, RPMH_TIMEOUT_MS);
+ WARN_ON(!ret);
+ return (ret > 0) ? 0 : -ETIMEDOUT;
+}
+EXPORT_SYMBOL(rpmh_write);
+
+static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrlr->cache_lock, flags);
+ list_add_tail(&req->list, &ctrlr->batch_cache);
+ spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
+}
+
+static int flush_batch(struct rpmh_ctrlr *ctrlr)
+{
+ struct batch_cache_req *req;
+ const struct rpmh_request *rpm_msg;
+ unsigned long flags;
+ int ret = 0;
+ int i;
+
+ /* Send Sleep/Wake requests to the controller, expect no response */
+ spin_lock_irqsave(&ctrlr->cache_lock, flags);
+ list_for_each_entry(req, &ctrlr->batch_cache, list) {
+ for (i = 0; i < req->count; i++) {
+ rpm_msg = req->rpm_msgs + i;
+ ret = rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr),
+ &rpm_msg->msg);
+ if (ret)
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
+
+ return ret;
+}
+
+static void invalidate_batch(struct rpmh_ctrlr *ctrlr)
+{
+ struct batch_cache_req *req, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrlr->cache_lock, flags);
+ list_for_each_entry_safe(req, tmp, &ctrlr->batch_cache, list)
+ kfree(req);
+ INIT_LIST_HEAD(&ctrlr->batch_cache);
+ spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
+}
+
+/**
+ * rpmh_write_batch: Write multiple sets of RPMH commands and wait for the
+ * batch to finish.
+ *
+ * @dev: the device making the request
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The array of count of elements in each batch, 0 terminated.
+ *
+ * Write a request to the RSC controller without caching. If the request
+ * state is ACTIVE, 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.
+ *
+ * May sleep. Do not call from atomic contexts for ACTIVE_ONLY requests.
+ */
+int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 *n)
+{
+ struct batch_cache_req *req;
+ struct rpmh_request *rpm_msgs;
+ DECLARE_COMPLETION_ONSTACK(compl);
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+ unsigned long time_left;
+ int count = 0;
+ int ret, i, j;
+
+ if (!cmd || !n)
+ return -EINVAL;
+
+ while (n[count] > 0)
+ count++;
+ if (!count)
+ return -EINVAL;
+
+ req = kzalloc(sizeof(*req) + count * sizeof(req->rpm_msgs[0]),
+ GFP_ATOMIC);
+ if (!req)
+ return -ENOMEM;
+ req->count = count;
+ rpm_msgs = req->rpm_msgs;
+
+ for (i = 0; i < count; i++) {
+ __fill_rpmh_msg(rpm_msgs + i, state, cmd, n[i]);
+ cmd += n[i];
+ }
+
+ if (state != RPMH_ACTIVE_ONLY_STATE) {
+ cache_batch(ctrlr, req);
+ return 0;
+ }
+
+ for (i = 0; i < count; i++) {
+ rpm_msgs[i].completion = &compl;
+ ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msgs[i].msg);
+ if (ret) {
+ pr_err("Error(%d) sending RPMH message addr=%#x\n",
+ ret, rpm_msgs[i].msg.cmds[0].addr);
+ for (j = i; j < count; j++)
+ rpmh_tx_done(&rpm_msgs[j].msg, ret);
+ break;
+ }
+ }
+
+ time_left = RPMH_TIMEOUT_MS;
+ for (i = 0; i < count; i++) {
+ time_left = wait_for_completion_timeout(&compl, time_left);
+ if (!time_left) {
+ /*
+ * Better hope they never finish because they'll signal
+ * the completion on our stack and that's bad once
+ * we've returned from the function.
+ */
+ WARN_ON(1);
+ ret = -ETIMEDOUT;
+ goto exit;
+ }
+ }
+
+exit:
+ kfree(req);
+
+ return ret;
+}
+EXPORT_SYMBOL(rpmh_write_batch);
+
+static int is_req_valid(struct cache_req *req)
+{
+ return (req->sleep_val != UINT_MAX &&
+ req->wake_val != UINT_MAX &&
+ req->sleep_val != req->wake_val);
+}
+
+static int send_single(const struct device *dev, enum rpmh_state state,
+ u32 addr, u32 data)
+{
+ DEFINE_RPMH_MSG_ONSTACK(dev, state, NULL, rpm_msg);
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+
+ /* Wake sets are always complete and sleep sets are not */
+ rpm_msg.msg.wait_for_compl = (state == RPMH_WAKE_ONLY_STATE);
+ rpm_msg.cmd[0].addr = addr;
+ rpm_msg.cmd[0].data = data;
+ rpm_msg.msg.num_cmds = 1;
+
+ return rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), &rpm_msg.msg);
+}
+
+/**
+ * rpmh_flush: Flushes the buffered active and sleep sets to TCS
+ *
+ * @dev: The device making the request
+ *
+ * Return: -EBUSY if the controller is busy, probably waiting on a response
+ * to a RPMH request sent earlier.
+ *
+ * This function is always called from the sleep code from the last CPU
+ * that is powering down the entire system. Since no other RPMH API would be
+ * executing at this time, it is safe to run lockless.
+ */
+int rpmh_flush(const struct device *dev)
+{
+ struct cache_req *p;
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+ int ret;
+
+ if (!ctrlr->dirty) {
+ pr_debug("Skipping flush, TCS has latest data.\n");
+ return 0;
+ }
+
+ /* First flush the cached batch requests */
+ ret = flush_batch(ctrlr);
+ if (ret)
+ return ret;
+
+ /*
+ * Nobody else should be calling this function other than system PM,
+ * hence we can run without locks.
+ */
+ list_for_each_entry(p, &ctrlr->cache, list) {
+ if (!is_req_valid(p)) {
+ pr_debug("%s: skipping RPMH req: a:%#x s:%#x w:%#x",
+ __func__, p->addr, p->sleep_val, p->wake_val);
+ continue;
+ }
+ ret = send_single(dev, RPMH_SLEEP_STATE, p->addr, p->sleep_val);
+ if (ret)
+ return ret;
+ ret = send_single(dev, RPMH_WAKE_ONLY_STATE,
+ p->addr, p->wake_val);
+ if (ret)
+ return ret;
+ }
+
+ ctrlr->dirty = false;
+
+ return 0;
+}
+EXPORT_SYMBOL(rpmh_flush);
+
+/**
+ * rpmh_invalidate: Invalidate all sleep and active sets
+ * sets.
+ *
+ * @dev: The device making the request
+ *
+ * Invalidate the sleep and active values in the TCS blocks.
+ */
+int rpmh_invalidate(const struct device *dev)
+{
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+ int ret;
+
+ invalidate_batch(ctrlr);
+ ctrlr->dirty = true;
+
+ do {
+ ret = rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr));
+ } while (ret == -EAGAIN);
+
+ return ret;
+}
+EXPORT_SYMBOL(rpmh_invalidate);
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 70b2ee80d6bd..bf4bd71ab53f 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -364,11 +364,6 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
end = phdr_to_last_uncached_entry(phdr);
cached = phdr_to_last_cached_entry(phdr);
- if (smem->global_partition) {
- dev_err(smem->dev, "Already found the global partition\n");
- return -EINVAL;
- }
-
while (hdr < end) {
if (hdr->canary != SMEM_PRIVATE_CANARY)
goto bad_canary;
@@ -736,6 +731,11 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
bool found = false;
int i;
+ if (smem->global_partition) {
+ dev_err(smem->dev, "Already found the global partition\n");
+ return -EINVAL;
+ }
+
ptable = qcom_smem_get_ptable(smem);
if (IS_ERR(ptable))
return PTR_ERR(ptable);
diff --git a/drivers/soc/qcom/trace-rpmh.h b/drivers/soc/qcom/trace-rpmh.h
new file mode 100644
index 000000000000..feb0cb455e37
--- /dev/null
+++ b/drivers/soc/qcom/trace-rpmh.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#if !defined(_TRACE_RPMH_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_RPMH_H
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM rpmh
+
+#include <linux/tracepoint.h>
+#include "rpmh-internal.h"
+
+TRACE_EVENT(rpmh_tx_done,
+
+ TP_PROTO(struct rsc_drv *d, int m, const struct tcs_request *r, int e),
+
+ TP_ARGS(d, m, r, e),
+
+ TP_STRUCT__entry(
+ __string(name, d->name)
+ __field(int, m)
+ __field(u32, addr)
+ __field(u32, data)
+ __field(int, err)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, d->name);
+ __entry->m = m;
+ __entry->addr = r->cmds[0].addr;
+ __entry->data = r->cmds[0].data;
+ __entry->err = e;
+ ),
+
+ TP_printk("%s: ack: tcs-m: %d addr: %#x data: %#x errno: %d",
+ __get_str(name), __entry->m, __entry->addr, __entry->data,
+ __entry->err)
+);
+
+TRACE_EVENT(rpmh_send_msg,
+
+ TP_PROTO(struct rsc_drv *d, int m, int n, u32 h,
+ const struct tcs_cmd *c),
+
+ TP_ARGS(d, m, n, h, c),
+
+ TP_STRUCT__entry(
+ __string(name, d->name)
+ __field(int, m)
+ __field(int, n)
+ __field(u32, hdr)
+ __field(u32, addr)
+ __field(u32, data)
+ __field(bool, wait)
+ ),
+
+ TP_fast_assign(
+ __assign_str(name, d->name);
+ __entry->m = m;
+ __entry->n = n;
+ __entry->hdr = h;
+ __entry->addr = c->addr;
+ __entry->data = c->data;
+ __entry->wait = c->wait;
+ ),
+
+ TP_printk("%s: send-msg: tcs(m): %d cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d",
+ __get_str(name), __entry->m, __entry->n, __entry->hdr,
+ __entry->addr, __entry->data, __entry->wait)
+);
+
+#endif /* _TRACE_RPMH_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace-rpmh
+
+#include <trace/define_trace.h>
diff --git a/include/dt-bindings/clock/qcom,gcc-msm8996.h b/include/dt-bindings/clock/qcom,gcc-msm8996.h
index 75b07cf5eed0..db80f2ee571b 100644
--- a/include/dt-bindings/clock/qcom,gcc-msm8996.h
+++ b/include/dt-bindings/clock/qcom,gcc-msm8996.h
@@ -235,6 +235,15 @@
#define GCC_RX1_USB2_CLKREF_CLK 218
#define GCC_HLOS1_VOTE_LPASS_CORE_SMMU_CLK 219
#define GCC_HLOS1_VOTE_LPASS_ADSP_SMMU_CLK 220
+#define GCC_EDP_CLKREF_CLK 221
+#define GCC_MSS_CFG_AHB_CLK 222
+#define GCC_MSS_Q6_BIMC_AXI_CLK 223
+#define GCC_MSS_SNOC_AXI_CLK 224
+#define GCC_MSS_MNOC_BIMC_AXI_CLK 225
+#define GCC_DCC_AHB_CLK 226
+#define GCC_AGGRE0_NOC_MPU_CFG_AHB_CLK 227
+#define GCC_MMSS_GPLL0_DIV_CLK 228
+#define GCC_MSS_GPLL0_DIV_CLK 229
#define GCC_SYSTEM_NOC_BCR 0
#define GCC_CONFIG_NOC_BCR 1
diff --git a/include/dt-bindings/interconnect/qcom.h b/include/dt-bindings/interconnect/qcom.h
new file mode 100644
index 000000000000..fe23aff7b619
--- /dev/null
+++ b/include/dt-bindings/interconnect/qcom.h
@@ -0,0 +1,440 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Qualcomm interconnect IDs
+ *
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef __QCOM_INTERCONNECT_IDS_H
+#define __QCOM_INTERCONNECT_IDS_H
+
+#define FAB_BIMC 0
+#define FAB_SYS_NOC 1024
+#define FAB_MMSS_NOC 2048
+#define FAB_OCMEM_NOC 3072
+#define FAB_PERIPH_NOC 4096
+#define FAB_CONFIG_NOC 5120
+#define FAB_OCMEM_VNOC 6144
+#define FAB_MMSS_AHB 2049
+#define FAB_A0_NOC 6145
+#define FAB_A1_NOC 6146
+#define FAB_A2_NOC 6147
+#define FAB_GNOC 6148
+#define FAB_CR_VIRT 6149
+
+#define MASTER_AMPSS_M0 1
+#define MASTER_AMPSS_M1 2
+#define APPSS_MASTER_FAB_MMSS 3
+#define APPSS_MASTER_FAB_SYSTEM 4
+#define SYSTEM_MASTER_FAB_APPSS 5
+#define MASTER_SPS 6
+#define MASTER_ADM_PORT0 7
+#define MASTER_ADM_PORT1 8
+#define SYSTEM_MASTER_ADM1_PORT0 9
+#define MASTER_ADM1_PORT1 10
+#define MASTER_LPASS_PROC 11
+#define MASTER_MSS_PROCI 12
+#define MASTER_MSS_PROCD 13
+#define MASTER_MSS_MDM_PORT0 14
+#define MASTER_LPASS 15
+#define SYSTEM_MASTER_CPSS_FPB 16
+#define SYSTEM_MASTER_SYSTEM_FPB 17
+#define SYSTEM_MASTER_MMSS_FPB 18
+#define MASTER_ADM1_CI 19
+#define MASTER_ADM0_CI 20
+#define MASTER_MSS_MDM_PORT1 21
+#define MASTER_MDP_PORT0 22
+#define MASTER_MDP_PORT1 23
+#define MMSS_MASTER_ADM1_PORT0 24
+#define MASTER_ROTATOR 25
+#define MASTER_GRAPHICS_3D 26
+#define MASTER_JPEG_DEC 27
+#define MASTER_GRAPHICS_2D_CORE0 28
+#define MASTER_VFE 29
+#define MASTER_VPE 30
+#define MASTER_JPEG_ENC 31
+#define MASTER_GRAPHICS_2D_CORE1 32
+#define MMSS_MASTER_APPS_FAB 33
+#define MASTER_HD_CODEC_PORT0 34
+#define MASTER_HD_CODEC_PORT1 35
+#define MASTER_SPDM 36
+#define MASTER_RPM 37
+#define MASTER_MSS 38
+#define MASTER_RIVA 39
+#define MASTER_SNOC_VMEM 40
+#define MASTER_MSS_SW_PROC 41
+#define MASTER_MSS_FW_PROC 42
+#define MASTER_HMSS 43
+#define MASTER_GSS_NAV 44
+#define MASTER_PCIE 45
+#define MASTER_SATA 46
+#define MASTER_CRYPTO 47
+#define MASTER_VIDEO_CAP 48
+#define MASTER_GRAPHICS_3D_PORT1 49
+#define MASTER_VIDEO_ENC 50
+#define MASTER_VIDEO_DEC 51
+#define MASTER_LPASS_AHB 52
+#define MASTER_QDSS_BAM 53
+#define MASTER_SNOC_CFG 54
+#define MASTER_CRYPTO_CORE0 55
+#define MASTER_CRYPTO_CORE1 56
+#define MASTER_MSS_NAV 57
+#define MASTER_OCMEM_DMA 58
+#define MASTER_WCSS 59
+#define MASTER_QDSS_ETR 60
+#define MASTER_USB3 61
+#define MASTER_JPEG 62
+#define MASTER_VIDEO_P0 63
+#define MASTER_VIDEO_P1 64
+#define MASTER_MSS_PROC 65
+#define MASTER_JPEG_OCMEM 66
+#define MASTER_MDP_OCMEM 67
+#define MASTER_VIDEO_P0_OCMEM 68
+#define MASTER_VIDEO_P1_OCMEM 69
+#define MASTER_VFE_OCMEM 70
+#define MASTER_CNOC_ONOC_CFG 71
+#define MASTER_RPM_INST 72
+#define MASTER_RPM_DATA 73
+#define MASTER_RPM_SYS 74
+#define MASTER_DEHR 75
+#define MASTER_QDSS_DAP 76
+#define MASTER_TIC 77
+#define MASTER_SDCC_1 78
+#define MASTER_SDCC_3 79
+#define MASTER_SDCC_4 80
+#define MASTER_SDCC_2 81
+#define MASTER_TSIF 82
+#define MASTER_BAM_DMA 83
+#define MASTER_BLSP_2 84
+#define MASTER_USB_HSIC 85
+#define MASTER_BLSP_1 86
+#define MASTER_USB_HS 87
+#define MASTER_PNOC_CFG 88
+#define MASTER_V_OCMEM_GFX3D 89
+#define MASTER_IPA 90
+#define MASTER_QPIC 91
+#define MASTER_MDPE 92
+#define MASTER_USB_HS2 93
+#define MASTER_VPU 94
+#define MASTER_UFS 95
+#define MASTER_BCAST 96
+#define MASTER_CRYPTO_CORE2 97
+#define MASTER_EMAC 98
+#define MASTER_VPU_1 99
+#define MASTER_PCIE_1 100
+#define MASTER_USB3_1 101
+#define MASTER_CNOC_MNOC_MMSS_CFG 102
+#define MASTER_CNOC_MNOC_CFG 103
+#define MASTER_TCU_0 104
+#define MASTER_TCU_1 105
+#define MASTER_CPP 106
+#define MASTER_AUDIO 107
+#define MASTER_PCIE_2 108
+#define MASTER_VFE1 109
+#define MASTER_XM_USB_HS1 110
+#define MASTER_PCNOC_BIMC_1 111
+#define MASTER_BIMC_PCNOC 112
+#define MASTER_XI_USB_HSIC 113
+#define MASTER_SGMII 114
+#define SPMI_FETCHER 115
+#define MASTER_GNOC_BIMC 116
+#define MASTER_CRVIRT_A2NOC 117
+#define MASTER_CNOC_A2NOC 118
+#define MASTER_WLAN 119
+#define MASTER_MSS_CE 120
+#define MASTER_MASTER_LAST 121
+
+#define SNOC_MM_INT_0 10000
+#define SNOC_MM_INT_1 10001
+#define SNOC_MM_INT_2 10002
+#define SNOC_MM_INT_BIMC 10003
+#define SNOC_INT_0 10004
+#define SNOC_INT_1 10005
+#define SNOC_INT_BIMC 10006
+#define SNOC_BIMC_0_MAS 10007
+#define SNOC_BIMC_1_MAS 10008
+#define SNOC_QDSS_INT 10009
+#define PNOC_SNOC_MAS 10010
+#define PNOC_SNOC_SLV 10011
+#define PNOC_INT_0 10012
+#define PNOC_INT_1 10013
+#define PNOC_M_0 10014
+#define PNOC_M_1 10015
+#define BIMC_SNOC_MAS 10016
+#define BIMC_SNOC_SLV 10017
+#define PNOC_SLV_0 10018
+#define PNOC_SLV_1 10019
+#define PNOC_SLV_2 10020
+#define PNOC_SLV_3 10021
+#define PNOC_SLV_4 10022
+#define PNOC_SLV_8 10023
+#define PNOC_SLV_9 10024
+#define SNOC_BIMC_0_SLV 10025
+#define SNOC_BIMC_1_SLV 10026
+#define MNOC_BIMC_MAS 10027
+#define MNOC_BIMC_SLV 10028
+#define BIMC_MNOC_MAS 10029
+#define BIMC_MNOC_SLV 10030
+#define SNOC_BIMC_MAS 10031
+#define SNOC_BIMC_SLV 10032
+#define CNOC_SNOC_MAS 10033
+#define CNOC_SNOC_SLV 10034
+#define SNOC_CNOC_MAS 10035
+#define SNOC_CNOC_SLV 10036
+#define OVNOC_SNOC_MAS 10037
+#define OVNOC_SNOC_SLV 10038
+#define SNOC_OVNOC_MAS 10039
+#define SNOC_OVNOC_SLV 10040
+#define SNOC_PNOC_MAS 10041
+#define SNOC_PNOC_SLV 10042
+#define BIMC_INT_APPS_EBI 10043
+#define BIMC_INT_APPS_SNOC 10044
+#define SNOC_BIMC_2_MAS 10045
+#define SNOC_BIMC_2_SLV 10046
+#define PNOC_SLV_5 10047
+#define PNOC_SLV_7 10048
+#define PNOC_INT_2 10049
+#define PNOC_INT_3 10050
+#define PNOC_INT_4 10051
+#define PNOC_INT_5 10052
+#define PNOC_INT_6 10053
+#define PNOC_INT_7 10054
+#define BIMC_SNOC_1_MAS 10055
+#define BIMC_SNOC_1_SLV 10056
+#define PNOC_A1NOC_MAS 10057
+#define PNOC_A1NOC_SLV 10058
+#define CNOC_A1NOC_MAS 10059
+#define A0NOC_SNOC_MAS 10060
+#define A0NOC_SNOC_SLV 10061
+#define A1NOC_SNOC_SLV 10062
+#define A1NOC_SNOC_MAS 10063
+#define A2NOC_SNOC_MAS 10064
+#define A2NOC_SNOC_SLV 10065
+#define SNOC_INT_2 10066
+#define A0NOC_QDSS_INT 10067
+
+#define SLAVE_EBI_CH0 512
+#define SLAVE_EBI_CH1 513
+#define SLAVE_AMPSS_L2 514
+#define APPSS_SLAVE_FAB_MMSS 515
+#define APPSS_SLAVE_FAB_SYSTEM 516
+#define SYSTEM_SLAVE_FAB_APPS 517
+#define SLAVE_SPS 518
+#define SLAVE_SYSTEM_IMEM 519
+#define SLAVE_AMPSS 520
+#define SLAVE_MSS 521
+#define SLAVE_LPASS 522
+#define SYSTEM_SLAVE_CPSS_FPB 523
+#define SYSTEM_SLAVE_SYSTEM_FPB 524
+#define SYSTEM_SLAVE_MMSS_FPB 525
+#define SLAVE_CORESIGHT 526
+#define SLAVE_RIVA 527
+#define SLAVE_SMI 528
+#define MMSS_SLAVE_FAB_APPS 529
+#define MMSS_SLAVE_FAB_APPS_1 530
+#define SLAVE_MM_IMEM 531
+#define SLAVE_CRYPTO 532
+#define SLAVE_SPDM 533
+#define SLAVE_RPM 534
+#define SLAVE_RPM_MSG_RAM 535
+#define SLAVE_MPM 536
+#define SLAVE_PMIC1_SSBI1_A 537
+#define SLAVE_PMIC1_SSBI1_B 538
+#define SLAVE_PMIC1_SSBI1_C 539
+#define SLAVE_PMIC2_SSBI2_A 540
+#define SLAVE_PMIC2_SSBI2_B 541
+#define SLAVE_GSBI1_UART 542
+#define SLAVE_GSBI2_UART 543
+#define SLAVE_GSBI3_UART 544
+#define SLAVE_GSBI4_UART 545
+#define SLAVE_GSBI5_UART 546
+#define SLAVE_GSBI6_UART 547
+#define SLAVE_GSBI7_UART 548
+#define SLAVE_GSBI8_UART 549
+#define SLAVE_GSBI9_UART 550
+#define SLAVE_GSBI10_UART 551
+#define SLAVE_GSBI11_UART 552
+#define SLAVE_GSBI12_UART 553
+#define SLAVE_GSBI1_QUP 554
+#define SLAVE_GSBI2_QUP 555
+#define SLAVE_GSBI3_QUP 556
+#define SLAVE_GSBI4_QUP 557
+#define SLAVE_GSBI5_QUP 558
+#define SLAVE_GSBI6_QUP 559
+#define SLAVE_GSBI7_QUP 560
+#define SLAVE_GSBI8_QUP 561
+#define SLAVE_GSBI9_QUP 562
+#define SLAVE_GSBI10_QUP 563
+#define SLAVE_GSBI11_QUP 564
+#define SLAVE_GSBI12_QUP 565
+#define SLAVE_EBI2_NAND 566
+#define SLAVE_EBI2_CS0 567
+#define SLAVE_EBI2_CS1 568
+#define SLAVE_EBI2_CS2 569
+#define SLAVE_EBI2_CS3 570
+#define SLAVE_EBI2_CS4 571
+#define SLAVE_EBI2_CS5 572
+#define SLAVE_USB_FS1 573
+#define SLAVE_USB_FS2 574
+#define SLAVE_TSIF 575
+#define SLAVE_MSM_TSSC 576
+#define SLAVE_MSM_PDM 577
+#define SLAVE_MSM_DIMEM 578
+#define SLAVE_MSM_TCSR 579
+#define SLAVE_MSM_PRNG 580
+#define SLAVE_GSS 581
+#define SLAVE_SATA 582
+#define SLAVE_USB3 583
+#define SLAVE_WCSS 584
+#define SLAVE_OCIMEM 585
+#define SLAVE_SNOC_OCMEM 586
+#define SLAVE_SERVICE_SNOC 587
+#define SLAVE_QDSS_STM 588
+#define SLAVE_CAMERA_CFG 589
+#define SLAVE_DISPLAY_CFG 590
+#define SLAVE_OCMEM_CFG 591
+#define SLAVE_CPR_CFG 592
+#define SLAVE_CPR_XPU_CFG 593
+#define SLAVE_MISC_CFG 594
+#define SLAVE_MISC_XPU_CFG 595
+#define SLAVE_VENUS_CFG 596
+#define SLAVE_MISC_VENUS_CFG 597
+#define SLAVE_GRAPHICS_3D_CFG 598
+#define SLAVE_MMSS_CLK_CFG 599
+#define SLAVE_MMSS_CLK_XPU_CFG 600
+#define SLAVE_MNOC_MPU_CFG 601
+#define SLAVE_ONOC_MPU_CFG 602
+#define SLAVE_SERVICE_MNOC 603
+#define SLAVE_OCMEM 604
+#define SLAVE_SERVICE_ONOC 605
+#define SLAVE_SDCC_1 606
+#define SLAVE_SDCC_3 607
+#define SLAVE_SDCC_2 608
+#define SLAVE_SDCC_4 609
+#define SLAVE_BAM_DMA 610
+#define SLAVE_BLSP_2 611
+#define SLAVE_USB_HSIC 612
+#define SLAVE_BLSP_1 613
+#define SLAVE_USB_HS 614
+#define SLAVE_PDM 615
+#define SLAVE_PERIPH_APU_CFG 616
+#define SLAVE_PNOC_MPU_CFG 617
+#define SLAVE_PRNG 618
+#define SLAVE_SERVICE_PNOC 619
+#define SLAVE_CLK_CTL 620
+#define SLAVE_CNOC_MSS 621
+#define SLAVE_SECURITY 622
+#define SLAVE_TCSR 623
+#define SLAVE_TLMM 624
+#define SLAVE_CRYPTO_0_CFG 625
+#define SLAVE_CRYPTO_1_CFG 626
+#define SLAVE_IMEM_CFG 627
+#define SLAVE_MESSAGE_RAM 628
+#define SLAVE_BIMC_CFG 629
+#define SLAVE_BOOT_ROM 630
+#define SLAVE_CNOC_MNOC_MMSS_CFG 631
+#define SLAVE_PMIC_ARB 632
+#define SLAVE_SPDM_WRAPPER 633
+#define SLAVE_DEHR_CFG 634
+#define SLAVE_QDSS_CFG 635
+#define SLAVE_RBCPR_CFG 636
+#define SLAVE_RBCPR_QDSS_APU_CFG 637
+#define SLAVE_SNOC_MPU_CFG 638
+#define SLAVE_CNOC_ONOC_CFG 639
+#define SLAVE_CNOC_MNOC_CFG 640
+#define SLAVE_PNOC_CFG 641
+#define SLAVE_SNOC_CFG 642
+#define SLAVE_EBI1_DLL_CFG 643
+#define SLAVE_PHY_APU_CFG 644
+#define SLAVE_EBI1_PHY_CFG 645
+#define SLAVE_SERVICE_CNOC 646
+#define SLAVE_IPS_CFG 647
+#define SLAVE_QPIC 648
+#define SLAVE_DSI_CFG 649
+#define SLAVE_UFS_CFG 650
+#define SLAVE_RBCPR_CX_CFG 651
+#define SLAVE_RBCPR_MX_CFG 652
+#define SLAVE_PCIE_CFG 653
+#define SLAVE_USB_PHYS_CFG 654
+#define SLAVE_VIDEO_CAP_CFG 655
+#define SLAVE_AVSYNC_CFG 656
+#define SLAVE_CRYPTO_2_CFG 657
+#define SLAVE_VPU_CFG 658
+#define SLAVE_BCAST_CFG 659
+#define SLAVE_KLM_CFG 660
+#define SLAVE_GENI_IR_CFG 661
+#define SLAVE_OCMEM_GFX 662
+#define SLAVE_CATS_128 663
+#define SLAVE_OCMEM_64 664
+#define SLAVE_PCIE_0 665
+#define SLAVE_PCIE_1 666
+#define SLAVE_PCIE_0_CFG 667
+#define SLAVE_PCIE_1_CFG 668
+#define SLAVE_SRVC_MNOC 669
+#define SLAVE_USB_HS2 670
+#define SLAVE_AUDIO 671
+#define SLAVE_TCU 672
+#define SLAVE_APPSS 673
+#define SLAVE_PCIE_PARF 674
+#define SLAVE_USB3_PHY_CFG 675
+#define SLAVE_IPA_CFG 676
+#define SLAVE_A0NOC_SNOC 677
+#define SLAVE_A1NOC_SNOC 678
+#define SLAVE_A2NOC_SNOC 679
+#define SLAVE_HMSS_L3 680
+#define SLAVE_PIMEM_CFG 681
+#define SLAVE_DCC_CFG 682
+#define SLAVE_QDSS_RBCPR_APU_CFG 683
+#define SLAVE_PCIE_2_CFG 684
+#define SLAVE_PCIE20_AHB2PHY 685
+#define SLAVE_A0NOC_CFG 686
+#define SLAVE_A1NOC_CFG 687
+#define SLAVE_A2NOC_CFG 688
+#define SLAVE_A1NOC_MPU_CFG 689
+#define SLAVE_A2NOC_MPU_CFG 690
+#define SLAVE_A0NOC_SMMU_CFG 691
+#define SLAVE_A1NOC_SMMU_CFG 692
+#define SLAVE_A2NOC_SMMU_CFG 693
+#define SLAVE_LPASS_SMMU_CFG 694
+#define SLAVE_MMAGIC_CFG 695
+#define SLAVE_VENUS_THROTTLE_CFG 696
+#define SLAVE_SSC_CFG 697
+#define SLAVE_DSA_CFG 698
+#define SLAVE_DSA_MPU_CFG 699
+#define SLAVE_DISPLAY_THROTTLE_CFG 700
+#define SLAVE_SMMU_CPP_CFG 701
+#define SLAVE_SMMU_JPEG_CFG 702
+#define SLAVE_SMMU_MDP_CFG 703
+#define SLAVE_SMMU_ROTATOR_CFG 704
+#define SLAVE_SMMU_VENUS_CFG 705
+#define SLAVE_SMMU_VFE_CFG 706
+#define SLAVE_A0NOC_MPU_CFG 707
+#define SLAVE_VMEM_CFG 708
+#define SLAVE_CAMERA_THROTTLE_CFG 709
+#define SLAVE_VMEM 710
+#define SLAVE_AHB2PHY 711
+#define SLAVE_PIMEM 712
+#define SLAVE_SNOC_VMEM 713
+#define SLAVE_PCIE_2 714
+#define SLAVE_RBCPR_MX 715
+#define SLAVE_RBCPR_CX 716
+#define SLAVE_BIMC_PCNOC 717
+#define SLAVE_PCNOC_BIMC_1 718
+#define SLAVE_SGMII 719
+#define SLAVE_SPMI_FETCHER 720
+#define PNOC_SLV_6 721
+#define SLAVE_MMSS_SMMU_CFG 722
+#define SLAVE_WLAN 723
+#define SLAVE_CRVIRT_A2NOC 724
+#define SLAVE_CNOC_A2NOC 725
+#define SLAVE_GLM 726
+#define SLAVE_GNOC_BIMC 727
+#define SLAVE_GNOC_SNOC 728
+#define SLAVE_QM_CFG 729
+#define SLAVE_TLMM_EAST 730
+#define SLAVE_TLMM_NORTH 731
+#define SLAVE_TLMM_WEST 732
+#define SLAVE_SKL 733
+
+#endif
diff --git a/include/dt-bindings/regulator/qcom,rpmh-regulator.h b/include/dt-bindings/regulator/qcom,rpmh-regulator.h
new file mode 100644
index 000000000000..86713dcf9e02
--- /dev/null
+++ b/include/dt-bindings/regulator/qcom,rpmh-regulator.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved. */
+
+#ifndef __QCOM_RPMH_REGULATOR_H
+#define __QCOM_RPMH_REGULATOR_H
+
+/*
+ * These mode constants may be used to specify modes for various RPMh regulator
+ * device tree properties (e.g. regulator-initial-mode). Each type of regulator
+ * supports a subset of the possible modes.
+ *
+ * %RPMH_REGULATOR_MODE_RET: Retention mode in which only an extremely small
+ * load current is allowed. This mode is supported
+ * by LDO and SMPS type regulators.
+ * %RPMH_REGULATOR_MODE_LPM: Low power mode in which a small load current is
+ * allowed. This mode corresponds to PFM for SMPS
+ * and BOB type regulators. This mode is supported
+ * by LDO, HFSMPS, BOB, and PMIC4 FTSMPS type
+ * regulators.
+ * %RPMH_REGULATOR_MODE_AUTO: Auto mode in which the regulator hardware
+ * automatically switches between LPM and HPM based
+ * upon the real-time load current. This mode is
+ * supported by HFSMPS, BOB, and PMIC4 FTSMPS type
+ * regulators.
+ * %RPMH_REGULATOR_MODE_HPM: High power mode in which the full rated current
+ * of the regulator is allowed. This mode
+ * corresponds to PWM for SMPS and BOB type
+ * regulators. This mode is supported by all types
+ * of regulators.
+ */
+#define RPMH_REGULATOR_MODE_RET 0
+#define RPMH_REGULATOR_MODE_LPM 1
+#define RPMH_REGULATOR_MODE_AUTO 2
+#define RPMH_REGULATOR_MODE_HPM 3
+
+#endif
diff --git a/include/dt-bindings/reset/qcom,sdm845-aoss.h b/include/dt-bindings/reset/qcom,sdm845-aoss.h
new file mode 100644
index 000000000000..476c5fc873b6
--- /dev/null
+++ b/include/dt-bindings/reset/qcom,sdm845-aoss.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 The Linux Foundation. All rights reserved.
+ */
+
+#ifndef _DT_BINDINGS_RESET_AOSS_SDM_845_H
+#define _DT_BINDINGS_RESET_AOSS_SDM_845_H
+
+#define AOSS_CC_MSS_RESTART 0
+#define AOSS_CC_CAMSS_RESTART 1
+#define AOSS_CC_VENUS_RESTART 2
+#define AOSS_CC_GPU_RESTART 3
+#define AOSS_CC_DISPSS_RESTART 4
+#define AOSS_CC_WCSS_RESTART 5
+#define AOSS_CC_LPASS_RESTART 6
+
+#endif
diff --git a/include/dt-bindings/soc/qcom,rpmh-rsc.h b/include/dt-bindings/soc/qcom,rpmh-rsc.h
new file mode 100644
index 000000000000..868f998ea998
--- /dev/null
+++ b/include/dt-bindings/soc/qcom,rpmh-rsc.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __DT_QCOM_RPMH_RSC_H__
+#define __DT_QCOM_RPMH_RSC_H__
+
+#define SLEEP_TCS 0
+#define WAKE_TCS 1
+#define ACTIVE_TCS 2
+#define CONTROL_TCS 3
+
+#endif /* __DT_QCOM_RPMH_RSC_H__ */
diff --git a/include/linux/device.h b/include/linux/device.h
index 055a69dbcd18..b24c5f804b8d 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -787,11 +787,13 @@ enum device_link_state {
* AUTOREMOVE: Remove this link automatically on consumer driver unbind.
* PM_RUNTIME: If set, the runtime PM framework will use this link.
* RPM_ACTIVE: Run pm_runtime_get_sync() on the supplier during link creation.
+ * AUTOREMOVE_S: Remove this link automatically on supplier driver unbind.
*/
#define DL_FLAG_STATELESS BIT(0)
#define DL_FLAG_AUTOREMOVE BIT(1)
#define DL_FLAG_PM_RUNTIME BIT(2)
#define DL_FLAG_RPM_ACTIVE BIT(3)
+#define DL_FLAG_AUTOREMOVE_S BIT(4)
/**
* struct device_link - Device link representation.
diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h
new file mode 100644
index 000000000000..c78aa930bcab
--- /dev/null
+++ b/include/linux/interconnect-provider.h
@@ -0,0 +1,130 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef _LINUX_INTERCONNECT_PROVIDER_H
+#define _LINUX_INTERCONNECT_PROVIDER_H
+
+#include <linux/interconnect.h>
+
+#define icc_units_to_bps(bw) ((bw) * 1000ULL)
+
+struct icc_node;
+
+/**
+ * struct icc_provider - interconnect provider (controller) entity that might
+ * provide multiple interconnect controls
+ *
+ * @provider_list: list of the registered interconnect providers
+ * @nodes: internal list of the interconnect provider nodes
+ * @set: pointer to device specific set operation function
+ * @aggregate: pointer to device specific aggregate operation function
+ * @dev: the device this interconnect provider belongs to
+ * @users: count of active users
+ * @avg_bw: aggregated value of average bandwidth requests from all nodes
+ * @peak_bw: aggregated value of peak bandwidth requests from all nodes
+ * @data: pointer to private data
+ */
+struct icc_provider {
+ struct list_head provider_list;
+ struct list_head nodes;
+ int (*set)(struct icc_node *src, struct icc_node *dst,
+ u32 avg_bw, u32 peak_bw);
+ int (*aggregate)(struct icc_node *node, u32 avg_bw, u32 peak_bw,
+ u32 *agg_avg, u32 *agg_peak);
+ struct device *dev;
+ int users;
+ u32 avg_bw;
+ u32 peak_bw;
+ void *data;
+};
+
+/**
+ * struct icc_node - entity that is part of the interconnect topology
+ *
+ * @id: platform specific node id
+ * @name: node name used in debugfs
+ * @links: a list of targets pointing to where we can go next when traversing
+ * @num_links: number of links to other interconnect nodes
+ * @provider: points to the interconnect provider of this node
+ * @node_list: the list entry in the parent provider's "nodes" list
+ * @search_list: list used when walking the nodes graph
+ * @reverse: pointer to previous node when walking the nodes graph
+ * @is_traversed: flag that is used when walking the nodes graph
+ * @req_list: a list of QoS constraint requests associated with this node
+ * @avg_bw: aggregated value of average bandwidth requests from all consumers
+ * @peak_bw: aggregated value of peak bandwidth requests from all consumers
+ * @data: pointer to private data
+ */
+struct icc_node {
+ int id;
+ const char *name;
+ struct icc_node **links;
+ size_t num_links;
+
+ struct icc_provider *provider;
+ struct list_head node_list;
+ struct list_head search_list;
+ struct icc_node *reverse;
+ bool is_traversed;
+ struct hlist_head req_list;
+ u32 avg_bw;
+ u32 peak_bw;
+ void *data;
+};
+
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+
+struct icc_node *icc_node_create(int id);
+void icc_node_destroy(int id);
+int icc_link_create(struct icc_node *node, const int dst_id);
+int icc_link_destroy(struct icc_node *src, struct icc_node *dst);
+void icc_node_add(struct icc_node *node, struct icc_provider *provider);
+void icc_node_del(struct icc_node *node);
+int icc_provider_add(struct icc_provider *provider);
+int icc_provider_del(struct icc_provider *provider);
+
+#else
+
+static inline struct icc_node *icc_node_create(int id)
+{
+ return ERR_PTR(-ENOTSUPP);
+}
+
+void icc_node_destroy(int id)
+{
+}
+
+static inline int icc_link_create(struct icc_node *node, const int dst_id)
+{
+ return -ENOTSUPP;
+}
+
+int icc_link_destroy(struct icc_node *src, struct icc_node *dst)
+{
+ return -ENOTSUPP;
+}
+
+void icc_node_add(struct icc_node *node, struct icc_provider *provider)
+{
+}
+
+void icc_node_del(struct icc_node *node)
+{
+}
+
+static inline int icc_provider_add(struct icc_provider *provider)
+{
+ return -ENOTSUPP;
+}
+
+static inline int icc_provider_del(struct icc_provider *provider)
+{
+ return -ENOTSUPP;
+}
+
+#endif /* CONFIG_INTERCONNECT */
+
+#endif /* _LINUX_INTERCONNECT_PROVIDER_H */
diff --git a/include/linux/interconnect.h b/include/linux/interconnect.h
new file mode 100644
index 000000000000..ae6744da9bc2
--- /dev/null
+++ b/include/linux/interconnect.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2018, Linaro Ltd.
+ * Author: Georgi Djakov <georgi.djakov@linaro.org>
+ */
+
+#ifndef _LINUX_INTERCONNECT_H
+#define _LINUX_INTERCONNECT_H
+
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+struct icc_path;
+struct device;
+
+#if IS_ENABLED(CONFIG_INTERCONNECT)
+
+struct icc_path *icc_get(struct device *dev, const int src_id,
+ const int dst_id);
+struct icc_path *of_icc_get(struct device *dev, const char *name);
+void icc_put(struct icc_path *path);
+int icc_set(struct icc_path *path, u32 avg_bw, u32 peak_bw);
+
+#else
+
+static inline struct icc_path *icc_get(struct device *dev, const int src_id,
+ const int dst_id)
+{
+ return NULL;
+}
+
+static inline struct icc_path *of_icc_get(struct device *dev,
+ const char *name)
+{
+ return NULL;
+}
+
+static inline void icc_put(struct icc_path *path)
+{
+}
+
+static inline int icc_set(struct icc_path *path, u32 avg_bw, u32 peak_bw)
+{
+ return 0;
+}
+
+#endif /* CONFIG_INTERCONNECT */
+
+#endif /* _LINUX_INTERCONNECT_H */
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 099b31960dec..41ae6465cad7 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -25,6 +25,7 @@ struct opp_table;
enum dev_pm_opp_event {
OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
+ OPP_EVENT_ADJUST_VOLTAGE,
};
/**
@@ -84,6 +85,7 @@ void dev_pm_opp_put_opp_table(struct opp_table *opp_table);
unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);
+struct regulator *dev_pm_opp_get_regulator(struct device *dev);
bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp);
@@ -108,6 +110,9 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq,
unsigned long u_volt);
void dev_pm_opp_remove(struct device *dev, unsigned long freq);
+int dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
+ unsigned long u_volt);
+
int dev_pm_opp_enable(struct device *dev, unsigned long freq);
int dev_pm_opp_disable(struct device *dev, unsigned long freq);
@@ -208,6 +213,13 @@ static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq)
{
}
+static inline int
+dev_pm_opp_adjust_voltage(struct device *dev, unsigned long freq,
+ unsigned long u_volt)
+{
+ return 0;
+}
+
static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq)
{
return 0;
diff --git a/include/linux/regulator/qcom_smd-regulator.h b/include/linux/regulator/qcom_smd-regulator.h
new file mode 100644
index 000000000000..16029448d6b6
--- /dev/null
+++ b/include/linux/regulator/qcom_smd-regulator.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __QCOM_SMD_REGULATOR_H_
+#define __QCOM_SMD_REGULATOR_H_
+
+#if IS_ENABLED(CONFIG_REGULATOR_QCOM_SMD_RPM)
+int qcom_rpm_set_floor(struct regulator *regulator, int floor);
+int qcom_rpm_set_corner(struct regulator *regulator, int corner);
+#else
+static inline int qcom_rpm_set_floor(struct regulator *regulator, int floor)
+{
+ return -EINVAL;
+}
+
+static inline int qcom_rpm_set_corner(struct regulator *regulator, int corner)
+{
+ return -EINVAL;
+}
+#endif
+
+#endif
diff --git a/include/linux/slimbus.h b/include/linux/slimbus.h
index c36cf121d2cd..419a9a983bc4 100644
--- a/include/linux/slimbus.h
+++ b/include/linux/slimbus.h
@@ -14,16 +14,16 @@ extern struct bus_type slimbus_bus;
/**
* struct slim_eaddr - Enumeration address for a SLIMbus device
- * @manf_id: Manufacturer Id for the device
- * @prod_code: Product code
- * @dev_index: Device index
* @instance: Instance value
+ * @dev_index: Device index
+ * @prod_code: Product code
+ * @manf_id: Manufacturer Id for the device
*/
struct slim_eaddr {
- u16 manf_id;
- u16 prod_code;
- u8 dev_index;
u8 instance;
+ u8 dev_index;
+ u16 prod_code;
+ u16 manf_id;
} __packed;
/**
@@ -108,6 +108,53 @@ struct slim_val_inf {
struct completion *comp;
};
+enum slim_stream_direction {
+ SLIM_STREAM_PLAYBACK = 0,
+ SLIM_STREAM_CAPTURE,
+};
+
+//FIXME ONLY ISO supported
+enum slim_channel_proto {
+ SLIM_HARD_ISO = 0,
+ SLIM_AUTO_ISO,
+ SLIM_PUSH,
+ SLIM_PULL,
+ SLIM_ASYNC_SMPLX,
+ SLIM_ASYNC_HALF_DUP,
+ SLIM_EXT_SMPLX,
+ SLIM_EXT_HALF_DUP,
+};
+
+/*
+ * 1:1 map between port and channel
+ *
+ * only ISO protocol is supported.
+ *
+ */
+struct slim_stream_config {
+ unsigned int rate;
+ unsigned int bps;
+
+ /* MAX 256 channels */
+ unsigned int ch_count;
+ unsigned int *chs;
+ /* Max 32 ports per device */
+ unsigned long port_mask;
+
+ enum slim_stream_direction direction;
+ enum slim_channel_proto prot;
+};
+
+struct slim_stream_runtime;
+
+struct slim_stream_runtime *slim_stream_allocate(struct slim_device *dev,
+ struct slim_stream_config *c);
+int slim_stream_prepare(struct slim_stream_runtime *stream);
+int slim_stream_enable(struct slim_stream_runtime *stream);
+int slim_stream_disable(struct slim_stream_runtime *stream);
+int slim_stream_unprepare(struct slim_stream_runtime *stream);
+int slim_stream_free(struct slim_stream_runtime *stream);
+
/*
* use a macro to avoid include chaining to get THIS_MODULE
*/
@@ -138,6 +185,8 @@ static inline void slim_set_devicedata(struct slim_device *dev, void *data)
dev_set_drvdata(&dev->dev, data);
}
+struct slim_device *of_slim_get_device(struct slim_controller *ctrl,
+ struct device_node *np);
struct slim_device *slim_get_device(struct slim_controller *ctrl,
struct slim_eaddr *e_addr);
int slim_get_logical_addr(struct slim_device *sbdev);
diff --git a/include/soc/qcom/kryo-l2-accessors.h b/include/soc/qcom/kryo-l2-accessors.h
new file mode 100644
index 000000000000..e9a5eab80418
--- /dev/null
+++ b/include/soc/qcom/kryo-l2-accessors.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * This 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 __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H
+#define __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H
+
+#ifdef CONFIG_ARCH_QCOM
+void set_l2_indirect_reg(u64 reg_addr, u64 val);
+u64 get_l2_indirect_reg(u64 reg_addr);
+#endif
+
+#endif
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
new file mode 100644
index 000000000000..619e07c75da9
--- /dev/null
+++ b/include/soc/qcom/rpmh.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SOC_QCOM_RPMH_H__
+#define __SOC_QCOM_RPMH_H__
+
+#include <soc/qcom/tcs.h>
+#include <linux/platform_device.h>
+
+
+#if IS_ENABLED(CONFIG_QCOM_RPMH)
+int rpmh_write(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n);
+
+int rpmh_write_async(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n);
+
+int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 *n);
+
+int rpmh_flush(const struct device *dev);
+
+int rpmh_invalidate(const struct device *dev);
+
+#else
+
+static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{ return -ENODEV; }
+
+static inline int rpmh_write_async(const struct device *dev,
+ enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{ return -ENODEV; }
+
+static inline int rpmh_write_batch(const struct device *dev,
+ enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 *n)
+{ return -ENODEV; }
+
+static inline int rpmh_flush(const struct device *dev)
+{ return -ENODEV; }
+
+static inline int rpmh_invalidate(const struct device *dev)
+{ return -ENODEV; }
+
+#endif /* CONFIG_QCOM_RPMH */
+
+#endif /* __SOC_QCOM_RPMH_H__ */
diff --git a/include/soc/qcom/tcs.h b/include/soc/qcom/tcs.h
new file mode 100644
index 000000000000..262876a59e86
--- /dev/null
+++ b/include/soc/qcom/tcs.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SOC_QCOM_TCS_H__
+#define __SOC_QCOM_TCS_H__
+
+#define MAX_RPMH_PAYLOAD 16
+
+/**
+ * rpmh_state: state for the request
+ *
+ * RPMH_SLEEP_STATE: State of the resource when the processor subsystem
+ * is powered down. There is no client using the
+ * resource actively.
+ * RPMH_WAKE_ONLY_STATE: Resume resource state to the value previously
+ * requested before the processor was powered down.
+ * RPMH_ACTIVE_ONLY_STATE: Active or AMC mode requests. Resource state
+ * is aggregated immediately.
+ */
+enum rpmh_state {
+ RPMH_SLEEP_STATE,
+ RPMH_WAKE_ONLY_STATE,
+ RPMH_ACTIVE_ONLY_STATE,
+};
+
+/**
+ * struct tcs_cmd: an individual request to RPMH.
+ *
+ * @addr: the address of the resource slv_id:18:16 | offset:0:15
+ * @data: the resource state request
+ * @wait: wait for this request to be complete before sending the next
+ */
+struct tcs_cmd {
+ u32 addr;
+ u32 data;
+ u32 wait;
+};
+
+/**
+ * struct tcs_request: A set of tcs_cmds sent together in a TCS
+ *
+ * @state: state for the request.
+ * @wait_for_compl: wait until we get a response from the h/w accelerator
+ * @num_cmds: the number of @cmds in this request
+ * @cmds: an array of tcs_cmds
+ */
+struct tcs_request {
+ enum rpmh_state state;
+ u32 wait_for_compl;
+ u32 num_cmds;
+ struct tcs_cmd *cmds;
+};
+
+#endif /* __SOC_QCOM_TCS_H__ */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index e6f8c40ed43c..4af71eb0f847 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -141,6 +141,11 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
int direction);
+
+int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot);
+
int snd_soc_dai_is_dummy(struct snd_soc_dai *dai);
struct snd_soc_dai_ops {
@@ -169,6 +174,10 @@ struct snd_soc_dai_ops {
unsigned int tx_num, unsigned int *tx_slot,
unsigned int rx_num, unsigned int *rx_slot);
int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
+ int (*get_channel_map)(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot);
+
int (*set_sdw_stream)(struct snd_soc_dai *dai,
void *stream, int direction);
diff --git a/kernel/configs/debug.config b/kernel/configs/debug.config
new file mode 100644
index 000000000000..451a71bb6bda
--- /dev/null
+++ b/kernel/configs/debug.config
@@ -0,0 +1,13 @@
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_DEBUG_PAGEALLOC=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_SLUB_DEBUG_ON=y
+CONFIG_KASAN=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
diff --git a/kernel/configs/distro.config b/kernel/configs/distro.config
new file mode 100644
index 000000000000..d128b17d25bf
--- /dev/null
+++ b/kernel/configs/distro.config
@@ -0,0 +1,456 @@
+# USB camera
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_M5602=m
+CONFIG_USB_STV06XX=m
+CONFIG_USB_GL860=m
+CONFIG_USB_GSPCA_BENQ=m
+CONFIG_USB_GSPCA_CONEX=m
+CONFIG_USB_GSPCA_CPIA1=m
+CONFIG_USB_GSPCA_DTCS033=m
+CONFIG_USB_GSPCA_ETOMS=m
+CONFIG_USB_GSPCA_FINEPIX=m
+CONFIG_USB_GSPCA_JEILINJ=m
+CONFIG_USB_GSPCA_JL2005BCD=m
+CONFIG_USB_GSPCA_KINECT=m
+CONFIG_USB_GSPCA_KONICA=m
+CONFIG_USB_GSPCA_MARS=m
+CONFIG_USB_GSPCA_MR97310A=m
+CONFIG_USB_GSPCA_NW80X=m
+CONFIG_USB_GSPCA_OV519=m
+CONFIG_USB_GSPCA_OV534=m
+CONFIG_USB_GSPCA_OV534_9=m
+CONFIG_USB_GSPCA_PAC207=m
+CONFIG_USB_GSPCA_PAC7302=m
+CONFIG_USB_GSPCA_PAC7311=m
+CONFIG_USB_GSPCA_SE401=m
+CONFIG_USB_GSPCA_SN9C2028=m
+CONFIG_USB_GSPCA_SN9C20X=m
+CONFIG_USB_GSPCA_SONIXB=m
+CONFIG_USB_GSPCA_SONIXJ=m
+CONFIG_USB_GSPCA_SPCA500=m
+CONFIG_USB_GSPCA_SPCA501=m
+CONFIG_USB_GSPCA_SPCA505=m
+CONFIG_USB_GSPCA_SPCA506=m
+CONFIG_USB_GSPCA_SPCA508=m
+CONFIG_USB_GSPCA_SPCA561=m
+CONFIG_USB_GSPCA_SPCA1528=m
+CONFIG_USB_GSPCA_SQ905=m
+CONFIG_USB_GSPCA_SQ905C=m
+CONFIG_USB_GSPCA_SQ930X=m
+CONFIG_USB_GSPCA_STK014=m
+CONFIG_USB_GSPCA_STK1135=m
+CONFIG_USB_GSPCA_STV0680=m
+CONFIG_USB_GSPCA_SUNPLUS=m
+CONFIG_USB_GSPCA_T613=m
+CONFIG_USB_GSPCA_TOPRO=m
+CONFIG_USB_GSPCA_TOUPTEK=m
+CONFIG_USB_GSPCA_TV8532=m
+CONFIG_USB_GSPCA_VC032X=m
+CONFIG_USB_GSPCA_VICAM=m
+CONFIG_USB_GSPCA_XIRLINK_CIT=m
+CONFIG_USB_GSPCA_ZC3XX=m
+CONFIG_USB_LAN78XX=m
+CONFIG_USB_PWC=m
+CONFIG_USB_ZR364XX=m
+CONFIG_USB_STKWEBCAM=m
+CONFIG_USB_S2255=m
+
+# USB serial
+CONFIG_USB_SERIAL=y
+CONFIG_USB_SERIAL_CONSOLE=y
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_SIMPLE=m
+CONFIG_USB_SERIAL_AIRCABLE=m
+CONFIG_USB_SERIAL_ARK3116=m
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_CH341=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_CP210X=m
+CONFIG_USB_SERIAL_CYPRESS_M8=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_F81232=m
+CONFIG_USB_SERIAL_GARMIN=m
+CONFIG_USB_SERIAL_IPW=m
+CONFIG_USB_SERIAL_IUU=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_METRO=m
+CONFIG_USB_SERIAL_MOS7720=m
+CONFIG_USB_SERIAL_MOS7840=m
+CONFIG_USB_SERIAL_MXUPORT=m
+CONFIG_USB_SERIAL_NAVMAN=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_OTI6858=m
+CONFIG_USB_SERIAL_QCAUX=m
+CONFIG_USB_SERIAL_QUALCOMM=m
+CONFIG_USB_SERIAL_SPCP8X5=m
+CONFIG_USB_SERIAL_SAFE=m
+CONFIG_USB_SERIAL_SIERRAWIRELESS=m
+CONFIG_USB_SERIAL_SYMBOL=m
+CONFIG_USB_SERIAL_TI=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OPTION=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_SERIAL_OPTICON=m
+CONFIG_USB_SERIAL_XSENS_MT=m
+CONFIG_USB_SERIAL_WISHBONE=m
+CONFIG_USB_SERIAL_SSU100=m
+CONFIG_USB_SERIAL_QT2=m
+
+# USB gadget
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=m
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+CONFIG_NEW_LEDS=y
+
+# USB Eth
+CONFIG_USB_USBNET=y
+CONFIG_USB_NET_AX88179_178A=y
+CONFIG_USB_NET_AX8817X=y
+CONFIG_USB_CATC=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=y
+CONFIG_USB_RTL8152=y
+CONFIG_USB_NET_SR9700=m
+CONFIG_USB_NET_SR9800=m
+CONFIG_USB_NET_SMSC75XX=m
+CONFIG_USB_NET_SMSC95XX=m
+CONFIG_USB_NET_MCS7830=m
+
+# USB device class
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+CONFIG_USB_WDM=m
+
+# LEDs
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_CPU=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_DISK=y
+CONFIG_LEDS_TRIGGER_MTD=y
+CONFIG_LEDS_TRIGGER_TRANSIENT=y
+CONFIG_LEDS_TRIGGER_PANIC=y
+CONFIG_MAC80211_LEDS=y
+
+# systemd
+CONFIG_IPV6=y
+CONFIG_NAMESPACES=y
+CONFIG_NET_NS=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_DEVTMPFS=y
+CONFIG_CGROUPS=y
+CONFIG_INOTIFY_USER=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EPOLL=y
+CONFIG_NET=y
+CONFIG_SYSFS=y
+CONFIG_PROC_FS=y
+CONFIG_FHANDLE=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_DNS_RESOLVER=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_SCHEDSTATS=y
+CONFIG_SCHED_DEBUG=y
+
+# NFS server
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+
+# HID
+CONFIG_HID_APPLE=y
+CONFIG_HID_LOGITECH=m
+CONFIG_HID_MAGICMOUSE=m
+CONFIG_HID_MICROSOFT=m
+CONFIG_HID_PLANTRONICS=m
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_HID_MULTITOUCH=m
+
+#misc
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_STAT=y
+CONFIG_PRINTK_TIME=y
+CONFIG_STACKTRACE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_GPIO_SYSFS=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=y
+CONFIG_RFKILL=y
+CONFIG_BINFMT_MISC=m
+CONFIG_DYNAMIC_DEBUG=y
+CONFIG_DRM_LOAD_EDID_FIRMWARE=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI_SPIDEV=m
+CONFIG_ZSMALLOC=m
+CONFIG_ZRAM=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BBR=m
+
+# PPP
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+
+# input
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_PM8941_PWRKEY=y
+CONFIG_INPUT_JOYDEV=m
+
+# Docker
+CONFIG_IPV6=y
+CONFIG_NET_NS=y
+CONFIG_IPC_NS=y
+CONFIG_UTS_NS=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_VETH=m
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_NETFILTER_SYNPROXY=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_NETFILTER=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_MATCH_CGROUP=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NF_TABLES=m
+CONFIG_NF_TABLES_INET=m
+CONFIG_NF_TABLES_NETDEV=m
+CONFIG_NF_TABLES_IPV4=m
+CONFIG_NF_TABLES_ARP=m
+CONFIG_NF_TABLES_IPV6=m
+CONFIG_NF_TABLES_BRIDGE=m
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_IPV4=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CONNTRACK_TIMEOUT=y
+CONFIG_NF_CONNTRACK_TIMESTAMP=y
+CONFIG_NF_CONNTRACK_LABELS=y
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_SNMP=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_USER_NS=y
+CONFIG_SECCOMP=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CGROUP_NET_PRIO=y
+CONFIG_CGROUP_PERF=y
+CONFIG_CFQ_GROUP_IOSCHED=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_CLS_CGROUP=m
+CONFIG_NET_SCH_FQ_CODEL=m
+CONFIG_NET_SCH_FQ=m
+CONFIG_CFS_BANDWIDTH=y
+CONFIG_IP_VS=m
+CONFIG_VXLAN=m
+CONFIG_XFRM_ALGO=m
+CONFIG_XFRM_USER=m
+CONFIG_IPVLAN=m
+CONFIG_MACVLAN=m
+CONFIG_DUMMY=m
+CONFIG_BTRFS_FS=m
+CONFIG_OVERLAY_FS=m
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_POSIX_MQUEUE=y
+
+# Extended IPV6 support
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_MIP6=m
+CONFIG_IPV6_ILA=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_IPV6_VTI=m
+CONFIG_IPV6_SIT_6RD=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_GRE=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MROUTE=y
+CONFIG_IPV6_MROUTE_MULTIPLE_TABLES=y
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NF_NAT_MASQUERADE_IPV6=m
+CONFIG_NF_DUP_IPV6=m
+CONFIG_NF_REJECT_IPV6=m
+CONFIG_NF_LOG_IPV6=m
+CONFIG_NF_NAT_IPV6=m
+CONFIG_NFT_CHAIN_NAT_IPV6=m
+CONFIG_NFT_CHAIN_ROUTE_IPV4=m
+CONFIG_NFT_CHAIN_ROUTE_IPV6=m
+CONFIG_NFT_DUP_IPV6=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RPFILTER=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_TARGET_SYNPROXY=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+CONFIG_IP6_NF_NAT=m
+CONFIG_IP6_NF_TARGET_MASQUERADE=m
+CONFIG_IP6_NF_TARGET_NPT=m
+
+# 6LOWPAN
+CONFIG_6LOWPAN=m
+CONFIG_6LOWPAN_NHC=m
+CONFIG_6LOWPAN_NHC_DEST=m
+CONFIG_6LOWPAN_NHC_FRAGMENT=m
+CONFIG_6LOWPAN_NHC_HOP=m
+CONFIG_6LOWPAN_NHC_IPV6=m
+CONFIG_6LOWPAN_NHC_MOBILITY=m
+CONFIG_6LOWPAN_NHC_ROUTING=m
+CONFIG_6LOWPAN_NHC_UDP=m
+CONFIG_IEEE802154=m
+CONFIG_IEEE802154_NL802154_EXPERIMENTAL=y
+CONFIG_IEEE802154_SOCKET=m
+CONFIG_IEEE802154_6LOWPAN=m
+CONFIG_IEEE802154_DRIVERS=m
+CONFIG_IEEE802154_FAKELB=m
+CONFIG_IEEE802154_AT86RF230=m
+CONFIG_IEEE802154_AT86RF230_DEBUGFS=y
+CONFIG_IEEE802154_MRF24J40=m
+CONFIG_IEEE802154_CC2520=m
+CONFIG_IEEE802154_ATUSB=m
+CONFIG_MAC802154=m
+
+# Extended BT support
+CONFIG_BT=m
+CONFIG_BT_BREDR=y
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_CMTP=m
+CONFIG_BT_HIDP=m
+CONFIG_BT_HS=y
+CONFIG_BT_LE=y
+CONFIG_BT_LEDS=y
+CONFIG_BT_DEBUGFS=y
+CONFIG_BT_HCIBTUSB=m
+CONFIG_BT_HCIBTSDIO=m
+CONFIG_BT_HCIUART=m
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+CONFIG_BT_HCIUART_3WIRE=y
+CONFIG_BT_6LOWPAN=m
+
+# Extended WLAN support
+CONFIG_CFG80211_WEXT=y
+
+# Legacy instruction support for arm64
+CONFIG_ARMV8_DEPRECATED=y
+CONFIG_SWP_EMULATION=y
+CONFIG_CP15_BARRIER_EMULATION=y
+CONFIG_SETEND_EMULATION=y
+
+# Enable DM_CRYPT
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_CRYPT=m
+CONFIG_RTC_DRV_PM8XXX=m
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 63cf62e9c9aa..ca59eeace9d9 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1053,6 +1053,13 @@ config SND_SOC_UDA1380
tristate
depends on I2C
+config SND_SOC_WCD9335
+ tristate "WCD9335 Codec"
+ select SLIMBUS
+ select REGMAP_SLIMBUS
+ select MFD_CORE
+ tristate
+
config SND_SOC_WL1273
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index e023fdf85221..07ccd7e972bc 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,4 +1,4 @@
-# SPDX-License-Identifier: GPL-2.0
+ SPDX-License-Identifier: GPL-2.0
snd-soc-88pm860x-objs := 88pm860x-codec.o
snd-soc-ab8500-codec-objs := ab8500-codec.o
snd-soc-ac97-objs := ac97.o
@@ -190,6 +190,7 @@ snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
+snd-soc-wcd9335-objs := wcd9335-slim.o wcd9335-regmap.o wcd-clsh.o wcd9335.o
snd-soc-wl1273-objs := wl1273.o
snd-soc-wm-adsp-objs := wm_adsp.o
snd-soc-wm0010-objs := wm0010.o
@@ -447,6 +448,8 @@ obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
+
+obj-$(CONFIG_SND_SOC_WCD9335) += snd-soc-wcd9335.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
diff --git a/sound/soc/codecs/wcd-clsh.c b/sound/soc/codecs/wcd-clsh.c
new file mode 100644
index 000000000000..8dd7a8082565
--- /dev/null
+++ b/sound/soc/codecs/wcd-clsh.c
@@ -0,0 +1,870 @@
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include "wcd9335.h"
+#include "wcd-clsh.h"
+
+/* Class-H registers for codecs from and above WCD9335 */
+#define WCD9XXX_A_CDC_RX0_RX_PATH_CFG0 (0xB42)
+#define WCD9XXX_A_CDC_RX1_RX_PATH_CFG0 (0xB56)
+#define WCD9XXX_A_CDC_RX2_RX_PATH_CFG0 (0xB6A)
+#define WCD9XXX_A_CDC_CLSH_K1_MSB (0xC08)
+#define WCD9XXX_A_CDC_CLSH_K1_LSB (0xC09)
+#define WCD9XXX_A_ANA_RX_SUPPLIES (0x608)
+#define WCD9XXX_A_ANA_HPH (0x609)
+#define WCD9XXX_A_CDC_CLSH_CRC (0xC01)
+#define WCD9XXX_FLYBACK_EN (0x6A4)
+#define WCD9XXX_RX_BIAS_FLYB_BUFF (0x6C7)
+#define WCD9XXX_HPH_L_EN (0x6D3)
+#define WCD9XXX_HPH_R_EN (0x6D6)
+#define WCD9XXX_HPH_REFBUFF_UHQA_CTL (0x6DD)
+#define WCD9XXX_CLASSH_CTRL_VCL_2 (0x69B)
+#define WCD9XXX_CDC_CLSH_HPH_V_PA (0xC04)
+#define WCD9XXX_CDC_RX0_RX_PATH_SEC0 (0xB49)
+#define WCD9XXX_CDC_RX1_RX_PATH_CTL (0xB55)
+#define WCD9XXX_CDC_RX2_RX_PATH_CTL (0xB69)
+#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL (0xD41)
+#define WCD9XXX_CLASSH_CTRL_CCL_1 (0x69C)
+
+#define WCD_USLEEP_RANGE 50
+
+enum {
+ DAC_GAIN_0DB = 0,
+ DAC_GAIN_0P2DB,
+ DAC_GAIN_0P4DB,
+ DAC_GAIN_0P6DB,
+ DAC_GAIN_0P8DB,
+ DAC_GAIN_M0P2DB,
+ DAC_GAIN_M0P4DB,
+ DAC_GAIN_M0P6DB,
+};
+
+enum {
+ VREF_FILT_R_0OHM = 0,
+ VREF_FILT_R_25KOHM,
+ VREF_FILT_R_50KOHM,
+ VREF_FILT_R_100KOHM,
+};
+
+enum {
+ DELTA_I_0MA,
+ DELTA_I_10MA,
+ DELTA_I_20MA,
+ DELTA_I_30MA,
+ DELTA_I_40MA,
+ DELTA_I_50MA,
+};
+
+static void (*clsh_state_fp[NUM_CLSH_STATES_V2])(struct snd_soc_component *,
+ struct wcd_clsh_cdc_data *,
+ u8 req_state, bool en, int mode);
+
+static bool is_native_44_1_active(struct snd_soc_component *component)
+{
+ bool native_active = false;
+ u8 native_clk, rx1_rate, rx2_rate;
+
+ native_clk = snd_soc_component_read32(component,
+ WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL);
+ rx1_rate = snd_soc_component_read32(component, WCD9XXX_CDC_RX1_RX_PATH_CTL);
+ rx2_rate = snd_soc_component_read32(component, WCD9XXX_CDC_RX2_RX_PATH_CTL);
+
+ if ((native_clk & 0x2) &&
+ ((rx1_rate & 0x0F) == 0x9 || (rx2_rate & 0x0F) == 0x9))
+ native_active = true;
+
+ return native_active;
+}
+
+static inline void wcd_enable_clsh_block(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d, bool enable)
+{
+ if ((enable && ++clsh_d->clsh_users == 1) ||
+ (!enable && --clsh_d->clsh_users == 0))
+ snd_soc_component_update_bits(component, WCD9XXX_A_CDC_CLSH_CRC, 0x01,
+ (u8) enable);
+ if (clsh_d->clsh_users < 0)
+ clsh_d->clsh_users = 0;
+}
+
+static inline bool wcd_clsh_enable_status(struct snd_soc_component *component)
+{
+ return snd_soc_component_read32(component, WCD9XXX_A_CDC_CLSH_CRC) & 0x01;
+}
+
+static inline int wcd_clsh_get_int_mode(struct wcd_clsh_cdc_data *clsh_d,
+ int clsh_state)
+{
+ int mode;
+
+ if ((clsh_state != WCD_CLSH_STATE_EAR) &&
+ (clsh_state != WCD_CLSH_STATE_HPHL) &&
+ (clsh_state != WCD_CLSH_STATE_HPHR) &&
+ (clsh_state != WCD_CLSH_STATE_LO))
+ mode = CLS_NONE;
+ else
+ mode = clsh_d->interpolator_modes[ffs(clsh_state)];
+
+ return mode;
+}
+
+static inline void wcd_clsh_set_int_mode(struct wcd_clsh_cdc_data *clsh_d,
+ int clsh_state, int mode)
+{
+ if ((clsh_state != WCD_CLSH_STATE_EAR) &&
+ (clsh_state != WCD_CLSH_STATE_HPHL) &&
+ (clsh_state != WCD_CLSH_STATE_HPHR) &&
+ (clsh_state != WCD_CLSH_STATE_LO))
+ return;
+
+ clsh_d->interpolator_modes[ffs(clsh_state)] = mode;
+}
+
+static inline void wcd_clsh_set_buck_mode(struct snd_soc_component *component,
+ int mode)
+{
+ if (mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES,
+ 0x08, 0x08); /* set to HIFI */
+ else
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES,
+ 0x08, 0x00); /* set to default */
+}
+
+static inline void wcd_clsh_set_flyback_mode(struct snd_soc_component *component,
+ int mode)
+{
+ if (mode == CLS_H_HIFI)
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES,
+ 0x04, 0x04); /* set to HIFI */
+ else
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES,
+ 0x04, 0x00); /* set to Default */
+}
+
+static void wcd_clsh_buck_ctrl(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ int mode,
+ bool enable)
+{
+ /* enable/disable buck */
+ if ((enable && (++clsh_d->buck_users == 1)) ||
+ (!enable && (--clsh_d->buck_users == 0)))
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES,
+ (1 << 7), (enable << 7));
+ /*
+ * 500us sleep is required after buck enable/disable
+ * as per HW requirement
+ */
+ usleep_range(500, 500 + WCD_USLEEP_RANGE);
+}
+
+static void wcd_clsh_flyback_ctrl(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ int mode,
+ bool enable)
+{
+ u8 vneg[] = {0x00, 0x40};
+
+ /* enable/disable flyback */
+ if ((enable && (++clsh_d->flyback_users == 1)) ||
+ (!enable && (--clsh_d->flyback_users == 0))) {
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES,
+ (1 << 6), (enable << 6));
+ /* 100usec delay is needed as per HW requirement */
+ usleep_range(100, 110);
+
+ if (enable && (WCD9335_IS_1_1(clsh_d->codec_version))) {
+ wcd_clsh_set_flyback_mode(component, CLS_H_HIFI);
+ snd_soc_component_update_bits(component, WCD9XXX_FLYBACK_EN,
+ 0x60, 0x40);
+ snd_soc_component_update_bits(component, WCD9XXX_FLYBACK_EN,
+ 0x10, 0x10);
+ vneg[0] = snd_soc_component_read32(component,
+ WCD9XXX_A_ANA_RX_SUPPLIES);
+ vneg[0] &= ~(0x40);
+ vneg[1] = vneg[0] | 0x40;
+
+
+ snd_soc_component_write(component, WCD9XXX_A_ANA_RX_SUPPLIES, vneg[0]);
+
+ snd_soc_component_write(component, WCD9XXX_A_ANA_RX_SUPPLIES, vneg[1]);
+ /* 500usec delay is needed as per HW requirement */
+ usleep_range(500, 510);
+ snd_soc_component_update_bits(component, WCD9XXX_FLYBACK_EN,
+ 0x10, 0x00);
+ wcd_clsh_set_flyback_mode(component, mode);
+ }
+
+ }
+ /*
+ * 500us sleep is required after flyback enable/disable
+ * as per HW requirement
+ */
+ usleep_range(500, 500 + WCD_USLEEP_RANGE);
+}
+
+static void wcd_clsh_set_gain_path(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ int mode)
+{
+ u8 val = 0;
+
+ if (!WCD9335_IS_2_0(clsh_d->codec_version))
+ return;
+
+ switch (mode) {
+ case CLS_H_NORMAL:
+ case CLS_AB:
+ val = 0x00;
+ break;
+ case CLS_H_HIFI:
+ val = 0x02;
+ break;
+ case CLS_H_LP:
+ val = 0x01;
+ break;
+ };
+ snd_soc_component_update_bits(component, WCD9XXX_HPH_L_EN, 0xC0, (val << 6));
+ snd_soc_component_update_bits(component, WCD9XXX_HPH_R_EN, 0xC0, (val << 6));
+}
+
+static void wcd_clsh_set_hph_mode(struct snd_soc_component *component,
+ int mode)
+{
+ u8 val = 0, gain = 0, res_val = VREF_FILT_R_0OHM;
+ u8 ipeak = DELTA_I_50MA;
+
+// struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent);
+
+ switch (mode) {
+ case CLS_H_NORMAL:
+ res_val = VREF_FILT_R_50KOHM;
+ val = 0x00;
+ gain = DAC_GAIN_0DB;
+ ipeak = DELTA_I_50MA;
+ break;
+ case CLS_AB:
+ val = 0x00;
+ gain = DAC_GAIN_0DB;
+ ipeak = DELTA_I_50MA;
+ break;
+ case CLS_H_HIFI:
+ val = 0x08;
+ gain = DAC_GAIN_M0P2DB;
+ ipeak = DELTA_I_50MA;
+ break;
+ case CLS_H_LP:
+ val = 0x04;
+ ipeak = DELTA_I_30MA;
+ break;
+ };
+
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_HPH, 0x0C, val);
+// if (TASHA_IS_2_0(wcd9xxx->version)) {
+ snd_soc_component_update_bits(component, WCD9XXX_CLASSH_CTRL_VCL_2,
+ 0x30, (res_val << 4));
+ if (mode != CLS_H_LP)
+ snd_soc_component_update_bits(component, WCD9XXX_HPH_REFBUFF_UHQA_CTL,
+ 0x07, gain);
+ snd_soc_component_update_bits(component, WCD9XXX_CLASSH_CTRL_CCL_1,
+ 0xF0, (ipeak << 4));
+// }
+}
+
+static void wcd_clsh_set_flyback_current(struct snd_soc_component *component, int mode)
+{
+// struct wcd9xxx *wcd9xxx = dev_get_drvdata(component->dev->parent);
+
+// if (!TASHA_IS_2_0(wcd9xxx->version))
+// return;
+
+ snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF, 0x0F, 0x0A);
+ snd_soc_component_update_bits(component, WCD9XXX_RX_BIAS_FLYB_BUFF, 0xF0, 0xA0);
+ /* Sleep needed to avoid click and pop as per HW requirement */
+ usleep_range(100, 110);
+}
+
+static void wcd_clsh_set_buck_regulator_mode(struct snd_soc_component *component,
+ int mode)
+{
+ if (mode == CLS_AB)
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES,
+ 0x02, 0x02);
+ else
+ snd_soc_component_update_bits(component, WCD9XXX_A_ANA_RX_SUPPLIES,
+ 0x02, 0x00);
+}
+
+static void wcd_clsh_state_lo(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ if (mode != CLS_AB) {
+ dev_err(component->dev, "%s: LO cannot be in this mode: %d\n",
+ __func__, mode);
+ return;
+ }
+
+ if (is_enable) {
+ wcd_clsh_set_buck_regulator_mode(component, mode);
+ wcd_clsh_set_buck_mode(component, mode);
+ wcd_clsh_set_flyback_mode(component, mode);
+ wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
+ wcd_clsh_set_flyback_current(component, mode);
+ wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
+ } else {
+ wcd_clsh_buck_ctrl(component, clsh_d, mode, false);
+ wcd_clsh_flyback_ctrl(component, clsh_d, mode, false);
+ wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_regulator_mode(component, CLS_H_NORMAL);
+ }
+}
+
+static void wcd_clsh_state_hph_ear(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ int hph_mode = 0;
+
+ if (is_enable) {
+ if (req_state == WCD_CLSH_STATE_EAR) {
+ /* If HPH is running in CLS-AB when
+ * EAR comes, let it continue to run
+ * in Class-AB, no need to enable Class-H
+ * for EAR.
+ */
+ if (clsh_d->state & WCD_CLSH_STATE_HPHL)
+ hph_mode = wcd_clsh_get_int_mode(clsh_d,
+ WCD_CLSH_STATE_HPHL);
+ else if (clsh_d->state & WCD_CLSH_STATE_HPHR)
+ hph_mode = wcd_clsh_get_int_mode(clsh_d,
+ WCD_CLSH_STATE_HPHR);
+ if (hph_mode != CLS_AB && !is_native_44_1_active(component))
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x40);
+ }
+
+ if (is_native_44_1_active(component)) {
+ snd_soc_component_write(component, WCD9XXX_CDC_CLSH_HPH_V_PA, 0x39);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_CDC_RX0_RX_PATH_SEC0,
+ 0x03, 0x00);
+ if ((req_state == WCD_CLSH_STATE_HPHL) ||
+ (req_state == WCD_CLSH_STATE_HPHR))
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x00);
+ }
+
+ if (req_state == WCD_CLSH_STATE_HPHL)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x40);
+ if (req_state == WCD_CLSH_STATE_HPHR)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x40);
+ if ((req_state == WCD_CLSH_STATE_HPHL) ||
+ (req_state == WCD_CLSH_STATE_HPHR)) {
+ wcd_clsh_set_gain_path(component, clsh_d, mode);
+ wcd_clsh_set_flyback_mode(component, mode);
+ wcd_clsh_set_buck_mode(component, mode);
+ }
+ } else {
+ if (req_state == WCD_CLSH_STATE_EAR) {
+ /*
+ * If EAR goes away, disable EAR Channel Enable
+ * if HPH running in Class-H otherwise
+ * and if HPH requested mode is CLS_AB then
+ * no need to disable EAR channel enable bit.
+ */
+ if (wcd_clsh_enable_status(component))
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x00);
+ }
+
+ if (is_native_44_1_active(component)) {
+ snd_soc_component_write(component, WCD9XXX_CDC_CLSH_HPH_V_PA, 0x1C);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_CDC_RX0_RX_PATH_SEC0,
+ 0x03, 0x01);
+ if (((clsh_d->state & WCD_CLSH_STATE_HPH_ST)
+ != WCD_CLSH_STATE_HPH_ST) &&
+ ((req_state == WCD_CLSH_STATE_HPHL) ||
+ (req_state == WCD_CLSH_STATE_HPHR)))
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x40);
+ }
+
+ if (req_state == WCD_CLSH_STATE_HPHL)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x00);
+ if (req_state == WCD_CLSH_STATE_HPHR)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x00);
+ if ((req_state & WCD_CLSH_STATE_HPH_ST) &&
+ !wcd_clsh_enable_status(component)) {
+ /* If Class-H is not enabled when HPH is turned
+ * off, enable it as EAR is in progress
+ */
+ wcd_enable_clsh_block(component, clsh_d, true);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x40);
+ wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
+ }
+ }
+}
+
+static void wcd_clsh_state_ear_lo(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ if (is_enable && (req_state == WCD_CLSH_STATE_LO)) {
+ wcd_clsh_set_buck_regulator_mode(component, 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 (wcd_clsh_enable_status(component)) {
+ wcd_clsh_set_buck_regulator_mode(component,
+ CLS_H_NORMAL);
+ goto end;
+ }
+ wcd_enable_clsh_block(component, clsh_d, true);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x40);
+ wcd_clsh_set_buck_regulator_mode(component,
+ CLS_H_NORMAL);
+ wcd_clsh_set_buck_mode(component, mode);
+ wcd_clsh_set_flyback_mode(component, mode);
+ wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
+ wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
+ }
+end:
+ return;
+}
+
+static void wcd_clsh_state_hph_lo(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ int hph_mode = 0;
+
+ if (is_enable) {
+ /*
+ * If requested state is LO, put regulator
+ * in class-AB or if requested state is HPH,
+ * which means LO is already enabled, keep
+ * the regulator config the same at class-AB
+ * and just set the power modes for flyback
+ * and buck.
+ */
+ if (req_state == WCD_CLSH_STATE_LO)
+ wcd_clsh_set_buck_regulator_mode(component, CLS_AB);
+ else {
+ if (!wcd_clsh_enable_status(component)) {
+ wcd_enable_clsh_block(component, clsh_d, true);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_CLSH_K1_MSB,
+ 0x0F, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_CLSH_K1_LSB,
+ 0xFF, 0xC0);
+ wcd_clsh_set_flyback_mode(component, mode);
+ wcd_clsh_set_buck_mode(component, mode);
+ wcd_clsh_set_hph_mode(component, mode);
+ wcd_clsh_set_gain_path(component, clsh_d, mode);
+ } else {
+ dev_dbg(component->dev, "%s:clsh is already enabled\n",
+ __func__);
+ }
+ if (req_state == WCD_CLSH_STATE_HPHL)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x40);
+ if (req_state == WCD_CLSH_STATE_HPHR)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x40);
+ }
+ } else {
+ if ((req_state == WCD_CLSH_STATE_HPHL) ||
+ (req_state == WCD_CLSH_STATE_HPHR)) {
+ if (req_state == WCD_CLSH_STATE_HPHL)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x00);
+ if (req_state == WCD_CLSH_STATE_HPHR)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x00);
+ /*
+ * If HPH is powering down first, then disable clsh,
+ * set the buck/flyback mode to default and keep the
+ * regulator at Class-AB
+ */
+ if ((clsh_d->state & WCD_CLSH_STATE_HPH_ST)
+ != WCD_CLSH_STATE_HPH_ST) {
+ wcd_enable_clsh_block(component, clsh_d, false);
+ wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
+ }
+ } else {
+ /* LO powerdown.
+ * If HPH mode also is CLS-AB, no need
+ * to turn-on class-H, otherwise enable
+ * Class-H configuration.
+ */
+ if (clsh_d->state & WCD_CLSH_STATE_HPHL)
+ hph_mode = wcd_clsh_get_int_mode(clsh_d,
+ WCD_CLSH_STATE_HPHL);
+ else if (clsh_d->state & WCD_CLSH_STATE_HPHR)
+ hph_mode = wcd_clsh_get_int_mode(clsh_d,
+ WCD_CLSH_STATE_HPHR);
+
+ if ((hph_mode == CLS_AB) ||
+ (hph_mode == CLS_NONE))
+ goto end;
+
+ /*
+ * If Class-H is already enabled (HPH ON and then
+ * LO ON), no need to turn on again, just set the
+ * regulator mode.
+ */
+ if (wcd_clsh_enable_status(component)) {
+ wcd_clsh_set_buck_regulator_mode(component,
+ hph_mode);
+ goto end;
+ } else {
+ dev_dbg(component->dev, "%s: clsh is not enabled\n",
+ __func__);
+ }
+
+ wcd_enable_clsh_block(component, clsh_d, true);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_CLSH_K1_MSB,
+ 0x0F, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_CLSH_K1_LSB,
+ 0xFF, 0xC0);
+ wcd_clsh_set_buck_regulator_mode(component,
+ hph_mode);
+ if (clsh_d->state & WCD_CLSH_STATE_HPHL)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x40);
+ if (clsh_d->state & WCD_CLSH_STATE_HPHR)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x40);
+ wcd_clsh_set_hph_mode(component, hph_mode);
+ }
+ }
+end:
+ return;
+}
+
+static void wcd_clsh_state_hph_st(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ if (mode == CLS_AB)
+ return;
+
+ if (is_enable) {
+ if (req_state == WCD_CLSH_STATE_HPHL)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x40);
+ if (req_state == WCD_CLSH_STATE_HPHR)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x40);
+ } else {
+ if (req_state == WCD_CLSH_STATE_HPHL)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x00);
+ if (req_state == WCD_CLSH_STATE_HPHR)
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x00);
+ }
+}
+
+static void wcd_clsh_state_hph_r(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ if (mode == CLS_H_NORMAL) {
+ dev_err(component->dev, "%s: Normal mode not applicable for hph_r\n",
+ __func__);
+ return;
+ }
+
+ if (is_enable) {
+ if (mode != CLS_AB) {
+ wcd_enable_clsh_block(component, clsh_d, true);
+ /*
+ * These K1 values depend on the Headphone Impedance
+ * For now it is assumed to be 16 ohm
+ */
+ snd_soc_component_update_bits(component, WCD9XXX_A_CDC_CLSH_K1_MSB,
+ 0x0F, 0x00);
+ snd_soc_component_update_bits(component, WCD9XXX_A_CDC_CLSH_K1_LSB,
+ 0xFF, 0xC0);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x40);
+ }
+ wcd_clsh_set_buck_regulator_mode(component, mode);
+ wcd_clsh_set_flyback_mode(component, mode);
+ wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
+ wcd_clsh_set_flyback_current(component, mode);
+ wcd_clsh_set_buck_mode(component, mode);
+ wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
+ wcd_clsh_set_hph_mode(component, mode);
+ wcd_clsh_set_gain_path(component, clsh_d, mode);
+ } else {
+ wcd_clsh_set_hph_mode(component, CLS_H_NORMAL);
+
+ if (mode != CLS_AB) {
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX2_RX_PATH_CFG0,
+ 0x40, 0x00);
+ wcd_enable_clsh_block(component, clsh_d, false);
+ }
+ /* buck and flyback set to default mode and disable */
+ wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false);
+ wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false);
+ wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_regulator_mode(component, CLS_H_NORMAL);
+ }
+}
+
+static void wcd_clsh_state_hph_l(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ if (mode == CLS_H_NORMAL) {
+ dev_err(component->dev, "%s: Normal mode not applicable for hph_l\n",
+ __func__);
+ return;
+ }
+
+ if (is_enable) {
+ if (mode != CLS_AB) {
+ wcd_enable_clsh_block(component, clsh_d, true);
+ /*
+ * These K1 values depend on the Headphone Impedance
+ * For now it is assumed to be 16 ohm
+ */
+ snd_soc_component_update_bits(component, WCD9XXX_A_CDC_CLSH_K1_MSB,
+ 0x0F, 0x00);
+ snd_soc_component_update_bits(component, WCD9XXX_A_CDC_CLSH_K1_LSB,
+ 0xFF, 0xC0);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x40);
+ }
+ wcd_clsh_set_buck_regulator_mode(component, mode);
+ wcd_clsh_set_flyback_mode(component, mode);
+ wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
+ wcd_clsh_set_flyback_current(component, mode);
+ wcd_clsh_set_buck_mode(component, mode);
+ wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
+ wcd_clsh_set_hph_mode(component, mode);
+ wcd_clsh_set_gain_path(component, clsh_d, mode);
+ } else {
+ wcd_clsh_set_hph_mode(component, CLS_H_NORMAL);
+
+ if (mode != CLS_AB) {
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX1_RX_PATH_CFG0,
+ 0x40, 0x00);
+ wcd_enable_clsh_block(component, clsh_d, false);
+ }
+ /* set buck and flyback to Default Mode */
+ wcd_clsh_buck_ctrl(component, clsh_d, CLS_H_NORMAL, false);
+ wcd_clsh_flyback_ctrl(component, clsh_d, CLS_H_NORMAL, false);
+ wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_regulator_mode(component, CLS_H_NORMAL);
+ }
+}
+
+static void wcd_clsh_state_ear(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ if (mode != CLS_H_NORMAL) {
+ dev_err(component->dev, "%s: mode: %d cannot be used for EAR\n",
+ __func__, mode);
+ return;
+ }
+
+ if (is_enable) {
+ wcd_enable_clsh_block(component, clsh_d, true);
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x40);
+ wcd_clsh_set_buck_mode(component, mode);
+ wcd_clsh_set_flyback_mode(component, mode);
+ wcd_clsh_flyback_ctrl(component, clsh_d, mode, true);
+ wcd_clsh_set_flyback_current(component, mode);
+ wcd_clsh_buck_ctrl(component, clsh_d, mode, true);
+ } else {
+ snd_soc_component_update_bits(component,
+ WCD9XXX_A_CDC_RX0_RX_PATH_CFG0,
+ 0x40, 0x00);
+ wcd_enable_clsh_block(component, clsh_d, false);
+ wcd_clsh_buck_ctrl(component, clsh_d, mode, false);
+ wcd_clsh_flyback_ctrl(component, clsh_d, mode, false);
+ wcd_clsh_set_flyback_mode(component, CLS_H_NORMAL);
+ wcd_clsh_set_buck_mode(component, CLS_H_NORMAL);
+ }
+}
+
+static void wcd_clsh_state_err(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *clsh_d,
+ u8 req_state, bool is_enable, int mode)
+{
+ char msg[128];
+
+ dev_err(component->dev, "Invalid class H state machine requested\n");
+ WARN_ON(1);
+}
+
+/*
+ * Function: wcd_clsh_is_state_valid
+ * Params: state
+ * Description:
+ * Provides information on valid states of Class H configuration
+ */
+static bool wcd_clsh_is_state_valid(u8 state)
+{
+ switch (state) {
+ case WCD_CLSH_STATE_IDLE:
+ case WCD_CLSH_STATE_EAR:
+ case WCD_CLSH_STATE_HPHL:
+ case WCD_CLSH_STATE_HPHR:
+ case WCD_CLSH_STATE_HPH_ST:
+ case WCD_CLSH_STATE_LO:
+ case WCD_CLSH_STATE_HPHL_EAR:
+ case WCD_CLSH_STATE_HPHR_EAR:
+ case WCD_CLSH_STATE_HPH_ST_EAR:
+ case WCD_CLSH_STATE_HPHL_LO:
+ case WCD_CLSH_STATE_HPHR_LO:
+ case WCD_CLSH_STATE_HPH_ST_LO:
+ return true;
+ default:
+ return false;
+ };
+}
+
+/*
+ * Function: wcd_clsh_fsm
+ * Params: component, cdc_clsh_d, req_state, req_type, clsh_event
+ * Description:
+ * This function handles PRE DAC and POST DAC conditions of different devices
+ * and updates class H configuration of different combination of devices
+ * based on validity of their states. cdc_clsh_d will contain current
+ * class h state information
+ */
+void wcd_clsh_fsm(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *cdc_clsh_d,
+ u8 clsh_event, u8 req_state,
+ int int_mode)
+{
+ u8 old_state, new_state;
+ char msg0[128], msg1[128];
+
+ switch (clsh_event) {
+ case WCD_CLSH_EVENT_PRE_DAC:
+ old_state = cdc_clsh_d->state;
+ new_state = old_state | req_state;
+
+ if (!wcd_clsh_is_state_valid(new_state)) {
+ dev_err(component->dev, "Class-H not a valid new state:\n");
+ return;
+ }
+ if (new_state == old_state) {
+ dev_err(component->dev, "Class-H already in requested state\n");
+ return;
+ }
+ cdc_clsh_d->state = new_state;
+ wcd_clsh_set_int_mode(cdc_clsh_d, req_state, int_mode);
+ (*clsh_state_fp[new_state]) (component, cdc_clsh_d, req_state,
+ CLSH_REQ_ENABLE, int_mode);
+ break;
+ case WCD_CLSH_EVENT_POST_PA:
+ old_state = cdc_clsh_d->state;
+ new_state = old_state & (~req_state);
+ if (new_state < NUM_CLSH_STATES_V2) {
+ if (!wcd_clsh_is_state_valid(old_state)) {
+ dev_err(component->dev, "Invalid old state\n");
+ return;
+ }
+ if (new_state == old_state) {
+ dev_err(component->dev,"Class-H already in requested state\n");
+ return;
+ }
+ (*clsh_state_fp[old_state]) (component, cdc_clsh_d,
+ req_state, CLSH_REQ_DISABLE,
+ int_mode);
+ cdc_clsh_d->state = new_state;
+ wcd_clsh_set_int_mode(cdc_clsh_d, req_state, CLS_NONE);
+ }
+ break;
+ };
+}
+
+int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh)
+{
+ return clsh->state;
+}
+
+void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh)
+{
+ clsh->state = WCD_CLSH_STATE_IDLE;
+ clsh_state_fp[WCD_CLSH_STATE_IDLE] = wcd_clsh_state_err;
+ clsh_state_fp[WCD_CLSH_STATE_EAR] = wcd_clsh_state_ear;
+ clsh_state_fp[WCD_CLSH_STATE_HPHL] =wcd_clsh_state_hph_l;
+ clsh_state_fp[WCD_CLSH_STATE_HPHR] = wcd_clsh_state_hph_r;
+ clsh_state_fp[WCD_CLSH_STATE_HPH_ST] = wcd_clsh_state_hph_st;
+ clsh_state_fp[WCD_CLSH_STATE_LO] = wcd_clsh_state_lo;
+ clsh_state_fp[WCD_CLSH_STATE_HPHL_EAR] = wcd_clsh_state_hph_ear;
+ clsh_state_fp[WCD_CLSH_STATE_HPHR_EAR] = wcd_clsh_state_hph_ear;
+ clsh_state_fp[WCD_CLSH_STATE_HPH_ST_EAR] = wcd_clsh_state_hph_ear;
+ clsh_state_fp[WCD_CLSH_STATE_HPHL_LO] = wcd_clsh_state_hph_lo;
+ clsh_state_fp[WCD_CLSH_STATE_HPHR_LO] = wcd_clsh_state_hph_lo;
+ clsh_state_fp[WCD_CLSH_STATE_HPH_ST_LO] = wcd_clsh_state_hph_lo;
+ clsh_state_fp[WCD_CLSH_STATE_EAR_LO] = wcd_clsh_state_ear_lo;
+
+ /* Set interpolaotr modes to NONE */
+ wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_EAR, CLS_NONE);
+ wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHL, CLS_NONE);
+ wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_HPHR, CLS_NONE);
+ wcd_clsh_set_int_mode(clsh, WCD_CLSH_STATE_LO, CLS_NONE);
+
+ clsh->flyback_users = 0;
+ clsh->buck_users = 0;
+ clsh->clsh_users = 0;
+}
diff --git a/sound/soc/codecs/wcd-clsh.h b/sound/soc/codecs/wcd-clsh.h
new file mode 100644
index 000000000000..1de3caabb208
--- /dev/null
+++ b/sound/soc/codecs/wcd-clsh.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _WCD9XXX_COMMON_V2
+
+#define _WCD9XXX_COMMON_V2
+
+#include <sound/soc.h>
+
+#define CLSH_REQ_ENABLE true
+#define CLSH_REQ_DISABLE false
+
+#define WCD_CLSH_EVENT_PRE_DAC 0x01
+#define WCD_CLSH_EVENT_POST_PA 0x02
+#define MAX_VBAT_MONITOR_WRITES 17
+/*
+ * Basic states for Class H state machine.
+ * represented as a bit mask within a u8 data type
+ * bit 0: EAR mode
+ * bit 1: HPH Left mode
+ * bit 2: HPH Right mode
+ * bit 3: Lineout mode
+ */
+#define WCD_CLSH_STATE_IDLE 0x00
+#define WCD_CLSH_STATE_EAR (0x01 << 0)
+#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
+#define NUM_CLSH_STATES_V2 (0x01 << WCD_CLSH_STATE_MAX)
+
+
+/* Derived State: Bits 1 and 2 should be set for Headphone stereo */
+#define WCD_CLSH_STATE_HPH_ST (WCD_CLSH_STATE_HPHL | \
+ WCD_CLSH_STATE_HPHR)
+
+#define WCD_CLSH_STATE_HPHL_LO (WCD_CLSH_STATE_HPHL | \
+ WCD_CLSH_STATE_LO)
+#define WCD_CLSH_STATE_HPHR_LO (WCD_CLSH_STATE_HPHR | \
+ WCD_CLSH_STATE_LO)
+#define WCD_CLSH_STATE_HPH_ST_LO (WCD_CLSH_STATE_HPH_ST | \
+ WCD_CLSH_STATE_LO)
+#define WCD_CLSH_STATE_EAR_LO (WCD_CLSH_STATE_EAR | \
+ WCD_CLSH_STATE_LO)
+#define WCD_CLSH_STATE_HPHL_EAR (WCD_CLSH_STATE_HPHL | \
+ WCD_CLSH_STATE_EAR)
+#define WCD_CLSH_STATE_HPHR_EAR (WCD_CLSH_STATE_HPHR | \
+ WCD_CLSH_STATE_EAR)
+#define WCD_CLSH_STATE_HPH_ST_EAR (WCD_CLSH_STATE_HPH_ST | \
+ WCD_CLSH_STATE_EAR)
+
+enum {
+ CLS_H_NORMAL = 0, /* Class-H Default */
+ CLS_H_HIFI, /* Class-H HiFi */
+ CLS_H_LP, /* Class-H Low Power */
+ CLS_AB, /* Class-AB */
+ CLS_H_LOHIFI, /* LoHIFI */
+ CLS_NONE, /* None of the above modes */
+};
+
+/* Class H data that the codec driver will maintain */
+struct wcd_clsh_cdc_data {
+ u8 state;
+ int flyback_users;
+ int buck_users;
+ int clsh_users;
+ int codec_version;
+ int interpolator_modes[WCD_CLSH_STATE_MAX];
+};
+
+struct wcd_mad_audio_header {
+ u32 reserved[3];
+ u32 num_reg_cfg;
+};
+
+struct wcd_mad_microphone_info {
+ uint8_t input_microphone;
+ uint8_t cycle_time;
+ uint8_t settle_time;
+ uint8_t padding;
+} __packed;
+
+struct wcd_mad_micbias_info {
+ uint8_t micbias;
+ uint8_t k_factor;
+ uint8_t external_bypass_capacitor;
+ uint8_t internal_biasing;
+ uint8_t cfilter;
+ uint8_t padding[3];
+} __packed;
+
+struct wcd_mad_rms_audio_beacon_info {
+ uint8_t rms_omit_samples;
+ uint8_t rms_comp_time;
+ uint8_t detection_mechanism;
+ uint8_t rms_diff_threshold;
+ uint8_t rms_threshold_lsb;
+ uint8_t rms_threshold_msb;
+ uint8_t padding[2];
+ uint8_t iir_coefficients[36];
+} __packed;
+
+struct wcd_mad_rms_ultrasound_info {
+ uint8_t rms_comp_time;
+ uint8_t detection_mechanism;
+ uint8_t rms_diff_threshold;
+ uint8_t rms_threshold_lsb;
+ uint8_t rms_threshold_msb;
+ uint8_t padding[3];
+ uint8_t iir_coefficients[36];
+} __packed;
+
+struct wcd_mad_audio_cal {
+ uint32_t version;
+ struct wcd_mad_microphone_info microphone_info;
+ struct wcd_mad_micbias_info micbias_info;
+ struct wcd_mad_rms_audio_beacon_info audio_info;
+ struct wcd_mad_rms_audio_beacon_info beacon_info;
+ struct wcd_mad_rms_ultrasound_info ultrasound_info;
+} __packed;
+
+struct wcd9xxx_anc_header {
+ u32 reserved[3];
+ u32 num_anc_slots;
+};
+
+struct vbat_monitor_reg {
+ u32 size;
+ u32 writes[MAX_VBAT_MONITOR_WRITES];
+} __packed;
+
+extern void wcd_clsh_fsm(struct snd_soc_component *component,
+ struct wcd_clsh_cdc_data *cdc_clsh_d,
+ u8 clsh_event, u8 req_state,
+ int int_mode);
+
+extern void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh);
+extern int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh);
+
+enum {
+ RESERVED = 0,
+ AANC_LPF_FF_FB = 1,
+ AANC_LPF_COEFF_MSB,
+ AANC_LPF_COEFF_LSB,
+ HW_MAD_AUDIO_ENABLE,
+ HW_MAD_ULTR_ENABLE,
+ HW_MAD_BEACON_ENABLE,
+ HW_MAD_AUDIO_SLEEP_TIME,
+ HW_MAD_ULTR_SLEEP_TIME,
+ HW_MAD_BEACON_SLEEP_TIME,
+ HW_MAD_TX_AUDIO_SWITCH_OFF,
+ HW_MAD_TX_ULTR_SWITCH_OFF,
+ HW_MAD_TX_BEACON_SWITCH_OFF,
+ MAD_AUDIO_INT_DEST_SELECT_REG,
+ MAD_ULT_INT_DEST_SELECT_REG,
+ MAD_BEACON_INT_DEST_SELECT_REG,
+ MAD_CLIP_INT_DEST_SELECT_REG,
+ VBAT_INT_DEST_SELECT_REG,
+ MAD_AUDIO_INT_MASK_REG,
+ MAD_ULT_INT_MASK_REG,
+ MAD_BEACON_INT_MASK_REG,
+ MAD_CLIP_INT_MASK_REG,
+ VBAT_INT_MASK_REG,
+ MAD_AUDIO_INT_STATUS_REG,
+ MAD_ULT_INT_STATUS_REG,
+ MAD_BEACON_INT_STATUS_REG,
+ MAD_CLIP_INT_STATUS_REG,
+ VBAT_INT_STATUS_REG,
+ MAD_AUDIO_INT_CLEAR_REG,
+ MAD_ULT_INT_CLEAR_REG,
+ MAD_BEACON_INT_CLEAR_REG,
+ MAD_CLIP_INT_CLEAR_REG,
+ VBAT_INT_CLEAR_REG,
+ SB_PGD_PORT_TX_WATERMARK_N,
+ SB_PGD_PORT_TX_ENABLE_N,
+ SB_PGD_PORT_RX_WATERMARK_N,
+ SB_PGD_PORT_RX_ENABLE_N,
+ SB_PGD_TX_PORTn_MULTI_CHNL_0,
+ SB_PGD_TX_PORTn_MULTI_CHNL_1,
+ SB_PGD_RX_PORTn_MULTI_CHNL_0,
+ SB_PGD_RX_PORTn_MULTI_CHNL_1,
+ AANC_FF_GAIN_ADAPTIVE,
+ AANC_FFGAIN_ADAPTIVE_EN,
+ AANC_GAIN_CONTROL,
+ SPKR_CLIP_PIPE_BANK_SEL,
+ SPKR_CLIPDET_VAL0,
+ SPKR_CLIPDET_VAL1,
+ SPKR_CLIPDET_VAL2,
+ SPKR_CLIPDET_VAL3,
+ SPKR_CLIPDET_VAL4,
+ SPKR_CLIPDET_VAL5,
+ SPKR_CLIPDET_VAL6,
+ SPKR_CLIPDET_VAL7,
+ VBAT_RELEASE_INT_DEST_SELECT_REG,
+ VBAT_RELEASE_INT_MASK_REG,
+ VBAT_RELEASE_INT_STATUS_REG,
+ VBAT_RELEASE_INT_CLEAR_REG,
+ MAD2_CLIP_INT_DEST_SELECT_REG,
+ MAD2_CLIP_INT_MASK_REG,
+ MAD2_CLIP_INT_STATUS_REG,
+ MAD2_CLIP_INT_CLEAR_REG,
+ SPKR2_CLIP_PIPE_BANK_SEL,
+ SPKR2_CLIPDET_VAL0,
+ SPKR2_CLIPDET_VAL1,
+ SPKR2_CLIPDET_VAL2,
+ SPKR2_CLIPDET_VAL3,
+ SPKR2_CLIPDET_VAL4,
+ SPKR2_CLIPDET_VAL5,
+ SPKR2_CLIPDET_VAL6,
+ SPKR2_CLIPDET_VAL7,
+ MAX_CFG_REGISTERS,
+};
+
+#endif
diff --git a/sound/soc/codecs/wcd-slim.h b/sound/soc/codecs/wcd-slim.h
new file mode 100644
index 000000000000..2c6550564d56
--- /dev/null
+++ b/sound/soc/codecs/wcd-slim.h
@@ -0,0 +1,82 @@
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __WCD_SLIMSLAVE_H_
+#define __WCD_SLIMSLAVE_H_
+
+#include <linux/slimbus.h>
+
+#define WCD_SLIM_CH(xport, xshift) \
+ {.port = xport, .shift = xshift}
+
+struct wcd_slim_ch {
+ u32 sph;
+ u32 ch_num;
+ u16 ch_h;
+ u16 port;
+ u16 shift;
+ struct list_head list;
+};
+
+struct wcd_slim_data {
+ struct slim_device *slim;
+ struct slim_device *slim_slave;
+ u16 rx_port_ch_reg_base;
+ u16 port_tx_cfg_reg_base;
+ u16 port_rx_cfg_reg_base;
+ struct regmap *regmap;
+ struct regmap *if_regmap;
+ struct wcd_slim_ch *rx_chs;
+ struct wcd_slim_ch *tx_chs;
+ u32 num_rx_port;
+ u32 num_tx_port;
+};
+
+#define WCD9335_RX_SLAVE_PORTS 16
+#define WCD9335_TX_SLAVE_PORTS 16
+#define SLIM_MAX_TX_PORTS 16
+#define SLIM_MAX_RX_PORTS 16
+
+/* below details are taken from SLIMBUS slave SWI */
+#define SB_PGD_PORT_BASE 0x000
+
+#define SB_PGD_PORT_CFG_BYTE_ADDR(offset, port_num) \
+ (SB_PGD_PORT_BASE + offset + (1 * port_num))
+
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0(port_num) \
+ (SB_PGD_PORT_BASE + 0x100 + 4*port_num)
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0_START_PORT_ID 0
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID 7
+
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_1(port_num) \
+ (SB_PGD_PORT_BASE + 0x101 + 4*port_num)
+#define SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID 8
+
+#define SB_PGD_RX_PORT_MULTI_CHANNEL_0(offset, port_num) \
+ (SB_PGD_PORT_BASE + offset + (4 * port_num))
+
+/* slave port water mark level
+ * (0: 6bytes, 1: 9bytes, 2: 12 bytes, 3: 15 bytes)
+ */
+#define SLAVE_PORT_WATER_MARK_6BYTES 0
+#define SLAVE_PORT_WATER_MARK_9BYTES 1
+#define SLAVE_PORT_WATER_MARK_12BYTES 2
+#define SLAVE_PORT_WATER_MARK_15BYTES 3
+#define SLAVE_PORT_WATER_MARK_SHIFT 1
+#define SLAVE_PORT_ENABLE 1
+#define SLAVE_PORT_DISABLE 0
+#define WATER_MARK_VAL \
+ ((SLAVE_PORT_WATER_MARK_12BYTES << SLAVE_PORT_WATER_MARK_SHIFT) | \
+ (SLAVE_PORT_ENABLE))
+#define BASE_CH_NUM 128
+
+#endif /* __WCD_SLIMSLAVE_H_ */
diff --git a/sound/soc/codecs/wcd9335-regmap.c b/sound/soc/codecs/wcd9335-regmap.c
new file mode 100644
index 000000000000..96dc0e4ebec6
--- /dev/null
+++ b/sound/soc/codecs/wcd9335-regmap.c
@@ -0,0 +1,2913 @@
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include "wcd9335_registers.h"
+#include "wcd9335.h"
+
+#define WCD9335_REG(reg) ((reg) & 0xFF)
+
+const u8 wcd9335_page0_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE0_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_CLK_BYPASS)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_CLK_GATE)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_CLK_MCLK_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_RST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_INT_MASK)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_INT_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CODEC_RPM_INT_CLEAR)] = 0,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_I2S_CLK)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_NATIVE_FIFO_SYNC)] = 1,
+ [WCD9335_REG(WCD9335_DATA_HUB_NATIVE_FIFO_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_INTR_CFG)] = 1,
+ [WCD9335_REG(WCD9335_INTR_CLR_COMMIT)] = 0,
+ [WCD9335_REG(WCD9335_INTR_PIN1_MASK0)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN1_MASK1)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN1_MASK2)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN1_MASK3)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN1_STATUS0)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN1_STATUS1)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN1_STATUS2)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN1_STATUS3)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN1_CLEAR0)] = 0,
+ [WCD9335_REG(WCD9335_INTR_PIN1_CLEAR1)] = 0,
+ [WCD9335_REG(WCD9335_INTR_PIN1_CLEAR2)] = 0,
+ [WCD9335_REG(WCD9335_INTR_PIN1_CLEAR3)] = 0,
+ [WCD9335_REG(WCD9335_INTR_PIN2_MASK0)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN2_MASK1)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN2_MASK2)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN2_MASK3)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN2_STATUS0)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN2_STATUS1)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN2_STATUS2)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN2_STATUS3)] = 1,
+ [WCD9335_REG(WCD9335_INTR_PIN2_CLEAR0)] = 0,
+ [WCD9335_REG(WCD9335_INTR_PIN2_CLEAR1)] = 0,
+ [WCD9335_REG(WCD9335_INTR_PIN2_CLEAR2)] = 0,
+ [WCD9335_REG(WCD9335_INTR_PIN2_CLEAR3)] = 0,
+ [WCD9335_REG(WCD9335_INTR_LEVEL0)] = 1,
+ [WCD9335_REG(WCD9335_INTR_LEVEL1)] = 1,
+ [WCD9335_REG(WCD9335_INTR_LEVEL2)] = 1,
+ [WCD9335_REG(WCD9335_INTR_LEVEL3)] = 1,
+ [WCD9335_REG(WCD9335_INTR_BYPASS0)] = 1,
+ [WCD9335_REG(WCD9335_INTR_BYPASS1)] = 1,
+ [WCD9335_REG(WCD9335_INTR_BYPASS2)] = 1,
+ [WCD9335_REG(WCD9335_INTR_BYPASS3)] = 1,
+ [WCD9335_REG(WCD9335_INTR_SET0)] = 1,
+ [WCD9335_REG(WCD9335_INTR_SET1)] = 1,
+ [WCD9335_REG(WCD9335_INTR_SET2)] = 1,
+ [WCD9335_REG(WCD9335_INTR_SET3)] = 1,
+};
+
+const u8 wcd9335_page1_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE1_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_8)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_USER_CTL_9)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_L_VAL_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_L_VAL_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_DSM_FRAC_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_DSM_FRAC_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_CONFIG_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_TEST_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_FREQ_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_SSC_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_FLL_MODE)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_STATUS_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_STATUS_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_STATUS_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_FLL_STATUS_3)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_8)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_USER_CTL_9)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_L_VAL_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_L_VAL_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_DSM_FRAC_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_DSM_FRAC_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_CONFIG_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_TEST_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_FREQ_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_SSC_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_FLL_MODE)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_STATUS_0)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_STATUS_1)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_STATUS_2)] = 1,
+ [WCD9335_REG(WCD9335_I2S_FLL_STATUS_3)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_8)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_USER_CTL_9)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_L_VAL_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_L_VAL_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_DSM_FRAC_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_DSM_FRAC_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_CONFIG_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_TEST_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_FREQ_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_SSC_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_FLL_MODE)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_STATUS_0)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_STATUS_1)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_STATUS_2)] = 1,
+ [WCD9335_REG(WCD9335_SB_FLL_STATUS_3)] = 1,
+};
+
+const u8 wcd9335_page2_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE2_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_PTR_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_3)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_4)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_5)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_6)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_7)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_8)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_9)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_10)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_11)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_12)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_13)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_14)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MEM_BANK_15)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_TRG)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_TRG)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_0)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_1)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_2)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_3)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_4)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_5)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_6)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_7)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_8)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_9)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_10)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_11)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_12)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_13)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_14)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX1_15)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_3)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_4)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_5)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_6)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_7)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_8)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_9)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_10)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_11)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_12)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_13)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_14)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_15)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_0)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_1)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_2)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_3)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_4)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_5)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_6)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_7)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_8)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_9)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_10)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_11)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_12)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_13)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_14)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_INBOX2_15)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_0)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_1)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_2)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_3)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_4)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_5)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_6)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_7)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_8)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_9)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_10)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_11)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_12)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_13)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_14)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_15)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX1_ACK)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_OUTBOX2_ACK)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_EC_BUF_INT_PERIOD)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_US_BUF_INT_PERIOD)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_US_EC_MUX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_MAD_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_CPAR_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_TX_PP_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_DMIC0_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_DMIC1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_DMIC2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_DMIC_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_SVA_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_CPAR_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_WDOG_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_BACKUP_INT)] = 0,
+ [WCD9335_REG(WCD9335_CPE_SS_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_CPE_OCD_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_MASK)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CPE_SS_SS_ERROR_INT_CLEAR)] = 0,
+ [WCD9335_REG(WCD9335_SOC_MAD_MAIN_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_MAIN_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_CTL_8)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_ULTR_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_4)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_5)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_6)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_7)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_CTL_8)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL)] = 1,
+ [WCD9335_REG(WCD9335_SOC_MAD_INP_SEL)] = 1,
+};
+
+const u8 wcd9335_page6_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE6_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_ANA_BIAS)] = 1,
+ [WCD9335_REG(WCD9335_ANA_CLK_TOP)] = 1,
+ [WCD9335_REG(WCD9335_ANA_RCO)] = 1,
+ [WCD9335_REG(WCD9335_ANA_BUCK_VOUT_A)] = 1,
+ [WCD9335_REG(WCD9335_ANA_BUCK_VOUT_D)] = 1,
+ [WCD9335_REG(WCD9335_ANA_BUCK_CTL)] = 1,
+ [WCD9335_REG(WCD9335_ANA_BUCK_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_ANA_RX_SUPPLIES)] = 1,
+ [WCD9335_REG(WCD9335_ANA_HPH)] = 1,
+ [WCD9335_REG(WCD9335_ANA_EAR)] = 1,
+ [WCD9335_REG(WCD9335_ANA_LO_1_2)] = 1,
+ [WCD9335_REG(WCD9335_ANA_LO_3_4)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MAD_SETUP)] = 1,
+ [WCD9335_REG(WCD9335_ANA_AMIC1)] = 1,
+ [WCD9335_REG(WCD9335_ANA_AMIC2)] = 1,
+ [WCD9335_REG(WCD9335_ANA_AMIC3)] = 1,
+ [WCD9335_REG(WCD9335_ANA_AMIC4)] = 1,
+ [WCD9335_REG(WCD9335_ANA_AMIC5)] = 1,
+ [WCD9335_REG(WCD9335_ANA_AMIC6)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_MECH)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_ELECT)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_ZDET)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_RESULT_1)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_RESULT_2)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_RESULT_3)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_BTN0)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_BTN1)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_BTN2)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_BTN3)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_BTN4)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_BTN5)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_BTN6)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MBHC_BTN7)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MICB1)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MICB2)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MICB2_RAMP)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MICB3)] = 1,
+ [WCD9335_REG(WCD9335_ANA_MICB4)] = 1,
+ [WCD9335_REG(WCD9335_ANA_VBADC)] = 1,
+ [WCD9335_REG(WCD9335_BIAS_CTL)] = 1,
+ [WCD9335_REG(WCD9335_BIAS_VBG_FINE_ADJ)] = 1,
+ [WCD9335_REG(WCD9335_CLOCK_TEST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CTRL_1)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CTRL_2)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CAL)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CAL_1)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CAL_2)] = 1,
+ [WCD9335_REG(WCD9335_RCO_TEST_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CAL_OUT_1)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CAL_OUT_2)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CAL_OUT_3)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CAL_OUT_4)] = 1,
+ [WCD9335_REG(WCD9335_RCO_CAL_OUT_5)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_MODE_1)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_MODE_2)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_MODE_3)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_MODE_4)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_VCL_1)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_VCL_2)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_VCL_3)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_1)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_2)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_3)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_4)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_5)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_6)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_7)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_8)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_9)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CCL_10)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_FILTER_1)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_FILTER_2)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_1)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_2)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_DRIVER_3)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_EXT_1)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_EXT_2)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_OUT_1)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_CAL_CODE_OUT_2)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_TEST_1)] = 1,
+ [WCD9335_REG(WCD9335_SIDO_SIDO_TEST_2)] = 1,
+ [WCD9335_REG(WCD9335_MBHC_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_MBHC_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_MBHC_PLUG_DETECT_CTL)] = 1,
+ [WCD9335_REG(WCD9335_MBHC_ZDET_ANA_CTL)] = 1,
+ [WCD9335_REG(WCD9335_MBHC_ZDET_RAMP_CTL)] = 1,
+ [WCD9335_REG(WCD9335_MBHC_FSM_DEBUG)] = 1,
+ [WCD9335_REG(WCD9335_MBHC_TEST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_SUBBLOCK_EN)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_IBIAS_FE)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_BIAS_ADC)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_FE_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_ADC_REF)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_ADC_IO)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_ADC_SAR)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_DEBUG)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_ADC_DOUTMSB)] = 1,
+ [WCD9335_REG(WCD9335_VBADC_ADC_DOUTLSB)] = 1,
+ [WCD9335_REG(WCD9335_LDOH_MODE)] = 1,
+ [WCD9335_REG(WCD9335_LDOH_BIAS)] = 1,
+ [WCD9335_REG(WCD9335_LDOH_STB_LOADS)] = 1,
+ [WCD9335_REG(WCD9335_LDOH_SLOWRAMP)] = 1,
+ [WCD9335_REG(WCD9335_MICB1_TEST_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_MICB1_TEST_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_MICB1_TEST_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_MICB2_TEST_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_MICB2_TEST_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_MICB2_TEST_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_MICB3_TEST_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_MICB3_TEST_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_MICB3_TEST_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_MICB4_TEST_CTL_1)] = 1,
+ [WCD9335_REG(WCD9335_MICB4_TEST_CTL_2)] = 1,
+ [WCD9335_REG(WCD9335_MICB4_TEST_CTL_3)] = 1,
+ [WCD9335_REG(WCD9335_TX_COM_ADC_VCM)] = 1,
+ [WCD9335_REG(WCD9335_TX_COM_BIAS_ATEST)] = 1,
+ [WCD9335_REG(WCD9335_TX_COM_ADC_INT1_IB)] = 1,
+ [WCD9335_REG(WCD9335_TX_COM_ADC_INT2_IB)] = 1,
+ [WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_CTL)] = 1,
+ [WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_START)] = 1,
+ [WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_STOP_9P6M)] = 1,
+ [WCD9335_REG(WCD9335_TX_COM_TXFE_DIV_STOP_12P288M)] = 1,
+ [WCD9335_REG(WCD9335_TX_1_2_TEST_EN)] = 1,
+ [WCD9335_REG(WCD9335_TX_1_2_ADC_IB)] = 1,
+ [WCD9335_REG(WCD9335_TX_1_2_ATEST_REFCTL)] = 1,
+ [WCD9335_REG(WCD9335_TX_1_2_TEST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_TX_1_2_TEST_BLK_EN)] = 1,
+ [WCD9335_REG(WCD9335_TX_1_2_TXFE_CLKDIV)] = 1,
+ [WCD9335_REG(WCD9335_TX_1_2_SAR1_ERR)] = 1,
+ [WCD9335_REG(WCD9335_TX_1_2_SAR2_ERR)] = 1,
+ [WCD9335_REG(WCD9335_TX_3_4_TEST_EN)] = 1,
+ [WCD9335_REG(WCD9335_TX_3_4_ADC_IB)] = 1,
+ [WCD9335_REG(WCD9335_TX_3_4_ATEST_REFCTL)] = 1,
+ [WCD9335_REG(WCD9335_TX_3_4_TEST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_TX_3_4_TEST_BLK_EN)] = 1,
+ [WCD9335_REG(WCD9335_TX_3_4_TXFE_CLKDIV)] = 1,
+ [WCD9335_REG(WCD9335_TX_3_4_SAR1_ERR)] = 1,
+ [WCD9335_REG(WCD9335_TX_3_4_SAR2_ERR)] = 1,
+ [WCD9335_REG(WCD9335_TX_5_6_TEST_EN)] = 1,
+ [WCD9335_REG(WCD9335_TX_5_6_ADC_IB)] = 1,
+ [WCD9335_REG(WCD9335_TX_5_6_ATEST_REFCTL)] = 1,
+ [WCD9335_REG(WCD9335_TX_5_6_TEST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_TX_5_6_TEST_BLK_EN)] = 1,
+ [WCD9335_REG(WCD9335_TX_5_6_TXFE_CLKDIV)] = 1,
+ [WCD9335_REG(WCD9335_TX_5_6_SAR1_ERR)] = 1,
+ [WCD9335_REG(WCD9335_TX_5_6_SAR2_ERR)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_MODE_1)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_MODE_2)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_MODE_3)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_CTRL_VCL_1)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_CTRL_VCL_2)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_1)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_2)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_3)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_4)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_CTRL_CCL_5)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_BUCK_TMUX_A_D)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_BUCK_SW_DRV_CNTL)] = 1,
+ [WCD9335_REG(WCD9335_CLASSH_SPARE)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_EN)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_1)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_2)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_3)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_4)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_5)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_6)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_7)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_8)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_CTRL_9)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_1)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_2)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_3)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_VNEG_DAC_CTRL_4)] = 1,
+ [WCD9335_REG(WCD9335_FLYBACK_TEST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_RX_AUX_SW_CTL)] = 1,
+ [WCD9335_REG(WCD9335_RX_PA_AUX_IN_CONN)] = 1,
+ [WCD9335_REG(WCD9335_RX_TIMER_DIV)] = 1,
+ [WCD9335_REG(WCD9335_RX_OCP_CTL)] = 1,
+ [WCD9335_REG(WCD9335_RX_OCP_COUNT)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_EAR_DAC)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_EAR_AMP)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_HPH_LDO)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_HPH_PA)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_HPH_RDAC_LDO)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_HPH_CNP1)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_HPH_LOWPOWER)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_PA)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_REF)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_DIFFLO_LDO)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_SELO_DAC_PA)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_BUCK_RST)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_BUCK_VREF_ERRAMP)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_FLYB_ERRAMP)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_FLYB_BUFF)] = 1,
+ [WCD9335_REG(WCD9335_RX_BIAS_FLYB_MID_RST)] = 1,
+ [WCD9335_REG(WCD9335_HPH_L_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_HPH_R_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_HPH_CNP_EN)] = 1,
+ [WCD9335_REG(WCD9335_HPH_CNP_WG_CTL)] = 1,
+ [WCD9335_REG(WCD9335_HPH_CNP_WG_TIME)] = 1,
+ [WCD9335_REG(WCD9335_HPH_OCP_CTL)] = 1,
+ [WCD9335_REG(WCD9335_HPH_AUTO_CHOP)] = 1,
+ [WCD9335_REG(WCD9335_HPH_CHOP_CTL)] = 1,
+ [WCD9335_REG(WCD9335_HPH_PA_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_HPH_PA_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_HPH_L_EN)] = 1,
+ [WCD9335_REG(WCD9335_HPH_L_TEST)] = 1,
+ [WCD9335_REG(WCD9335_HPH_L_ATEST)] = 1,
+ [WCD9335_REG(WCD9335_HPH_R_EN)] = 1,
+ [WCD9335_REG(WCD9335_HPH_R_TEST)] = 1,
+ [WCD9335_REG(WCD9335_HPH_R_ATEST)] = 1,
+ [WCD9335_REG(WCD9335_HPH_RDAC_CLK_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_HPH_RDAC_CLK_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_HPH_RDAC_LDO_CTL)] = 1,
+ [WCD9335_REG(WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL)] = 1,
+ [WCD9335_REG(WCD9335_HPH_REFBUFF_UHQA_CTL)] = 1,
+ [WCD9335_REG(WCD9335_HPH_REFBUFF_LP_CTL)] = 1,
+ [WCD9335_REG(WCD9335_HPH_L_DAC_CTL)] = 1,
+ [WCD9335_REG(WCD9335_HPH_R_DAC_CTL)] = 1,
+ [WCD9335_REG(WCD9335_EAR_EN_REG)] = 1,
+ [WCD9335_REG(WCD9335_EAR_CMBUFF)] = 1,
+ [WCD9335_REG(WCD9335_EAR_ICTL)] = 1,
+ [WCD9335_REG(WCD9335_EAR_EN_DBG_CTL)] = 1,
+ [WCD9335_REG(WCD9335_EAR_CNP)] = 1,
+ [WCD9335_REG(WCD9335_EAR_DAC_CTL_ATEST)] = 1,
+ [WCD9335_REG(WCD9335_EAR_STATUS_REG)] = 1,
+ [WCD9335_REG(WCD9335_EAR_OUT_SHORT)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_MISC)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_LO2_COMPANDER)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_LO1_COMPANDER)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_COMMON)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_BYPASS_EN)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_CNP)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_CORE_OUT_PROG)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_LDO_OUT_PROG)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_COM_PA_FREQ)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_RESERVED_REG)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_LO1_STATUS_1)] = 1,
+ [WCD9335_REG(WCD9335_DIFF_LO_LO1_STATUS_2)] = 1,
+ [WCD9335_REG(WCD9335_SE_LO_COM1)] = 1,
+ [WCD9335_REG(WCD9335_SE_LO_COM2)] = 1,
+ [WCD9335_REG(WCD9335_SE_LO_LO3_GAIN)] = 1,
+ [WCD9335_REG(WCD9335_SE_LO_LO3_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_SE_LO_LO4_GAIN)] = 1,
+ [WCD9335_REG(WCD9335_SE_LO_LO4_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_SE_LO_LO3_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_SE_LO_LO4_STATUS)] = 1,
+};
+
+const u8 wcd9335_page10_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE10_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_CLK_RESET_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_MODE_1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_MODE_2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_FF_SHIFT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_FB_SHIFT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_LPF_FF_A_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_LPF_FF_B_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_LPF_FB_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_SMLPF_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_IIR_ADAPT_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_IIR_COEFF_1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_IIR_COEFF_2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_FF_A_GAIN_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_FF_B_GAIN_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC0_FB_GAIN_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_CLK_RESET_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_MODE_1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_MODE_2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_FF_SHIFT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_FB_SHIFT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_LPF_FF_A_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_LPF_FF_B_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_LPF_FB_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_SMLPF_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_IIR_ADAPT_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_IIR_COEFF_1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_IIR_COEFF_2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_FF_A_GAIN_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_FF_B_GAIN_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_ANC1_FB_GAIN_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX0_TX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX1_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX2_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX3_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX4_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX5_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX6_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX7_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_192_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_192_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX8_TX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0)] = 1,
+};
+
+const u8 wcd9335_page11_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE11_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER1_CTL7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER2_CTL7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER3_CTL7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER4_CTL7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER5_CTL7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER6_CTL7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER7_CTL7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_COMPANDER8_CTL7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX0_RX_PATH_MIX_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX1_RX_PATH_MIX_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX2_RX_PATH_MIX_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX3_RX_PATH_MIX_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX4_RX_PATH_MIX_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX5_RX_PATH_MIX_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX6_RX_PATH_MIX_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX7_RX_PATH_MIX_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_VOL_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_VOL_MIX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_SEC7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_SEC0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX8_RX_PATH_MIX_SEC1)] = 1,
+};
+
+const u8 wcd9335_page12_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE12_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_CRC)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_DLY_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_DECAY_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_HPH_V_PA)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_EAR_V_PA)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_HPH_V_HD)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_EAR_V_HD)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_K1_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_K1_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_K2_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_K2_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_IDLE_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_IDLE_HPH)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_IDLE_EAR)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_TEST0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_TEST1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLSH_OVR_VREF)] = 1,
+ [WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_BOOST0_BOOST_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_BOOST1_BOOST_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_0)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_1)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_2)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_DATA_3)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_0)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_1)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_2)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_RD_DATA_3)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG)] = 1,
+ [WCD9335_REG(WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_CFG)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_ADC_CAL3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_PK_EST3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_RF_PROC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_RF_PROC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_TAC4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_DEBUG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON)] = 0,
+ [WCD9335_REG(WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL)] = 1,
+ [WCD9335_REG(WCD9335_SPLINE_SRC0_CLK_RST_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SPLINE_SRC0_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_SPLINE_SRC1_CLK_RST_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SPLINE_SRC1_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_SPLINE_SRC2_CLK_RST_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SPLINE_SRC2_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_SPLINE_SRC3_CLK_RST_CTL_0)] = 1,
+ [WCD9335_REG(WCD9335_SPLINE_SRC3_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1)] = 1,
+};
+
+const u8 wcd9335_page13_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE13_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_ANC_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD)] = 1,
+ [WCD9335_REG(WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG0)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG1)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG2)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG3)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG4)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG5)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG6)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_TOP_CFG7)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_WR_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_WR_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_LUT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_RD_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHL_COMP_RD_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_WR_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_WR_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_LUT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_RD_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_HPHR_COMP_RD_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_LUT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_LUT)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB)] = 1,
+ [WCD9335_REG(WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB)] = 1,
+};
+
+const u8 wcd9335_page_0x80_reg_readable[WCD9335_PAGE_SIZE] = {
+ [WCD9335_REG(WCD9335_PAGE80_PAGE_REGISTER)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_BIST_MODE_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_RF_PA_ON_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_INTR1_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_INTR2_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_SWR_DATA_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_SWR_CLK_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_SLIMBUS_DATA2_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2C_CLK_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2C_DATA_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2S_RX_SD0_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2S_RX_SD1_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2S_RX_SCK_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2S_RX_WS_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2S_TX_SD0_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2S_TX_SD1_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2S_TX_SCK_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_I2S_TX_WS_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_DMIC1_CLK_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_DMIC1_DATA_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_DMIC2_CLK_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_DMIC2_DATA_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_DMIC3_CLK_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_DMIC3_DATA_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_JTDI_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_JTDO_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_JTMS_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_JTCK_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TLMM_JTRST_PINCFG)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_0)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_1)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_2)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_OE_3)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_0)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_1)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_2)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_CTL_DATA_3)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PAD_DRVCTL)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_PIN_STATUS)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_NPL_DLY_TEST_1)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_NPL_DLY_TEST_2)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_MEM_CTRL)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_BUS_SEL)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_JTAG)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_1)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_2)] = 1,
+ [WCD9335_REG(WCD9335_TEST_DEBUG_DEBUG_EN_3)] = 1,
+};
+
+const u8 *wcd9335_reg[WCD9335_NUM_PAGES] = {
+ [PAGE_0] = wcd9335_page0_reg_readable,
+ [PAGE_1] = wcd9335_page1_reg_readable,
+ [PAGE_2] = wcd9335_page2_reg_readable,
+ [PAGE_6] = wcd9335_page6_reg_readable,
+ [PAGE_10] = wcd9335_page10_reg_readable,
+ [PAGE_11] = wcd9335_page11_reg_readable,
+ [PAGE_12] = wcd9335_page12_reg_readable,
+ [PAGE_13] = wcd9335_page13_reg_readable,
+ [PAGE_0X80] = wcd9335_page_0x80_reg_readable,
+};
+
+static const struct reg_sequence wcd9335_1_x_defaults[] = {
+ { WCD9335_CODEC_RPM_CLK_GATE , 0x03 },
+ { WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN , 0x1f },
+ { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_CTL , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG , 0x00 },
+ { WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD , 0x14 },
+ { WCD9335_CPE_SS_SS_ERROR_INT_MASK , 0x3f },
+ { WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL , 0x00 },
+ { WCD9335_BIAS_VBG_FINE_ADJ , 0x55 },
+ { WCD9335_SIDO_SIDO_CCL_2 , 0x6c },
+ { WCD9335_SIDO_SIDO_CCL_3 , 0x2d },
+ { WCD9335_SIDO_SIDO_CCL_8 , 0x6c },
+ { WCD9335_SIDO_SIDO_CCL_10 , 0x6c },
+ { WCD9335_SIDO_SIDO_DRIVER_2 , 0x77 },
+ { WCD9335_SIDO_SIDO_DRIVER_3 , 0x77 },
+ { WCD9335_SIDO_SIDO_TEST_2 , 0x00 },
+ { WCD9335_MBHC_ZDET_ANA_CTL , 0x00 },
+ { WCD9335_MBHC_FSM_DEBUG , 0xc0 },
+ { WCD9335_TX_1_2_ATEST_REFCTL , 0x08 },
+ { WCD9335_TX_3_4_ATEST_REFCTL , 0x08 },
+ { WCD9335_TX_5_6_ATEST_REFCTL , 0x08 },
+ { WCD9335_FLYBACK_VNEG_CTRL_1 , 0x67 },
+ { WCD9335_FLYBACK_VNEG_CTRL_4 , 0x5f },
+ { WCD9335_FLYBACK_VNEG_CTRL_9 , 0x50 },
+ { WCD9335_FLYBACK_VNEG_DAC_CTRL_1 , 0x65 },
+ { WCD9335_FLYBACK_VNEG_DAC_CTRL_4 , 0x40 },
+ { WCD9335_RX_BIAS_HPH_PA , 0xaa },
+ { WCD9335_RX_BIAS_HPH_LOWPOWER , 0x62 },
+ { WCD9335_HPH_PA_CTL2 , 0x40 },
+ { WCD9335_HPH_L_EN , 0x00 },
+ { WCD9335_HPH_R_EN , 0x00 },
+ { WCD9335_HPH_R_ATEST , 0x50 },
+ { WCD9335_HPH_RDAC_LDO_CTL , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_TX1_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_TX2_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_TX3_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_TX4_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_TX5_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_TX6_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_TX7_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_TX8_TX_PATH_SEC3 , 0x0c },
+ { WCD9335_CDC_COMPANDER1_CTL7 , 0x0c },
+ { WCD9335_CDC_COMPANDER2_CTL7 , 0x0c },
+ { WCD9335_CDC_COMPANDER3_CTL7 , 0x0c },
+ { WCD9335_CDC_COMPANDER4_CTL7 , 0x0c },
+ { WCD9335_CDC_COMPANDER5_CTL7 , 0x0c },
+ { WCD9335_CDC_COMPANDER6_CTL7 , 0x0c },
+ { WCD9335_CDC_COMPANDER7_CTL7 , 0x0c },
+ { WCD9335_CDC_COMPANDER8_CTL7 , 0x0c },
+ { WCD9335_CDC_RX0_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX0_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX0_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX1_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX1_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX2_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX2_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX3_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX3_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX4_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX4_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX5_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX5_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX6_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX6_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX7_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX7_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_CFG1 , 0x04 },
+ { WCD9335_CDC_RX8_RX_PATH_MIX_CFG , 0x0e },
+ { WCD9335_CDC_RX8_RX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_MIX_SEC0 , 0x00 },
+ { WCD9335_SPLINE_SRC0_CLK_RST_CTL_0 , 0x00 },
+ { WCD9335_SPLINE_SRC1_CLK_RST_CTL_0 , 0x00 },
+ { WCD9335_SPLINE_SRC2_CLK_RST_CTL_0 , 0x00 },
+ { WCD9335_SPLINE_SRC3_CLK_RST_CTL_0 , 0x00 },
+ { WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL , 0x00 },
+ { WCD9335_TEST_DEBUG_NPL_DLY_TEST_1 , 0x00 },
+ { WCD9335_TEST_DEBUG_NPL_DLY_TEST_2 , 0x00 },
+};
+
+static const struct reg_sequence wcd9335_2_0_defaults[] = {
+ { WCD9335_CODEC_RPM_CLK_GATE , 0x07 },
+ { WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN , 0x3f },
+ { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0 , 0x01 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_CTL , 0x10 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG , 0x08 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG , 0x08 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG , 0x08 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG , 0x08 },
+ { WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD , 0x13 },
+ { WCD9335_CPE_SS_SS_ERROR_INT_MASK , 0xff },
+ { WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL , 0x40 },
+ { WCD9335_BIAS_VBG_FINE_ADJ , 0xc5 },
+ { WCD9335_SIDO_SIDO_CCL_2 , 0x92 },
+ { WCD9335_SIDO_SIDO_CCL_3 , 0x35 },
+ { WCD9335_SIDO_SIDO_CCL_8 , 0x6e },
+ { WCD9335_SIDO_SIDO_CCL_10 , 0x6e },
+ { WCD9335_SIDO_SIDO_DRIVER_2 , 0x55 },
+ { WCD9335_SIDO_SIDO_DRIVER_3 , 0x55 },
+ { WCD9335_SIDO_SIDO_TEST_2 , 0x0f },
+ { WCD9335_MBHC_ZDET_ANA_CTL , 0x0f },
+ { WCD9335_TX_1_2_ATEST_REFCTL , 0x0a },
+ { WCD9335_TX_3_4_ATEST_REFCTL , 0x0a },
+ { WCD9335_TX_5_6_ATEST_REFCTL , 0x0a },
+ { WCD9335_FLYBACK_VNEG_CTRL_1 , 0xeb },
+ { WCD9335_FLYBACK_VNEG_CTRL_4 , 0x7f },
+ { WCD9335_FLYBACK_VNEG_CTRL_9 , 0x64 },
+ { WCD9335_FLYBACK_VNEG_DAC_CTRL_1 , 0xed },
+ { WCD9335_RX_BIAS_HPH_PA , 0x9a },
+ { WCD9335_RX_BIAS_HPH_LOWPOWER , 0x82 },
+ { WCD9335_HPH_PA_CTL2 , 0x50 },
+ { WCD9335_HPH_L_EN , 0x80 },
+ { WCD9335_HPH_R_EN , 0x80 },
+ { WCD9335_HPH_R_ATEST , 0x54 },
+ { WCD9335_HPH_RDAC_LDO_CTL , 0x33 },
+ { WCD9335_CDC_TX0_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX0_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_TX1_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX1_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_TX2_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX3_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX4_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX5_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX6_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX7_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX8_TX_PATH_CFG0 , 0x10 },
+ { WCD9335_CDC_TX2_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX3_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX4_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX5_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX6_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX7_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX8_TX_PATH_CFG1 , 0x02 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX3_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX4_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX5_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX6_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX7_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX8_TX_PATH_SEC2 , 0x01 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_TX3_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_TX4_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_TX5_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_TX6_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_TX7_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_TX8_TX_PATH_SEC3 , 0x3c },
+ { WCD9335_CDC_COMPANDER1_CTL7 , 0x08 },
+ { WCD9335_CDC_COMPANDER2_CTL7 , 0x08 },
+ { WCD9335_CDC_COMPANDER3_CTL7 , 0x08 },
+ { WCD9335_CDC_COMPANDER4_CTL7 , 0x08 },
+ { WCD9335_CDC_COMPANDER5_CTL7 , 0x08 },
+ { WCD9335_CDC_COMPANDER6_CTL7 , 0x08 },
+ { WCD9335_CDC_COMPANDER7_CTL7 , 0x08 },
+ { WCD9335_CDC_COMPANDER8_CTL7 , 0x08 },
+ { WCD9335_CDC_RX0_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX0_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX0_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX0_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX0_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_CDC_RX1_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX1_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX1_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX1_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX1_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_CDC_RX2_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX2_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX2_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX2_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX2_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_CDC_RX3_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX3_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX3_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX3_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX3_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_CDC_RX4_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX4_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX4_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX4_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX4_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_CDC_RX5_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX5_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX5_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX5_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX5_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_CDC_RX6_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX6_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX6_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX6_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX6_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_CDC_RX7_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX7_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX7_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX7_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX7_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_CDC_RX8_RX_PATH_CFG1 , 0x44 },
+ { WCD9335_CDC_RX8_RX_PATH_MIX_CFG , 0x1e },
+ { WCD9335_CDC_RX8_RX_PATH_SEC0 , 0xfc },
+ { WCD9335_CDC_RX8_RX_PATH_SEC1 , 0x08 },
+ { WCD9335_CDC_RX8_RX_PATH_MIX_SEC0 , 0x08 },
+ { WCD9335_SPLINE_SRC0_CLK_RST_CTL_0 , 0x20 },
+ { WCD9335_SPLINE_SRC1_CLK_RST_CTL_0 , 0x20 },
+ { WCD9335_SPLINE_SRC2_CLK_RST_CTL_0 , 0x20 },
+ { WCD9335_SPLINE_SRC3_CLK_RST_CTL_0 , 0x20 },
+ { WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL , 0x0c },
+ { WCD9335_TEST_DEBUG_NPL_DLY_TEST_1 , 0x10 },
+ { WCD9335_TEST_DEBUG_NPL_DLY_TEST_2 , 0x60 },
+ { WCD9335_DATA_HUB_NATIVE_FIFO_SYNC , 0x00 },
+ { WCD9335_DATA_HUB_NATIVE_FIFO_STATUS , 0x00 },
+ { WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD , 0x60 },
+ { WCD9335_CPE_SS_TX_PP_CFG , 0x3C },
+ { WCD9335_CPE_SS_SVA_CFG , 0x00 },
+ { WCD9335_MBHC_FSM_STATUS , 0x00 },
+ { WCD9335_FLYBACK_CTRL_1 , 0x45 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC7 , 0x25 },
+ { WCD9335_SPLINE_SRC0_STATUS , 0x00 },
+ { WCD9335_SPLINE_SRC1_STATUS , 0x00 },
+ { WCD9335_SPLINE_SRC2_STATUS , 0x00 },
+ { WCD9335_SPLINE_SRC3_STATUS , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT , 0x00 },
+};
+
+static const struct reg_default wcd9335_defaults[] = {
+ /* Page #0 registers */
+ { WCD9335_PAGE0_PAGE_REGISTER , 0x00 },
+ { WCD9335_CODEC_RPM_CLK_BYPASS , 0x00 },
+ { WCD9335_CODEC_RPM_CLK_MCLK_CFG , 0x00 },
+ { WCD9335_CODEC_RPM_RST_CTL , 0x00 },
+ { WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL , 0x07 },
+ { WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1 , 0x00 },
+ { WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2 , 0x00 },
+ { WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3 , 0x00 },
+ { WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN , 0x01 },
+ { WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1 , 0xff },
+ { WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2 , 0xff },
+ { WCD9335_CODEC_RPM_INT_MASK , 0x3f },
+ { WCD9335_CODEC_RPM_INT_STATUS , 0x00 },
+ { WCD9335_CODEC_RPM_INT_CLEAR , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2 , 0x07 },
+ { WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3 , 0x01 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO , 0x0d },
+ { WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3 , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL , 0xCC },
+ { WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL , 0x06 },
+ { WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL , 0x06 },
+ { WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL , 0x06 },
+ { WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB , 0x00 },
+ { WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL , 0x0c },
+ { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL , 0x0c },
+ { WCD9335_DATA_HUB_DATA_HUB_I2S_CLK , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG , 0x00 },
+ { WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG , 0x00 },
+ { WCD9335_INTR_CFG , 0x00 },
+ { WCD9335_INTR_CLR_COMMIT , 0x00 },
+ { WCD9335_INTR_PIN1_MASK0 , 0xff },
+ { WCD9335_INTR_PIN1_MASK1 , 0xff },
+ { WCD9335_INTR_PIN1_MASK2 , 0xff },
+ { WCD9335_INTR_PIN1_MASK3 , 0xff },
+ { WCD9335_INTR_PIN1_STATUS0 , 0x00 },
+ { WCD9335_INTR_PIN1_STATUS1 , 0x00 },
+ { WCD9335_INTR_PIN1_STATUS2 , 0x00 },
+ { WCD9335_INTR_PIN1_STATUS3 , 0x00 },
+ { WCD9335_INTR_PIN1_CLEAR0 , 0x00 },
+ { WCD9335_INTR_PIN1_CLEAR1 , 0x00 },
+ { WCD9335_INTR_PIN1_CLEAR2 , 0x00 },
+ { WCD9335_INTR_PIN1_CLEAR3 , 0x00 },
+ { WCD9335_INTR_PIN2_MASK0 , 0xff },
+ { WCD9335_INTR_PIN2_MASK1 , 0xff },
+ { WCD9335_INTR_PIN2_MASK2 , 0xff },
+ { WCD9335_INTR_PIN2_MASK3 , 0xff },
+ { WCD9335_INTR_PIN2_STATUS0 , 0x00 },
+ { WCD9335_INTR_PIN2_STATUS1 , 0x00 },
+ { WCD9335_INTR_PIN2_STATUS2 , 0x00 },
+ { WCD9335_INTR_PIN2_STATUS3 , 0x00 },
+ { WCD9335_INTR_PIN2_CLEAR0 , 0x00 },
+ { WCD9335_INTR_PIN2_CLEAR1 , 0x00 },
+ { WCD9335_INTR_PIN2_CLEAR2 , 0x00 },
+ { WCD9335_INTR_PIN2_CLEAR3 , 0x00 },
+ { WCD9335_INTR_LEVEL0 , 0x03 },
+ { WCD9335_INTR_LEVEL1 , 0xe0 },
+ { WCD9335_INTR_LEVEL2 , 0x10 },
+ { WCD9335_INTR_LEVEL3 , 0x80 },
+ { WCD9335_INTR_BYPASS0 , 0x00 },
+ { WCD9335_INTR_BYPASS1 , 0x00 },
+ { WCD9335_INTR_BYPASS2 , 0x00 },
+ { WCD9335_INTR_BYPASS3 , 0x00 },
+ { WCD9335_INTR_SET0 , 0x00 },
+ { WCD9335_INTR_SET1 , 0x00 },
+ { WCD9335_INTR_SET2 , 0x00 },
+ { WCD9335_INTR_SET3 , 0x00 },
+ /* Page #1 registers */
+ { WCD9335_PAGE1_PAGE_REGISTER , 0x00 },
+ { WCD9335_CPE_FLL_USER_CTL_0 , 0x71 },
+ { WCD9335_CPE_FLL_USER_CTL_1 , 0x34 },
+ { WCD9335_CPE_FLL_USER_CTL_2 , 0x0b },
+ { WCD9335_CPE_FLL_USER_CTL_3 , 0x02 },
+ { WCD9335_CPE_FLL_USER_CTL_4 , 0x04 },
+ { WCD9335_CPE_FLL_USER_CTL_5 , 0x02 },
+ { WCD9335_CPE_FLL_USER_CTL_6 , 0x64 },
+ { WCD9335_CPE_FLL_USER_CTL_7 , 0x00 },
+ { WCD9335_CPE_FLL_USER_CTL_8 , 0x94 },
+ { WCD9335_CPE_FLL_USER_CTL_9 , 0x70 },
+ { WCD9335_CPE_FLL_L_VAL_CTL_0 , 0x40 },
+ { WCD9335_CPE_FLL_L_VAL_CTL_1 , 0x00 },
+ { WCD9335_CPE_FLL_DSM_FRAC_CTL_0 , 0x00 },
+ { WCD9335_CPE_FLL_DSM_FRAC_CTL_1 , 0xff },
+ { WCD9335_CPE_FLL_CONFIG_CTL_0 , 0x6b },
+ { WCD9335_CPE_FLL_CONFIG_CTL_1 , 0x05 },
+ { WCD9335_CPE_FLL_CONFIG_CTL_2 , 0x08 },
+ { WCD9335_CPE_FLL_CONFIG_CTL_3 , 0x00 },
+ { WCD9335_CPE_FLL_CONFIG_CTL_4 , 0x10 },
+ { WCD9335_CPE_FLL_TEST_CTL_0 , 0x00 },
+ { WCD9335_CPE_FLL_TEST_CTL_1 , 0x00 },
+ { WCD9335_CPE_FLL_TEST_CTL_2 , 0x00 },
+ { WCD9335_CPE_FLL_TEST_CTL_3 , 0x00 },
+ { WCD9335_CPE_FLL_TEST_CTL_4 , 0x00 },
+ { WCD9335_CPE_FLL_TEST_CTL_5 , 0x00 },
+ { WCD9335_CPE_FLL_TEST_CTL_6 , 0x00 },
+ { WCD9335_CPE_FLL_TEST_CTL_7 , 0x33 },
+ { WCD9335_CPE_FLL_FREQ_CTL_0 , 0x00 },
+ { WCD9335_CPE_FLL_FREQ_CTL_1 , 0x00 },
+ { WCD9335_CPE_FLL_FREQ_CTL_2 , 0x00 },
+ { WCD9335_CPE_FLL_FREQ_CTL_3 , 0x00 },
+ { WCD9335_CPE_FLL_SSC_CTL_0 , 0x00 },
+ { WCD9335_CPE_FLL_SSC_CTL_1 , 0x00 },
+ { WCD9335_CPE_FLL_SSC_CTL_2 , 0x00 },
+ { WCD9335_CPE_FLL_SSC_CTL_3 , 0x00 },
+ { WCD9335_CPE_FLL_FLL_MODE , 0x20 },
+ { WCD9335_CPE_FLL_STATUS_0 , 0x00 },
+ { WCD9335_CPE_FLL_STATUS_1 , 0x00 },
+ { WCD9335_CPE_FLL_STATUS_2 , 0x00 },
+ { WCD9335_CPE_FLL_STATUS_3 , 0x00 },
+ { WCD9335_I2S_FLL_USER_CTL_0 , 0x41 },
+ { WCD9335_I2S_FLL_USER_CTL_1 , 0x94 },
+ { WCD9335_I2S_FLL_USER_CTL_2 , 0x08 },
+ { WCD9335_I2S_FLL_USER_CTL_3 , 0x02 },
+ { WCD9335_I2S_FLL_USER_CTL_4 , 0x04 },
+ { WCD9335_I2S_FLL_USER_CTL_5 , 0x02 },
+ { WCD9335_I2S_FLL_USER_CTL_6 , 0x40 },
+ { WCD9335_I2S_FLL_USER_CTL_7 , 0x00 },
+ { WCD9335_I2S_FLL_USER_CTL_8 , 0x5f },
+ { WCD9335_I2S_FLL_USER_CTL_9 , 0x02 },
+ { WCD9335_I2S_FLL_L_VAL_CTL_0 , 0x40 },
+ { WCD9335_I2S_FLL_L_VAL_CTL_1 , 0x00 },
+ { WCD9335_I2S_FLL_DSM_FRAC_CTL_0 , 0x00 },
+ { WCD9335_I2S_FLL_DSM_FRAC_CTL_1 , 0xff },
+ { WCD9335_I2S_FLL_CONFIG_CTL_0 , 0x6b },
+ { WCD9335_I2S_FLL_CONFIG_CTL_1 , 0x05 },
+ { WCD9335_I2S_FLL_CONFIG_CTL_2 , 0x08 },
+ { WCD9335_I2S_FLL_CONFIG_CTL_3 , 0x00 },
+ { WCD9335_I2S_FLL_CONFIG_CTL_4 , 0x30 },
+ { WCD9335_I2S_FLL_TEST_CTL_0 , 0x80 },
+ { WCD9335_I2S_FLL_TEST_CTL_1 , 0x00 },
+ { WCD9335_I2S_FLL_TEST_CTL_2 , 0x00 },
+ { WCD9335_I2S_FLL_TEST_CTL_3 , 0x00 },
+ { WCD9335_I2S_FLL_TEST_CTL_4 , 0x00 },
+ { WCD9335_I2S_FLL_TEST_CTL_5 , 0x00 },
+ { WCD9335_I2S_FLL_TEST_CTL_6 , 0x00 },
+ { WCD9335_I2S_FLL_TEST_CTL_7 , 0xff },
+ { WCD9335_I2S_FLL_FREQ_CTL_0 , 0x00 },
+ { WCD9335_I2S_FLL_FREQ_CTL_1 , 0x00 },
+ { WCD9335_I2S_FLL_FREQ_CTL_2 , 0x00 },
+ { WCD9335_I2S_FLL_FREQ_CTL_3 , 0x00 },
+ { WCD9335_I2S_FLL_SSC_CTL_0 , 0x00 },
+ { WCD9335_I2S_FLL_SSC_CTL_1 , 0x00 },
+ { WCD9335_I2S_FLL_SSC_CTL_2 , 0x00 },
+ { WCD9335_I2S_FLL_SSC_CTL_3 , 0x00 },
+ { WCD9335_I2S_FLL_FLL_MODE , 0x00 },
+ { WCD9335_I2S_FLL_STATUS_0 , 0x00 },
+ { WCD9335_I2S_FLL_STATUS_1 , 0x00 },
+ { WCD9335_I2S_FLL_STATUS_2 , 0x00 },
+ { WCD9335_I2S_FLL_STATUS_3 , 0x00 },
+ { WCD9335_SB_FLL_USER_CTL_0 , 0x41 },
+ { WCD9335_SB_FLL_USER_CTL_1 , 0x94 },
+ { WCD9335_SB_FLL_USER_CTL_2 , 0x08 },
+ { WCD9335_SB_FLL_USER_CTL_3 , 0x02 },
+ { WCD9335_SB_FLL_USER_CTL_4 , 0x04 },
+ { WCD9335_SB_FLL_USER_CTL_5 , 0x02 },
+ { WCD9335_SB_FLL_USER_CTL_6 , 0x40 },
+ { WCD9335_SB_FLL_USER_CTL_7 , 0x00 },
+ { WCD9335_SB_FLL_USER_CTL_8 , 0x5e },
+ { WCD9335_SB_FLL_USER_CTL_9 , 0x01 },
+ { WCD9335_SB_FLL_L_VAL_CTL_0 , 0x40 },
+ { WCD9335_SB_FLL_L_VAL_CTL_1 , 0x00 },
+ { WCD9335_SB_FLL_DSM_FRAC_CTL_0 , 0x00 },
+ { WCD9335_SB_FLL_DSM_FRAC_CTL_1 , 0xff },
+ { WCD9335_SB_FLL_CONFIG_CTL_0 , 0x6b },
+ { WCD9335_SB_FLL_CONFIG_CTL_1 , 0x05 },
+ { WCD9335_SB_FLL_CONFIG_CTL_2 , 0x08 },
+ { WCD9335_SB_FLL_CONFIG_CTL_3 , 0x00 },
+ { WCD9335_SB_FLL_CONFIG_CTL_4 , 0x10 },
+ { WCD9335_SB_FLL_TEST_CTL_0 , 0x00 },
+ { WCD9335_SB_FLL_TEST_CTL_1 , 0x00 },
+ { WCD9335_SB_FLL_TEST_CTL_2 , 0x00 },
+ { WCD9335_SB_FLL_TEST_CTL_3 , 0x00 },
+ { WCD9335_SB_FLL_TEST_CTL_4 , 0x00 },
+ { WCD9335_SB_FLL_TEST_CTL_5 , 0x00 },
+ { WCD9335_SB_FLL_TEST_CTL_6 , 0x00 },
+ { WCD9335_SB_FLL_TEST_CTL_7 , 0xff },
+ { WCD9335_SB_FLL_FREQ_CTL_0 , 0x00 },
+ { WCD9335_SB_FLL_FREQ_CTL_1 , 0x00 },
+ { WCD9335_SB_FLL_FREQ_CTL_2 , 0x00 },
+ { WCD9335_SB_FLL_FREQ_CTL_3 , 0x00 },
+ { WCD9335_SB_FLL_SSC_CTL_0 , 0x00 },
+ { WCD9335_SB_FLL_SSC_CTL_1 , 0x00 },
+ { WCD9335_SB_FLL_SSC_CTL_2 , 0x00 },
+ { WCD9335_SB_FLL_SSC_CTL_3 , 0x00 },
+ { WCD9335_SB_FLL_FLL_MODE , 0x00 },
+ { WCD9335_SB_FLL_STATUS_0 , 0x00 },
+ { WCD9335_SB_FLL_STATUS_1 , 0x00 },
+ { WCD9335_SB_FLL_STATUS_2 , 0x00 },
+ { WCD9335_SB_FLL_STATUS_3 , 0x00 },
+ /* Page #2 registers */
+ { WCD9335_PAGE2_PAGE_REGISTER , 0x00 },
+ { WCD9335_CPE_SS_MEM_PTR_0 , 0x00 },
+ { WCD9335_CPE_SS_MEM_PTR_1 , 0x00 },
+ { WCD9335_CPE_SS_MEM_PTR_2 , 0x00 },
+ { WCD9335_CPE_SS_MEM_CTRL , 0x08 },
+ { WCD9335_CPE_SS_MEM_BANK_0 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_1 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_2 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_3 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_4 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_5 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_6 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_7 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_8 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_9 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_10 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_11 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_12 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_13 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_14 , 0x00 },
+ { WCD9335_CPE_SS_MEM_BANK_15 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_TRG , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_TRG , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_0 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_1 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_2 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_3 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_4 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_5 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_6 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_7 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_8 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_9 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_10 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_11 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_12 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_13 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_14 , 0x00 },
+ { WCD9335_CPE_SS_INBOX1_15 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_0 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_1 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_2 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_3 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_4 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_5 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_6 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_7 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_8 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_9 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_10 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_11 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_12 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_13 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_14 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_15 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_0 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_1 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_2 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_3 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_4 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_5 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_6 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_7 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_8 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_9 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_10 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_11 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_12 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_13 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_14 , 0x00 },
+ { WCD9335_CPE_SS_INBOX2_15 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_0 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_1 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_2 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_3 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_4 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_5 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_6 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_7 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_8 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_9 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_10 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_11 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_12 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_13 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_14 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_15 , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX1_ACK , 0x00 },
+ { WCD9335_CPE_SS_OUTBOX2_ACK , 0x00 },
+ { WCD9335_CPE_SS_EC_BUF_INT_PERIOD , 0x3c },
+ { WCD9335_CPE_SS_US_BUF_INT_PERIOD , 0x60 },
+ { WCD9335_CPE_SS_CFG , 0x41 },
+ { WCD9335_CPE_SS_US_EC_MUX_CFG , 0x00 },
+ { WCD9335_CPE_SS_MAD_CTL , 0x00 },
+ { WCD9335_CPE_SS_CPAR_CTL , 0x00 },
+ { WCD9335_CPE_SS_DMIC0_CTL , 0x00 },
+ { WCD9335_CPE_SS_DMIC1_CTL , 0x00 },
+ { WCD9335_CPE_SS_DMIC2_CTL , 0x00 },
+ { WCD9335_CPE_SS_DMIC_CFG , 0x80 },
+ { WCD9335_CPE_SS_CPAR_CFG , 0x00 },
+ { WCD9335_CPE_SS_WDOG_CFG , 0x01 },
+ { WCD9335_CPE_SS_BACKUP_INT , 0x00 },
+ { WCD9335_CPE_SS_STATUS , 0x00 },
+ { WCD9335_CPE_SS_CPE_OCD_CFG , 0x00 },
+ { WCD9335_CPE_SS_SS_ERROR_INT_STATUS , 0x00 },
+ { WCD9335_CPE_SS_SS_ERROR_INT_CLEAR , 0x00 },
+ { WCD9335_SOC_MAD_MAIN_CTL_1 , 0x00 },
+ { WCD9335_SOC_MAD_MAIN_CTL_2 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_CTL_1 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_CTL_2 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_CTL_3 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_CTL_4 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_CTL_5 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_CTL_6 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_CTL_7 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_CTL_8 , 0x00 },
+ { WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR , 0x00 },
+ { WCD9335_SOC_MAD_ULTR_CTL_1 , 0x00 },
+ { WCD9335_SOC_MAD_ULTR_CTL_2 , 0x00 },
+ { WCD9335_SOC_MAD_ULTR_CTL_3 , 0x00 },
+ { WCD9335_SOC_MAD_ULTR_CTL_4 , 0x00 },
+ { WCD9335_SOC_MAD_ULTR_CTL_5 , 0x00 },
+ { WCD9335_SOC_MAD_ULTR_CTL_6 , 0x00 },
+ { WCD9335_SOC_MAD_ULTR_CTL_7 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_CTL_1 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_CTL_2 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_CTL_3 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_CTL_4 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_CTL_5 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_CTL_6 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_CTL_7 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_CTL_8 , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR , 0x00 },
+ { WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL , 0x00 },
+ { WCD9335_SOC_MAD_INP_SEL , 0x00 },
+ /* Page #6 registers */
+ { WCD9335_PAGE6_PAGE_REGISTER , 0x00 },
+ { WCD9335_ANA_BIAS , 0x00 },
+ { WCD9335_ANA_CLK_TOP , 0x00 },
+ { WCD9335_ANA_RCO , 0x30 },
+ { WCD9335_ANA_BUCK_VOUT_A , 0xb4 },
+ { WCD9335_ANA_BUCK_VOUT_D , 0xb4 },
+ { WCD9335_ANA_BUCK_CTL , 0x00 },
+ { WCD9335_ANA_BUCK_STATUS , 0xe0 },
+ { WCD9335_ANA_RX_SUPPLIES , 0x00 },
+ { WCD9335_ANA_HPH , 0x00 },
+ { WCD9335_ANA_EAR , 0x00 },
+ { WCD9335_ANA_LO_1_2 , 0x00 },
+ { WCD9335_ANA_LO_3_4 , 0x00 },
+ { WCD9335_ANA_MAD_SETUP , 0x81 },
+ { WCD9335_ANA_AMIC1 , 0x20 },
+ { WCD9335_ANA_AMIC2 , 0x00 },
+ { WCD9335_ANA_AMIC3 , 0x20 },
+ { WCD9335_ANA_AMIC4 , 0x00 },
+ { WCD9335_ANA_AMIC5 , 0x20 },
+ { WCD9335_ANA_AMIC6 , 0x00 },
+ { WCD9335_ANA_MBHC_MECH , 0x39 },
+ { WCD9335_ANA_MBHC_ELECT , 0x08 },
+ { WCD9335_ANA_MBHC_ZDET , 0x00 },
+ { WCD9335_ANA_MBHC_RESULT_1 , 0x00 },
+ { WCD9335_ANA_MBHC_RESULT_2 , 0x00 },
+ { WCD9335_ANA_MBHC_RESULT_3 , 0x00 },
+ { WCD9335_ANA_MBHC_BTN0 , 0x00 },
+ { WCD9335_ANA_MBHC_BTN1 , 0x10 },
+ { WCD9335_ANA_MBHC_BTN2 , 0x20 },
+ { WCD9335_ANA_MBHC_BTN3 , 0x30 },
+ { WCD9335_ANA_MBHC_BTN4 , 0x40 },
+ { WCD9335_ANA_MBHC_BTN5 , 0x50 },
+ { WCD9335_ANA_MBHC_BTN6 , 0x60 },
+ { WCD9335_ANA_MBHC_BTN7 , 0x70 },
+ { WCD9335_ANA_MICB1 , 0x10 },
+ { WCD9335_ANA_MICB2 , 0x10 },
+ { WCD9335_ANA_MICB2_RAMP , 0x00 },
+ { WCD9335_ANA_MICB3 , 0x10 },
+ { WCD9335_ANA_MICB4 , 0x10 },
+ { WCD9335_ANA_VBADC , 0x00 },
+ { WCD9335_BIAS_CTL , 0x28 },
+ { WCD9335_CLOCK_TEST_CTL , 0x00 },
+ { WCD9335_RCO_CTRL_1 , 0x44 },
+ { WCD9335_RCO_CTRL_2 , 0x44 },
+ { WCD9335_RCO_CAL , 0x00 },
+ { WCD9335_RCO_CAL_1 , 0x00 },
+ { WCD9335_RCO_CAL_2 , 0x00 },
+ { WCD9335_RCO_TEST_CTRL , 0x00 },
+ { WCD9335_RCO_CAL_OUT_1 , 0x00 },
+ { WCD9335_RCO_CAL_OUT_2 , 0x00 },
+ { WCD9335_RCO_CAL_OUT_3 , 0x00 },
+ { WCD9335_RCO_CAL_OUT_4 , 0x00 },
+ { WCD9335_RCO_CAL_OUT_5 , 0x00 },
+ { WCD9335_SIDO_SIDO_MODE_1 , 0x84 },
+ { WCD9335_SIDO_SIDO_MODE_2 , 0xfe },
+ { WCD9335_SIDO_SIDO_MODE_3 , 0xf6 },
+ { WCD9335_SIDO_SIDO_MODE_4 , 0x56 },
+ { WCD9335_SIDO_SIDO_VCL_1 , 0x00 },
+ { WCD9335_SIDO_SIDO_VCL_2 , 0x6c },
+ { WCD9335_SIDO_SIDO_VCL_3 , 0x44 },
+ { WCD9335_SIDO_SIDO_CCL_1 , 0x57 },
+ { WCD9335_SIDO_SIDO_CCL_4 , 0x61 },
+ { WCD9335_SIDO_SIDO_CCL_5 , 0x6d },
+ { WCD9335_SIDO_SIDO_CCL_6 , 0x60 },
+ { WCD9335_SIDO_SIDO_CCL_7 , 0x6f },
+ { WCD9335_SIDO_SIDO_CCL_9 , 0x6e },
+ { WCD9335_SIDO_SIDO_FILTER_1 , 0x92 },
+ { WCD9335_SIDO_SIDO_FILTER_2 , 0x54 },
+ { WCD9335_SIDO_SIDO_DRIVER_1 , 0x77 },
+ { WCD9335_SIDO_SIDO_CAL_CODE_EXT_1 , 0x9c },
+ { WCD9335_SIDO_SIDO_CAL_CODE_EXT_2 , 0x82 },
+ { WCD9335_SIDO_SIDO_CAL_CODE_OUT_1 , 0x00 },
+ { WCD9335_SIDO_SIDO_CAL_CODE_OUT_2 , 0x00 },
+ { WCD9335_SIDO_SIDO_TEST_1 , 0x00 },
+ { WCD9335_MBHC_CTL_1 , 0x32 },
+ { WCD9335_MBHC_CTL_2 , 0x01 },
+ { WCD9335_MBHC_PLUG_DETECT_CTL , 0x69 },
+ { WCD9335_MBHC_ZDET_RAMP_CTL , 0x00 },
+ { WCD9335_MBHC_TEST_CTL , 0x00 },
+ { WCD9335_VBADC_SUBBLOCK_EN , 0xfe },
+ { WCD9335_VBADC_IBIAS_FE , 0x54 },
+ { WCD9335_VBADC_BIAS_ADC , 0x51 },
+ { WCD9335_VBADC_FE_CTRL , 0x1c },
+ { WCD9335_VBADC_ADC_REF , 0x20 },
+ { WCD9335_VBADC_ADC_IO , 0x80 },
+ { WCD9335_VBADC_ADC_SAR , 0xff },
+ { WCD9335_VBADC_DEBUG , 0x00 },
+ { WCD9335_VBADC_ADC_DOUTMSB , 0x00 },
+ { WCD9335_VBADC_ADC_DOUTLSB , 0x00 },
+ { WCD9335_LDOH_MODE , 0x2b },
+ { WCD9335_LDOH_BIAS , 0x68 },
+ { WCD9335_LDOH_STB_LOADS , 0x00 },
+ { WCD9335_LDOH_SLOWRAMP , 0x50 },
+ { WCD9335_MICB1_TEST_CTL_1 , 0x1a },
+ { WCD9335_MICB1_TEST_CTL_2 , 0x18 },
+ { WCD9335_MICB1_TEST_CTL_3 , 0xa4 },
+ { WCD9335_MICB2_TEST_CTL_1 , 0x1a },
+ { WCD9335_MICB2_TEST_CTL_2 , 0x18 },
+ { WCD9335_MICB2_TEST_CTL_3 , 0x24 },
+ { WCD9335_MICB3_TEST_CTL_1 , 0x1a },
+ { WCD9335_MICB3_TEST_CTL_2 , 0x18 },
+ { WCD9335_MICB3_TEST_CTL_3 , 0xa4 },
+ { WCD9335_MICB4_TEST_CTL_1 , 0x1a },
+ { WCD9335_MICB4_TEST_CTL_2 , 0x18 },
+ { WCD9335_MICB4_TEST_CTL_3 , 0xa4 },
+ { WCD9335_TX_COM_ADC_VCM , 0x39 },
+ { WCD9335_TX_COM_BIAS_ATEST , 0xc0 },
+ { WCD9335_TX_COM_ADC_INT1_IB , 0x6f },
+ { WCD9335_TX_COM_ADC_INT2_IB , 0x4f },
+ { WCD9335_TX_COM_TXFE_DIV_CTL , 0x2e },
+ { WCD9335_TX_COM_TXFE_DIV_START , 0x00 },
+ { WCD9335_TX_COM_TXFE_DIV_STOP_9P6M , 0xc7 },
+ { WCD9335_TX_COM_TXFE_DIV_STOP_12P288M , 0xff },
+ { WCD9335_TX_1_2_TEST_EN , 0xcc },
+ { WCD9335_TX_1_2_ADC_IB , 0x09 },
+ { WCD9335_TX_1_2_TEST_CTL , 0x38 },
+ { WCD9335_TX_1_2_TEST_BLK_EN , 0xff },
+ { WCD9335_TX_1_2_TXFE_CLKDIV , 0x00 },
+ { WCD9335_TX_1_2_SAR1_ERR , 0x00 },
+ { WCD9335_TX_1_2_SAR2_ERR , 0x00 },
+ { WCD9335_TX_3_4_TEST_EN , 0xcc },
+ { WCD9335_TX_3_4_ADC_IB , 0x09 },
+ { WCD9335_TX_3_4_TEST_CTL , 0x38 },
+ { WCD9335_TX_3_4_TEST_BLK_EN , 0xff },
+ { WCD9335_TX_3_4_TXFE_CLKDIV , 0x00 },
+ { WCD9335_TX_3_4_SAR1_ERR , 0x00 },
+ { WCD9335_TX_3_4_SAR2_ERR , 0x00 },
+ { WCD9335_TX_5_6_TEST_EN , 0xcc },
+ { WCD9335_TX_5_6_ADC_IB , 0x09 },
+ { WCD9335_TX_5_6_TEST_CTL , 0x38 },
+ { WCD9335_TX_5_6_TEST_BLK_EN , 0xff },
+ { WCD9335_TX_5_6_TXFE_CLKDIV , 0x00 },
+ { WCD9335_TX_5_6_SAR1_ERR , 0x00 },
+ { WCD9335_TX_5_6_SAR2_ERR , 0x00 },
+ { WCD9335_CLASSH_MODE_1 , 0x40 },
+ { WCD9335_CLASSH_MODE_2 , 0x3a },
+ { WCD9335_CLASSH_MODE_3 , 0x00 },
+ { WCD9335_CLASSH_CTRL_VCL_1 , 0x70 },
+ { WCD9335_CLASSH_CTRL_VCL_2 , 0xa2 },
+ { WCD9335_CLASSH_CTRL_CCL_1 , 0x51 },
+ { WCD9335_CLASSH_CTRL_CCL_2 , 0x80 },
+ { WCD9335_CLASSH_CTRL_CCL_3 , 0x80 },
+ { WCD9335_CLASSH_CTRL_CCL_4 , 0x51 },
+ { WCD9335_CLASSH_CTRL_CCL_5 , 0x00 },
+ { WCD9335_CLASSH_BUCK_TMUX_A_D , 0x00 },
+ { WCD9335_CLASSH_BUCK_SW_DRV_CNTL , 0x77 },
+ { WCD9335_CLASSH_SPARE , 0x00 },
+ { WCD9335_FLYBACK_EN , 0x4e },
+ { WCD9335_FLYBACK_VNEG_CTRL_2 , 0x45 },
+ { WCD9335_FLYBACK_VNEG_CTRL_3 , 0x74 },
+ { WCD9335_FLYBACK_VNEG_CTRL_5 , 0x83 },
+ { WCD9335_FLYBACK_VNEG_CTRL_6 , 0x98 },
+ { WCD9335_FLYBACK_VNEG_CTRL_7 , 0xa9 },
+ { WCD9335_FLYBACK_VNEG_CTRL_8 , 0x68 },
+ { WCD9335_FLYBACK_VNEG_DAC_CTRL_2 , 0x50 },
+ { WCD9335_FLYBACK_VNEG_DAC_CTRL_3 , 0xa6 },
+ { WCD9335_FLYBACK_TEST_CTL , 0x00 },
+ { WCD9335_RX_AUX_SW_CTL , 0x00 },
+ { WCD9335_RX_PA_AUX_IN_CONN , 0x00 },
+ { WCD9335_RX_TIMER_DIV , 0x74 },
+ { WCD9335_RX_OCP_CTL , 0x1f },
+ { WCD9335_RX_OCP_COUNT , 0x77 },
+ { WCD9335_RX_BIAS_EAR_DAC , 0xa0 },
+ { WCD9335_RX_BIAS_EAR_AMP , 0xaa },
+ { WCD9335_RX_BIAS_HPH_LDO , 0xa9 },
+ { WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2 , 0x8a },
+ { WCD9335_RX_BIAS_HPH_RDAC_LDO , 0x88 },
+ { WCD9335_RX_BIAS_HPH_CNP1 , 0x86 },
+ { WCD9335_RX_BIAS_DIFFLO_PA , 0x80 },
+ { WCD9335_RX_BIAS_DIFFLO_REF , 0x88 },
+ { WCD9335_RX_BIAS_DIFFLO_LDO , 0x88 },
+ { WCD9335_RX_BIAS_SELO_DAC_PA , 0xa8 },
+ { WCD9335_RX_BIAS_BUCK_RST , 0x08 },
+ { WCD9335_RX_BIAS_BUCK_VREF_ERRAMP , 0x44 },
+ { WCD9335_RX_BIAS_FLYB_ERRAMP , 0x40 },
+ { WCD9335_RX_BIAS_FLYB_BUFF , 0xaa },
+ { WCD9335_RX_BIAS_FLYB_MID_RST , 0x44 },
+ { WCD9335_HPH_L_STATUS , 0x04 },
+ { WCD9335_HPH_R_STATUS , 0x04 },
+ { WCD9335_HPH_CNP_EN , 0x80 },
+ { WCD9335_HPH_CNP_WG_CTL , 0xda },
+ { WCD9335_HPH_CNP_WG_TIME , 0x15 },
+ { WCD9335_HPH_OCP_CTL , 0x28 },
+ { WCD9335_HPH_AUTO_CHOP , 0x12 },
+ { WCD9335_HPH_CHOP_CTL , 0x83 },
+ { WCD9335_HPH_PA_CTL1 , 0x46 },
+ { WCD9335_HPH_L_TEST , 0x00 },
+ { WCD9335_HPH_L_ATEST , 0x50 },
+ { WCD9335_HPH_R_TEST , 0x00 },
+ { WCD9335_HPH_RDAC_CLK_CTL1 , 0x99 },
+ { WCD9335_HPH_RDAC_CLK_CTL2 , 0x9b },
+ { WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL , 0x00 },
+ { WCD9335_HPH_REFBUFF_UHQA_CTL , 0xa8 },
+ { WCD9335_HPH_REFBUFF_LP_CTL , 0x00 },
+ { WCD9335_HPH_L_DAC_CTL , 0x00 },
+ { WCD9335_HPH_R_DAC_CTL , 0x00 },
+ { WCD9335_EAR_EN_REG , 0x60 },
+ { WCD9335_EAR_CMBUFF , 0x0d },
+ { WCD9335_EAR_ICTL , 0x40 },
+ { WCD9335_EAR_EN_DBG_CTL , 0x00 },
+ { WCD9335_EAR_CNP , 0xe0 },
+ { WCD9335_EAR_DAC_CTL_ATEST , 0x00 },
+ { WCD9335_EAR_STATUS_REG , 0x04 },
+ { WCD9335_EAR_OUT_SHORT , 0x00 },
+ { WCD9335_DIFF_LO_MISC , 0x03 },
+ { WCD9335_DIFF_LO_LO2_COMPANDER , 0x00 },
+ { WCD9335_DIFF_LO_LO1_COMPANDER , 0x00 },
+ { WCD9335_DIFF_LO_COMMON , 0x40 },
+ { WCD9335_DIFF_LO_BYPASS_EN , 0x00 },
+ { WCD9335_DIFF_LO_CNP , 0x20 },
+ { WCD9335_DIFF_LO_CORE_OUT_PROG , 0x00 },
+ { WCD9335_DIFF_LO_LDO_OUT_PROG , 0x00 },
+ { WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ , 0x9b },
+ { WCD9335_DIFF_LO_COM_PA_FREQ , 0xb0 },
+ { WCD9335_DIFF_LO_RESERVED_REG , 0x60 },
+ { WCD9335_DIFF_LO_LO1_STATUS_1 , 0x00 },
+ { WCD9335_DIFF_LO_LO1_STATUS_2 , 0x00 },
+ { WCD9335_SE_LO_COM1 , 0x80 },
+ { WCD9335_SE_LO_COM2 , 0x04 },
+ { WCD9335_SE_LO_LO3_GAIN , 0x20 },
+ { WCD9335_SE_LO_LO3_CTRL , 0x04 },
+ { WCD9335_SE_LO_LO4_GAIN , 0x20 },
+ { WCD9335_SE_LO_LO4_CTRL , 0x04 },
+ { WCD9335_SE_LO_LO3_STATUS , 0x00 },
+ { WCD9335_SE_LO_LO4_STATUS , 0x00 },
+ /* Page #10 registers */
+ { WCD9335_PAGE10_PAGE_REGISTER , 0x00 },
+ { WCD9335_CDC_ANC0_CLK_RESET_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_MODE_1_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_MODE_2_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_FF_SHIFT , 0x00 },
+ { WCD9335_CDC_ANC0_FB_SHIFT , 0x00 },
+ { WCD9335_CDC_ANC0_LPF_FF_A_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_LPF_FF_B_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_LPF_FB_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_SMLPF_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_IIR_ADAPT_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_IIR_COEFF_1_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_IIR_COEFF_2_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_FF_A_GAIN_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_FF_B_GAIN_CTL , 0x00 },
+ { WCD9335_CDC_ANC0_FB_GAIN_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_CLK_RESET_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_MODE_1_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_MODE_2_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_FF_SHIFT , 0x00 },
+ { WCD9335_CDC_ANC1_FB_SHIFT , 0x00 },
+ { WCD9335_CDC_ANC1_LPF_FF_A_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_LPF_FF_B_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_LPF_FB_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_SMLPF_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_IIR_ADAPT_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_IIR_COEFF_1_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_IIR_COEFF_2_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_FF_A_GAIN_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_FF_B_GAIN_CTL , 0x00 },
+ { WCD9335_CDC_ANC1_FB_GAIN_CTL , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX0_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX0_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX1_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX1_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX2_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX2_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX3_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX3_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX3_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX4_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX4_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX4_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX5_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX5_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX5_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX6_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX6_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX6_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX7_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX7_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX7_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_TX8_TX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_192_CTL , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_192_CFG , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_SEC0 , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_SEC1 , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_SEC4 , 0x20 },
+ { WCD9335_CDC_TX8_TX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_TX8_TX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL , 0x02 },
+ { WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL , 0x02 },
+ { WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL , 0x02 },
+ { WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL , 0x02 },
+ { WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0 , 0x00 },
+ /* Page #11 registers */
+ { WCD9335_PAGE11_PAGE_REGISTER , 0x00 },
+ { WCD9335_CDC_COMPANDER1_CTL0 , 0x60 },
+ { WCD9335_CDC_COMPANDER1_CTL1 , 0xdb },
+ { WCD9335_CDC_COMPANDER1_CTL2 , 0xff },
+ { WCD9335_CDC_COMPANDER1_CTL3 , 0x35 },
+ { WCD9335_CDC_COMPANDER1_CTL4 , 0xff },
+ { WCD9335_CDC_COMPANDER1_CTL5 , 0x00 },
+ { WCD9335_CDC_COMPANDER1_CTL6 , 0x01 },
+ { WCD9335_CDC_COMPANDER2_CTL0 , 0x60 },
+ { WCD9335_CDC_COMPANDER2_CTL1 , 0xdb },
+ { WCD9335_CDC_COMPANDER2_CTL2 , 0xff },
+ { WCD9335_CDC_COMPANDER2_CTL3 , 0x35 },
+ { WCD9335_CDC_COMPANDER2_CTL4 , 0xff },
+ { WCD9335_CDC_COMPANDER2_CTL5 , 0x00 },
+ { WCD9335_CDC_COMPANDER2_CTL6 , 0x01 },
+ { WCD9335_CDC_COMPANDER3_CTL0 , 0x60 },
+ { WCD9335_CDC_COMPANDER3_CTL1 , 0xdb },
+ { WCD9335_CDC_COMPANDER3_CTL2 , 0xff },
+ { WCD9335_CDC_COMPANDER3_CTL3 , 0x35 },
+ { WCD9335_CDC_COMPANDER3_CTL4 , 0xff },
+ { WCD9335_CDC_COMPANDER3_CTL5 , 0x00 },
+ { WCD9335_CDC_COMPANDER3_CTL6 , 0x01 },
+ { WCD9335_CDC_COMPANDER4_CTL0 , 0x60 },
+ { WCD9335_CDC_COMPANDER4_CTL1 , 0xdb },
+ { WCD9335_CDC_COMPANDER4_CTL2 , 0xff },
+ { WCD9335_CDC_COMPANDER4_CTL3 , 0x35 },
+ { WCD9335_CDC_COMPANDER4_CTL4 , 0xff },
+ { WCD9335_CDC_COMPANDER4_CTL5 , 0x00 },
+ { WCD9335_CDC_COMPANDER4_CTL6 , 0x01 },
+ { WCD9335_CDC_COMPANDER5_CTL0 , 0x60 },
+ { WCD9335_CDC_COMPANDER5_CTL1 , 0xdb },
+ { WCD9335_CDC_COMPANDER5_CTL2 , 0xff },
+ { WCD9335_CDC_COMPANDER5_CTL3 , 0x35 },
+ { WCD9335_CDC_COMPANDER5_CTL4 , 0xff },
+ { WCD9335_CDC_COMPANDER5_CTL5 , 0x00 },
+ { WCD9335_CDC_COMPANDER5_CTL6 , 0x01 },
+ { WCD9335_CDC_COMPANDER6_CTL0 , 0x60 },
+ { WCD9335_CDC_COMPANDER6_CTL1 , 0xdb },
+ { WCD9335_CDC_COMPANDER6_CTL2 , 0xff },
+ { WCD9335_CDC_COMPANDER6_CTL3 , 0x35 },
+ { WCD9335_CDC_COMPANDER6_CTL4 , 0xff },
+ { WCD9335_CDC_COMPANDER6_CTL5 , 0x00 },
+ { WCD9335_CDC_COMPANDER6_CTL6 , 0x01 },
+ { WCD9335_CDC_COMPANDER7_CTL0 , 0x60 },
+ { WCD9335_CDC_COMPANDER7_CTL1 , 0xdb },
+ { WCD9335_CDC_COMPANDER7_CTL2 , 0xff },
+ { WCD9335_CDC_COMPANDER7_CTL3 , 0x35 },
+ { WCD9335_CDC_COMPANDER7_CTL4 , 0xff },
+ { WCD9335_CDC_COMPANDER7_CTL5 , 0x00 },
+ { WCD9335_CDC_COMPANDER7_CTL6 , 0x01 },
+ { WCD9335_CDC_COMPANDER8_CTL0 , 0x60 },
+ { WCD9335_CDC_COMPANDER8_CTL1 , 0xdb },
+ { WCD9335_CDC_COMPANDER8_CTL2 , 0xff },
+ { WCD9335_CDC_COMPANDER8_CTL3 , 0x35 },
+ { WCD9335_CDC_COMPANDER8_CTL4 , 0xff },
+ { WCD9335_CDC_COMPANDER8_CTL5 , 0x00 },
+ { WCD9335_CDC_COMPANDER8_CTL6 , 0x01 },
+ { WCD9335_CDC_RX0_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX0_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX0_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX0_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX0_RX_PATH_MIX_SEC1 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX1_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX1_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX1_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_SEC4 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX1_RX_PATH_MIX_SEC1 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX2_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX2_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX2_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_SEC4 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX2_RX_PATH_MIX_SEC1 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX3_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX3_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX3_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX3_RX_PATH_MIX_SEC1 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX4_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX4_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX4_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX4_RX_PATH_MIX_SEC1 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX5_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX5_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX5_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX5_RX_PATH_MIX_SEC1 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX6_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX6_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX6_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX6_RX_PATH_MIX_SEC1 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX7_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX7_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX7_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX7_RX_PATH_MIX_SEC1 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_CTL , 0x04 },
+ { WCD9335_CDC_RX8_RX_PATH_CFG0 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_CFG2 , 0x8f },
+ { WCD9335_CDC_RX8_RX_VOL_CTL , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_MIX_CTL , 0x04 },
+ { WCD9335_CDC_RX8_RX_VOL_MIX_CTL , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_SEC2 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_SEC3 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_SEC5 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_SEC6 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_SEC7 , 0x00 },
+ { WCD9335_CDC_RX8_RX_PATH_MIX_SEC1 , 0x00 },
+ /* Page #12 registers */
+ { WCD9335_PAGE12_PAGE_REGISTER , 0x00 },
+ { WCD9335_CDC_CLSH_CRC , 0x00 },
+ { WCD9335_CDC_CLSH_DLY_CTRL , 0x03 },
+ { WCD9335_CDC_CLSH_DECAY_CTRL , 0x02 },
+ { WCD9335_CDC_CLSH_HPH_V_PA , 0x1c },
+ { WCD9335_CDC_CLSH_EAR_V_PA , 0x39 },
+ { WCD9335_CDC_CLSH_HPH_V_HD , 0x0c },
+ { WCD9335_CDC_CLSH_EAR_V_HD , 0x0c },
+ { WCD9335_CDC_CLSH_K1_MSB , 0x01 },
+ { WCD9335_CDC_CLSH_K1_LSB , 0x00 },
+ { WCD9335_CDC_CLSH_K2_MSB , 0x00 },
+ { WCD9335_CDC_CLSH_K2_LSB , 0x80 },
+ { WCD9335_CDC_CLSH_IDLE_CTRL , 0x00 },
+ { WCD9335_CDC_CLSH_IDLE_HPH , 0x00 },
+ { WCD9335_CDC_CLSH_IDLE_EAR , 0x00 },
+ { WCD9335_CDC_CLSH_TEST0 , 0x07 },
+ { WCD9335_CDC_CLSH_TEST1 , 0x00 },
+ { WCD9335_CDC_CLSH_OVR_VREF , 0x00 },
+ { WCD9335_CDC_BOOST0_BOOST_PATH_CTL , 0x00 },
+ { WCD9335_CDC_BOOST0_BOOST_CTL , 0xb2 },
+ { WCD9335_CDC_BOOST0_BOOST_CFG1 , 0x00 },
+ { WCD9335_CDC_BOOST0_BOOST_CFG2 , 0x00 },
+ { WCD9335_CDC_BOOST1_BOOST_PATH_CTL , 0x00 },
+ { WCD9335_CDC_BOOST1_BOOST_CTL , 0xb2 },
+ { WCD9335_CDC_BOOST1_BOOST_CFG1 , 0x00 },
+ { WCD9335_CDC_BOOST1_BOOST_CFG2 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_WR_DATA_0 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_WR_DATA_1 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_WR_DATA_2 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_WR_DATA_3 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_RD_DATA_0 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_RD_DATA_1 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_RD_DATA_2 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_RD_DATA_3 , 0x00 },
+ { WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG , 0x0f },
+ { WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS , 0x03 },
+ { WCD9335_CDC_VBAT_VBAT_PATH_CTL , 0x00 },
+ { WCD9335_CDC_VBAT_VBAT_CFG , 0x0a },
+ { WCD9335_CDC_VBAT_VBAT_ADC_CAL1 , 0x00 },
+ { WCD9335_CDC_VBAT_VBAT_ADC_CAL2 , 0x00 },
+ { WCD9335_CDC_VBAT_VBAT_ADC_CAL3 , 0x04 },
+ { WCD9335_CDC_VBAT_VBAT_PK_EST1 , 0xe0 },
+ { WCD9335_CDC_VBAT_VBAT_PK_EST2 , 0x01 },
+ { WCD9335_CDC_VBAT_VBAT_PK_EST3 , 0x40 },
+ { WCD9335_CDC_VBAT_VBAT_RF_PROC1 , 0x2a },
+ { WCD9335_CDC_VBAT_VBAT_RF_PROC2 , 0x86 },
+ { WCD9335_CDC_VBAT_VBAT_TAC1 , 0x70 },
+ { WCD9335_CDC_VBAT_VBAT_TAC2 , 0x18 },
+ { WCD9335_CDC_VBAT_VBAT_TAC3 , 0x18 },
+ { WCD9335_CDC_VBAT_VBAT_TAC4 , 0x03 },
+ { WCD9335_CDC_VBAT_VBAT_GAIN_UPD1 , 0x01 },
+ { WCD9335_CDC_VBAT_VBAT_GAIN_UPD2 , 0x00 },
+ { WCD9335_CDC_VBAT_VBAT_GAIN_UPD3 , 0x64 },
+ { WCD9335_CDC_VBAT_VBAT_GAIN_UPD4 , 0x01 },
+ { WCD9335_CDC_VBAT_VBAT_DEBUG1 , 0x00 },
+ { WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON , 0x00 },
+ { WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL , 0x00 },
+ { WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL , 0x04 },
+ { WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1 , 0x00 },
+ { WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL , 0x04 },
+ { WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1 , 0x00 },
+ /* Page #13 registers */
+ { WCD9335_PAGE13_PAGE_REGISTER , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_ANC_CFG0 , 0x00 },
+ { WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0 , 0x00 },
+ { WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0 , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0, 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1, 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2, 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3, 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0, 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1, 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2, 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3, 0x00 },
+ { WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0 , 0x00 },
+ { WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1 , 0x00 },
+ { WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2 , 0x00 },
+ { WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3 , 0x00 },
+ { WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL , 0x00 },
+ { WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_CTL , 0x08 },
+ { WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0 , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1 , 0x4b },
+ { WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_STATUS , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD , 0x00 },
+ { WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_CTL , 0x40 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_CTL , 0x40 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL , 0x00 },
+ { WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL , 0x00 },
+ { WCD9335_CDC_TOP_TOP_CFG0 , 0x00 },
+ { WCD9335_CDC_TOP_TOP_CFG1 , 0x00 },
+ { WCD9335_CDC_TOP_TOP_CFG2 , 0x00 },
+ { WCD9335_CDC_TOP_TOP_CFG3 , 0x18 },
+ { WCD9335_CDC_TOP_TOP_CFG4 , 0x00 },
+ { WCD9335_CDC_TOP_TOP_CFG5 , 0x00 },
+ { WCD9335_CDC_TOP_TOP_CFG6 , 0x00 },
+ { WCD9335_CDC_TOP_TOP_CFG7 , 0x00 },
+ { WCD9335_CDC_TOP_HPHL_COMP_WR_LSB , 0x00 },
+ { WCD9335_CDC_TOP_HPHL_COMP_WR_MSB , 0x00 },
+ { WCD9335_CDC_TOP_HPHL_COMP_LUT , 0x00 },
+ { WCD9335_CDC_TOP_HPHL_COMP_RD_LSB , 0x00 },
+ { WCD9335_CDC_TOP_HPHL_COMP_RD_MSB , 0x00 },
+ { WCD9335_CDC_TOP_HPHR_COMP_WR_LSB , 0x00 },
+ { WCD9335_CDC_TOP_HPHR_COMP_WR_MSB , 0x00 },
+ { WCD9335_CDC_TOP_HPHR_COMP_LUT , 0x00 },
+ { WCD9335_CDC_TOP_HPHR_COMP_RD_LSB , 0x00 },
+ { WCD9335_CDC_TOP_HPHR_COMP_RD_MSB , 0x00 },
+ { WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB , 0x00 },
+ { WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB , 0x00 },
+ { WCD9335_CDC_TOP_DIFFL_COMP_LUT , 0x00 },
+ { WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB , 0x00 },
+ { WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB , 0x00 },
+ { WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB , 0x00 },
+ { WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB , 0x00 },
+ { WCD9335_CDC_TOP_DIFFR_COMP_LUT , 0x00 },
+ { WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB , 0x00 },
+ { WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB , 0x00 },
+ /* Page #0x80 registers */
+ { WCD9335_PAGE80_PAGE_REGISTER , 0x00 },
+ { WCD9335_TLMM_BIST_MODE_PINCFG , 0x00 },
+ { WCD9335_TLMM_RF_PA_ON_PINCFG , 0x00 },
+ { WCD9335_TLMM_INTR1_PINCFG , 0x00 },
+ { WCD9335_TLMM_INTR2_PINCFG , 0x00 },
+ { WCD9335_TLMM_SWR_DATA_PINCFG , 0x00 },
+ { WCD9335_TLMM_SWR_CLK_PINCFG , 0x00 },
+ { WCD9335_TLMM_SLIMBUS_DATA2_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2C_CLK_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2C_DATA_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2S_RX_SD0_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2S_RX_SD1_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2S_RX_SCK_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2S_RX_WS_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2S_TX_SD0_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2S_TX_SD1_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2S_TX_SCK_PINCFG , 0x00 },
+ { WCD9335_TLMM_I2S_TX_WS_PINCFG , 0x00 },
+ { WCD9335_TLMM_DMIC1_CLK_PINCFG , 0x00 },
+ { WCD9335_TLMM_DMIC1_DATA_PINCFG , 0x00 },
+ { WCD9335_TLMM_DMIC2_CLK_PINCFG , 0x00 },
+ { WCD9335_TLMM_DMIC2_DATA_PINCFG , 0x00 },
+ { WCD9335_TLMM_DMIC3_CLK_PINCFG , 0x00 },
+ { WCD9335_TLMM_DMIC3_DATA_PINCFG , 0x00 },
+ { WCD9335_TLMM_JTDI_PINCFG , 0x00 },
+ { WCD9335_TLMM_JTDO_PINCFG , 0x00 },
+ { WCD9335_TLMM_JTMS_PINCFG , 0x00 },
+ { WCD9335_TLMM_JTCK_PINCFG , 0x00 },
+ { WCD9335_TLMM_JTRST_PINCFG , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_CTL_OE_0 , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_CTL_OE_1 , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_CTL_OE_2 , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_CTL_OE_3 , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_CTL_DATA_0 , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_CTL_DATA_1 , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_CTL_DATA_2 , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_CTL_DATA_3 , 0x00 },
+ { WCD9335_TEST_DEBUG_PAD_DRVCTL , 0x00 },
+ { WCD9335_TEST_DEBUG_PIN_STATUS , 0x00 },
+ { WCD9335_TEST_DEBUG_MEM_CTRL , 0x00 },
+ { WCD9335_TEST_DEBUG_DEBUG_BUS_SEL , 0x00 },
+ { WCD9335_TEST_DEBUG_DEBUG_JTAG , 0x00 },
+ { WCD9335_TEST_DEBUG_DEBUG_EN_1 , 0x00 },
+ { WCD9335_TEST_DEBUG_DEBUG_EN_2 , 0x00 },
+ { WCD9335_TEST_DEBUG_DEBUG_EN_3 , 0x00 },
+};
+
+/*
+ * wcd9335_regmap_register_patch: Update register defaults based on version
+ * @regmap: handle to wcd9xxx regmap
+ * @version: wcd9335 version
+ *
+ * Returns error code in case of failure or 0 for success
+ */
+int wcd9335_regmap_register_patch(struct regmap *regmap, int version)
+{
+ const struct reg_sequence *wcd9335_patch;
+ int patch_size;
+
+ switch (version) {
+ case WCD9335_VERSION_1_0:
+ case WCD9335_VERSION_1_1:
+ wcd9335_patch = wcd9335_1_x_defaults;
+ patch_size = ARRAY_SIZE(wcd9335_1_x_defaults);
+ break;
+ case WCD9335_VERSION_2_0:
+ wcd9335_patch = wcd9335_2_0_defaults;
+ patch_size = ARRAY_SIZE(wcd9335_2_0_defaults);
+ break;
+ default:
+ pr_err("%s: unknown version: %d\n", __func__, version);
+ return -EINVAL;
+ }
+ return regmap_multi_reg_write_bypassed(regmap, wcd9335_patch,
+ patch_size);
+}
+EXPORT_SYMBOL(wcd9335_regmap_register_patch);
+
+static bool wcd9335_is_readable_register(struct device *dev, unsigned int reg)
+{
+ u8 pg_num, reg_offset;
+ const u8 *reg_tbl = NULL;
+
+ /*
+ * Get the page number from MSB of codec register. If its 0x80, assign
+ * the corresponding page index PAGE_0x80.
+ */
+ pg_num = reg >> 0x8;
+ if (pg_num == 0x80)
+ pg_num = PAGE_0X80;
+ else if (pg_num >= 0xE)
+ return false;
+
+ reg_tbl = wcd9335_reg[pg_num];
+ reg_offset = reg & 0xFF;
+
+ if (reg_tbl)
+ return reg_tbl[reg_offset];
+ else
+ return false;
+}
+
+static bool wcd9335_is_volatile_register(struct device *dev, unsigned int reg)
+{
+ /*
+ * registers from 0x000 to 0x0FF are volatile because
+ * this space contains registers related to interrupt
+ * status, mask etc
+ */
+ if (reg < 0x100)
+ return true;
+
+ /* IIR Coeff registers are not cacheable */
+ if ((reg >= WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL) &&
+ (reg <= WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL))
+ return true;
+
+ if ((reg >= WCD9335_CDC_ANC0_IIR_COEFF_1_CTL) &&
+ (reg <= WCD9335_CDC_ANC0_IIR_COEFF_2_CTL))
+ return true;
+
+ if ((reg >= WCD9335_CDC_ANC1_IIR_COEFF_1_CTL) &&
+ (reg <= WCD9335_CDC_ANC1_IIR_COEFF_2_CTL))
+ return true;
+ /*
+ * CPE inbox and outbox registers are volatile
+ * since they can be updated in the codec hardware
+ * to indicate CPE status
+ */
+ if (reg >= WCD9335_CPE_SS_MEM_PTR_0 &&
+ reg <= WCD9335_CPE_SS_OUTBOX2_ACK)
+ return true;
+
+ if (reg >= WCD9335_RCO_CAL_OUT_1 &&
+ reg <= WCD9335_RCO_CAL_OUT_5)
+ return true;
+
+ switch (reg) {
+ case WCD9335_CPE_SS_INBOX1_TRG:
+ case WCD9335_CPE_SS_INBOX2_TRG:
+ case WCD9335_SWR_AHB_BRIDGE_WR_DATA_0:
+ case WCD9335_SWR_AHB_BRIDGE_WR_DATA_1:
+ case WCD9335_SWR_AHB_BRIDGE_WR_DATA_2:
+ case WCD9335_SWR_AHB_BRIDGE_WR_DATA_3:
+ case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0:
+ case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1:
+ case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2:
+ case WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3:
+ case WCD9335_SWR_AHB_BRIDGE_RD_DATA_0:
+ case WCD9335_SWR_AHB_BRIDGE_RD_DATA_1:
+ case WCD9335_SWR_AHB_BRIDGE_RD_DATA_2:
+ case WCD9335_SWR_AHB_BRIDGE_RD_DATA_3:
+ case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0:
+ case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1:
+ case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2:
+ case WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3:
+ case WCD9335_ANA_BIAS:
+ case WCD9335_ANA_CLK_TOP:
+ case WCD9335_ANA_RCO:
+ case WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL:
+ case WCD9335_ANA_MBHC_RESULT_3:
+ case WCD9335_ANA_MBHC_RESULT_2:
+ case WCD9335_ANA_MBHC_RESULT_1:
+ case WCD9335_ANA_MBHC_MECH:
+ case WCD9335_ANA_MBHC_ELECT:
+ case WCD9335_ANA_MBHC_ZDET:
+ case WCD9335_ANA_MICB2:
+ case WCD9335_CPE_SS_SS_ERROR_INT_STATUS:
+ case WCD9335_CPE_SS_SS_ERROR_INT_MASK:
+ case WCD9335_CPE_SS_SS_ERROR_INT_CLEAR:
+ case WCD9335_CPE_SS_STATUS:
+ case WCD9335_CPE_SS_BACKUP_INT:
+ case WCD9335_CPE_SS_CFG:
+ case WCD9335_SOC_MAD_MAIN_CTL_1:
+ case WCD9335_SOC_MAD_AUDIO_CTL_3:
+ case WCD9335_SOC_MAD_AUDIO_CTL_4:
+ case WCD9335_FLYBACK_EN:
+ case WCD9335_ANA_RX_SUPPLIES:
+ case WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL:
+ case WCD9335_SIDO_SIDO_CCL_2:
+ case WCD9335_SIDO_SIDO_CCL_4:
+ case WCD9335_DATA_HUB_NATIVE_FIFO_STATUS:
+ case WCD9335_MBHC_FSM_STATUS:
+ case WCD9335_SPLINE_SRC0_STATUS:
+ case WCD9335_SPLINE_SRC1_STATUS:
+ case WCD9335_SPLINE_SRC2_STATUS:
+ case WCD9335_SPLINE_SRC3_STATUS:
+ case WCD9335_SIDO_SIDO_TEST_2:
+ case WCD9335_SIDO_SIDO_CCL_8:
+ case WCD9335_BIAS_VBG_FINE_ADJ:
+ case WCD9335_VBADC_ADC_DOUTMSB:
+ case WCD9335_VBADC_ADC_DOUTLSB:
+ case WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL:
+ case WCD9335_ANA_BUCK_CTL:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_range_cfg wcd9335_ranges[] = {
+ { .name = "WCD9335",
+ .range_min = 0x0,
+ .range_max = 0x80ff,
+ .selector_reg = WCD9335_PAGE0_PAGE_REGISTER,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ },
+};
+
+struct regmap_config wcd9335_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = wcd9335_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wcd9335_defaults),
+ .max_register = WCD9335_MAX_REGISTER,
+ .volatile_reg = wcd9335_is_volatile_register,
+ .readable_reg = wcd9335_is_readable_register,
+ .can_multi_write = true,
+ .ranges = wcd9335_ranges,
+ .num_ranges = ARRAY_SIZE(wcd9335_ranges),
+};
diff --git a/sound/soc/codecs/wcd9335-slim.c b/sound/soc/codecs/wcd9335-slim.c
new file mode 100644
index 000000000000..d4ff2cbdd38d
--- /dev/null
+++ b/sound/soc/codecs/wcd9335-slim.c
@@ -0,0 +1,498 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slimbus.h>
+#include <linux/ratelimit.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+
+#include "wcd9335.h"
+#include "wcd9335_registers.h"
+
+
+extern struct regmap_config wcd9335_regmap_config;
+
+static const struct regmap_irq wcd9335_irqs[] = {
+ /* INTR_REG 0 */
+ [WCD9335_IRQ_SLIMBUS] = {
+ .reg_offset = 0,
+ .mask = BIT(0),
+ },
+ [WCD9335_IRQ_FLL_LOCK_LOSS] = {
+ .reg_offset = 0,
+ .mask = BIT(1),
+ },
+ [WCD9335_IRQ_HPH_PA_OCPL_FAULT] = {
+ .reg_offset = 0,
+ .mask = BIT(2),
+ },
+ [WCD9335_IRQ_HPH_PA_OCPR_FAULT] = {
+ .reg_offset = 0,
+ .mask = BIT(3),
+ },
+ [WCD9335_IRQ_EAR_PA_OCP_FAULT] = {
+ .reg_offset = 0,
+ .mask = BIT(4),
+ },
+ [WCD9335_IRQ_HPH_PA_CNPL_COMPLETE] = {
+ .reg_offset = 0,
+ .mask = BIT(5),
+ },
+ [WCD9335_IRQ_HPH_PA_CNPR_COMPLETE] = {
+ .reg_offset = 0,
+ .mask = BIT(6),
+ },
+ [WCD9335_IRQ_EAR_PA_CNP_COMPLETE] = {
+ .reg_offset = 0,
+ .mask = BIT(7),
+ },
+ /* INTR_REG 1 */
+ [WCD9335_IRQ_MBHC_SW_DET] = {
+ .reg_offset = 1,
+ .mask = BIT(0),
+ },
+ [WCD9335_IRQ_MBHC_ELECT_INS_REM_DET] = {
+ .reg_offset = 1,
+ .mask = BIT(1),
+ },
+ [WCD9335_IRQ_MBHC_BUTTON_PRESS_DET] = {
+ .reg_offset = 1,
+ .mask = BIT(2),
+ },
+ [WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET] = {
+ .reg_offset = 1,
+ .mask = BIT(3),
+ },
+ [WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET] = {
+ .reg_offset = 1,
+ .mask = BIT(4),
+ },
+ /* INTR_REG 2 */
+ [WCD9335_IRQ_LINE_PA1_CNP_COMPLETE] = {
+ .reg_offset = 2,
+ .mask = BIT(0),
+ },
+ [WCD9335_IRQ_LINE_PA2_CNP_COMPLETE] = {
+ .reg_offset = 2,
+ .mask = BIT(1),
+ },
+ [WCD9335_IRQ_LINE_PA3_CNP_COMPLETE] = {
+ .reg_offset = 2,
+ .mask = BIT(2),
+ },
+ [WCD9335_IRQ_LINE_PA4_CNP_COMPLETE] = {
+ .reg_offset = 2,
+ .mask = BIT(3),
+ },
+ [WCD9335_IRQ_SOUNDWIRE] = {
+ .reg_offset = 2,
+ .mask = BIT(4),
+ },
+ [WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE] = {
+ .reg_offset = 2,
+ .mask = BIT(5),
+ },
+ [WCD9335_IRQ_RCO_ERROR] = {
+ .reg_offset = 2,
+ .mask = BIT(6),
+ },
+ [WCD9335_IRQ_SVA_ERROR] = {
+ .reg_offset = 2,
+ .mask = BIT(7),
+ },
+ /* INTR_REG 3 */
+ [WCD9335_IRQ_MAD_AUDIO] = {
+ .reg_offset = 3,
+ .mask = BIT(0),
+ },
+ [WCD9335_IRQ_MAD_BEACON] = {
+ .reg_offset = 3,
+ .mask = BIT(1),
+ },
+ [WCD9335_IRQ_MAD_ULTRASOUND] = {
+ .reg_offset = 3,
+ .mask = BIT(2),
+ },
+ [WCD9335_IRQ_VBAT_ATTACK] = {
+ .reg_offset = 3,
+ .mask = BIT(3),
+ },
+ [WCD9335_IRQ_VBAT_RESTORE] = {
+ .reg_offset = 3,
+ .mask = BIT(4),
+ },
+ [WCD9335_IRQ_SVA_OUTBOX1] = {
+ .reg_offset = 3,
+ .mask = BIT(5),
+ },
+ [WCD9335_IRQ_SVA_OUTBOX2] = {
+ .reg_offset = 3,
+ .mask = BIT(6),
+ },
+};
+
+static const struct regmap_irq_chip wcd9335_regmap_irq1_chip = {
+ .name = "wcd9335_pin1_irq",
+ .status_base = WCD9335_INTR_PIN1_STATUS0,
+ .mask_base = WCD9335_INTR_PIN1_MASK0,
+ .ack_base = WCD9335_INTR_PIN1_CLEAR0,
+ .type_base = WCD9335_INTR_LEVEL0,
+ .num_regs = 4,
+ .irqs = wcd9335_irqs,
+ .num_irqs = ARRAY_SIZE(wcd9335_irqs),
+};
+
+static const struct regmap_irq_chip wcd9335_regmap_irq2_chip = {
+ .name = "wcd9335_pin2_irq",
+ .status_base = WCD9335_INTR_PIN2_STATUS0,
+ .mask_base = WCD9335_INTR_PIN2_MASK0,
+ .ack_base = WCD9335_INTR_PIN2_CLEAR0,
+ .type_base = WCD9335_INTR_LEVEL0,
+ .num_regs = 4,
+ .irqs = wcd9335_irqs,
+ .num_irqs = ARRAY_SIZE(wcd9335_irqs),
+};
+static struct regmap_config wcd9335_ifd_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+// .can_multi_write = true,
+};
+
+
+static int wcd9335_parse_dt(struct wcd9335 *wcd)
+{
+ struct device *dev = wcd->dev;
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ wcd->reset_gpio = of_get_named_gpio(np, "qcom,cdc-reset-gpio", 0);
+ if (wcd->reset_gpio < 0) {
+ dev_err(dev, "Reset gpio missing in DT\n");
+ return -EINVAL;
+ }
+
+ wcd->irq_gpio = of_get_named_gpio(np, "qcom,gpio-int2", 0);
+ if (!gpio_is_valid(wcd->irq_gpio)) {
+ dev_err(dev, "IRQ gpio missing in DT\n");
+ return -EINVAL;
+ }
+
+ wcd->clk1_gpio = of_get_named_gpio(np, "qcom,clk1-gpio", 0);
+ if (!gpio_is_valid(wcd->clk1_gpio)) {
+ dev_err(dev, "CLK gpio missing in DT\n");
+ return -EINVAL;
+ }
+
+ gpio_request(wcd->clk1_gpio, "CLK1");
+ gpio_direction_output(wcd->clk1_gpio, 0);
+
+ //FIXME should go in to machine driver
+ ret = of_property_read_u32(np, "qcom,cdc-mclk-clk-rate", &wcd->mclk_rate);
+ if (ret) {
+ dev_err(dev, "Reset mclk rate missing in DT\n");
+ return -EINVAL;
+ }
+
+ if (wcd->mclk_rate != WCD9XXX_MCLK_CLK_9P6HZ &&
+ wcd->mclk_rate != WCD9XXX_MCLK_CLK_12P288MHZ) {
+ dev_err(dev, "Invalid mclk_rate = %u\n", wcd->mclk_rate);
+ return -EINVAL;
+ }
+ wcd->ext_clk = devm_clk_get(dev, "mclk");
+ if (IS_ERR(wcd->ext_clk)) {
+ dev_err(dev, "Unable to find external clk\n");
+ return -EINVAL;
+ }
+
+ wcd->native_clk = devm_clk_get(dev, "native");
+ if (IS_ERR(wcd->native_clk)) {
+ dev_err(dev, "Unable to find native clk\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void wcd9335_reset(struct wcd9335 *wcd)
+{
+ gpio_direction_output(wcd->reset_gpio, 0);
+ msleep(20);
+ gpio_set_value(wcd->reset_gpio, 1);
+ msleep(20);
+}
+
+int wcd9335_power_up(struct wcd9335 *wcd)
+{
+ struct device *dev = wcd->dev;
+ int ret;
+
+ wcd->num_of_supplies = 5;
+ wcd->supplies[0].supply = "vdd-buck";
+ wcd->supplies[1].supply = "buck-sido";
+ wcd->supplies[2].supply = "vdd-tx-h";
+ wcd->supplies[3].supply = "vdd-rx-h";
+ wcd->supplies[4].supply = "vddpx-1";
+
+ ret = regulator_bulk_get(dev, wcd->num_of_supplies, wcd->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to get supplies: err = %d\n", ret);
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(wcd->num_of_supplies, wcd->supplies);
+ if (ret != 0) {
+ dev_err(dev, "Failed to get supplies: err = %d\n", ret);
+ return ret;
+ }
+
+ /*
+ * For WCD9335, it takes about 600us for the Vout_A and
+ * Vout_D to be ready after BUCK_SIDO is powered up.
+ * SYS_RST_N shouldn't be pulled high during this time
+ */
+ usleep_range(600, 650);
+
+
+ return 0;
+}
+
+static int wcd9335_init(struct wcd9335 *wcd)
+{
+ int ret;
+
+ wcd->irq = gpio_to_irq(wcd->irq_gpio);
+ if (wcd->irq < 0) {
+ pr_err("Unable to configure irq\n");
+ return wcd->irq;
+ }
+ ret = regmap_add_irq_chip(wcd->regmap, wcd->irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ 0, &wcd9335_regmap_irq1_chip,
+ &wcd->irq_data);
+ if (ret != 0) {
+ pr_err("Failed to register IRQ chip: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int wcd9335_bring_up(struct wcd9335 *wcd)
+{
+ int val, byte0;
+ int ret = 0;
+
+ regmap_read(wcd->regmap,
+ WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0, &val);
+ regmap_read(wcd->regmap,
+ WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0, &byte0);
+
+ if ((val < 0) || (byte0 < 0)) {
+ dev_err(wcd->dev, "%s: tasha codec version detection fail!\n",
+ __func__);
+ return -EINVAL;
+ }
+
+
+ if ((val & 0x80) && (byte0 == 0x0)) {
+ dev_info(wcd->dev, "%s: wcd9335 codec version is v1.1\n",
+ __func__);
+ regmap_write(wcd->regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+ regmap_write(wcd->regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
+ regmap_write(wcd->regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
+ regmap_write(wcd->regmap,
+ WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
+ regmap_write(wcd->regmap,
+ WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
+ regmap_write(wcd->regmap,
+ WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
+ regmap_write(wcd->regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+ } else if (byte0 == 0x1) {
+ dev_info(wcd->dev, "%s: wcd9335 codec version is v2.0\n",
+ __func__);
+ regmap_write(wcd->regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+ regmap_write(wcd->regmap, WCD9335_SIDO_SIDO_TEST_2, 0x00);
+ regmap_write(wcd->regmap, WCD9335_SIDO_SIDO_CCL_8, 0x6F);
+ regmap_write(wcd->regmap, WCD9335_BIAS_VBG_FINE_ADJ, 0x65);
+ regmap_write(wcd->regmap,
+ WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x5);
+ regmap_write(wcd->regmap,
+ WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x7);
+ regmap_write(wcd->regmap,
+ WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
+ regmap_write(wcd->regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+ } else if ((byte0 == 0) && (!(val & 0x80))) {
+ dev_info(wcd->dev, "%s: wcd9335 codec version is v1.0\n",
+ __func__);
+ regmap_write(wcd->regmap, WCD9335_CODEC_RPM_RST_CTL, 0x01);
+ regmap_write(wcd->regmap, WCD9335_SIDO_SIDO_CCL_2, 0xFC);
+ regmap_write(wcd->regmap, WCD9335_SIDO_SIDO_CCL_4, 0x21);
+ regmap_write(wcd->regmap,
+ WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL, 0x3);
+ regmap_write(wcd->regmap, WCD9335_CODEC_RPM_RST_CTL, 0x3);
+ } else {
+ dev_err(wcd->dev, "%s: tasha codec version unknown\n",
+ __func__);
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int wcd9335_slim_probe(struct slim_device *slim)
+{
+ struct device *dev = &slim->dev;
+ struct wcd9335 *wcd;
+ int ret = 0;
+
+ pr_err("DEBUG:: %x: %x: %x: %x\n",
+ slim->e_addr.instance,
+ slim->e_addr.dev_index,
+ slim->e_addr.prod_code,
+ slim->e_addr.manf_id);
+ // Interface device
+ if (slim->e_addr.dev_index == 0)
+ return 0;
+// return 0;
+ wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
+ if (!wcd)
+ return -ENOMEM;
+
+ wcd->slim = slim;
+ wcd->dev = dev;
+
+
+ ret = wcd9335_power_up(wcd);
+ if (ret) {
+ dev_err(dev, "Error Powering\n");
+ return ret;
+ }
+
+ ret = wcd9335_parse_dt(wcd);
+ if (ret) {
+ dev_err(dev, "Error parsing DT\n");
+ return ret;
+ }
+
+ wcd->regmap = regmap_init_slimbus(slim, &wcd9335_regmap_config);
+
+ if (IS_ERR(wcd->regmap)) {
+ ret = PTR_ERR(wcd->regmap);
+ dev_err(&slim->dev, "%s: Failed to allocate register map: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+
+ dev_set_drvdata(dev, wcd);
+
+ usleep_range(600, 650);
+ wcd9335_reset(wcd);
+ wcd->version = 2;
+ wcd->dev = dev;
+ wcd->intf_type = WCD_INTERFACE_TYPE_SLIMBUS;
+
+ wcd->slim_data.slim = slim;
+ wcd->slim_data.regmap = wcd->regmap;
+ //FIXME
+ wcd->slim_data.rx_port_ch_reg_base = 0x180 - (WCD9335_RX_SLAVE_PORTS * 4);
+ wcd->slim_data.port_rx_cfg_reg_base = 0x040 - WCD9335_RX_SLAVE_PORTS;
+ wcd->slim_data.port_tx_cfg_reg_base = 0x050;
+
+
+ return 0;
+}
+
+static int wcd9335_slim_status(struct slim_device *sdev,
+ enum slim_device_status s)
+{
+ int ret;
+ int reg, i;
+ u32 val = 0;
+ struct wcd9335 *wcd;
+ struct device_node *np;
+ struct device *dev;
+ struct device_node *ifd_np = NULL;
+
+ dev_err(&sdev->dev, "GOT LOGICAL ADDRESS for %x \n", sdev->laddr);
+ // Interface device
+ if (sdev->e_addr.dev_index == 0)
+ return 0;
+
+ wcd = dev_get_drvdata(&sdev->dev);
+ np = wcd->dev->of_node;
+ dev = wcd->dev;
+
+ // Interface device
+ wcd9335_init(wcd);
+
+ ifd_np = of_parse_phandle(np, "ifd", 0);
+ if (!ifd_np) {
+ dev_err(wcd->dev, "No Interface device found\n");
+ return 0;
+ }
+
+ wcd->slim_ifd = of_slim_get_device(sdev->ctrl, ifd_np);
+ if (!wcd->slim_ifd) {
+ dev_err(wcd->dev, "UNable to get SLIM Interface device\n");
+ return 0;
+ }
+
+ wcd->ifd_regmap = regmap_init_slimbus(wcd->slim_ifd, &wcd9335_ifd_regmap_config);
+ if (IS_ERR(wcd->ifd_regmap)) {
+ ret = PTR_ERR(wcd->ifd_regmap);
+ dev_err(dev, "%s: Failed to allocate register map: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+
+ ret = wcd9335_bring_up(wcd);
+ if (ret) {
+ pr_err("DEBUG:: %s: %d\n", __func__, __LINE__);
+ }
+
+ wcd->slim_slave = wcd->slim_ifd;
+ wcd->slim_data.slim_slave = wcd->slim_ifd;
+ wcd->slim_data.if_regmap = wcd->ifd_regmap;
+
+ dev_err(dev, "DEBUG %s::::::::::::::::::::::::\n", __func__);
+ //regmap_read(wcd->regmap, 0x806, &val);
+ val = 0x7;
+ regmap_write(wcd->regmap, 0x806, 0x7);
+ dev_err(dev,"DEBUG:%s:: val %x \n", __func__, val);
+
+ return of_platform_populate(wcd->dev->of_node, NULL, NULL, wcd->dev);
+}
+
+static void wcd9335_slim_remove(struct slim_device *sdev)
+{
+}
+
+static const struct slim_device_id wcd9335_slim_id[] = {
+ {0x217, 0x1a0, 0x1, 0x0},
+ {}
+};
+
+static struct slim_driver wcd9335_slim_driver = {
+ .driver = {
+ .name = "wcd9335-slim",
+ .owner = THIS_MODULE,
+ },
+ .probe = wcd9335_slim_probe,
+ .remove = wcd9335_slim_remove,
+ .device_status = wcd9335_slim_status,
+ .id_table = wcd9335_slim_id,
+};
+
+module_slim_driver(wcd9335_slim_driver);
+MODULE_DESCRIPTION("Codec core driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
new file mode 100644
index 000000000000..20ae7280cac6
--- /dev/null
+++ b/sound/soc/codecs/wcd9335.c
@@ -0,0 +1,4448 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/printk.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include <linux/kernel.h>
+#include <linux/gpio.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/info.h>
+
+#include "wcd9335_registers.h"
+#include "wcd-clsh.h"
+#include "wcd9335.h"
+#include "wcd-slim.h"
+
+#define WCD9335_RX_PORT_START_NUMBER 16
+
+/* Number of input and output Slimbus port */
+enum {
+ WCD9335_RX0 = 0,
+ WCD9335_RX1,
+ WCD9335_RX2,
+ WCD9335_RX3,
+ WCD9335_RX4,
+ WCD9335_RX5,
+ WCD9335_RX6,
+ WCD9335_RX7,
+ WCD9335_RX8,
+ WCD9335_RX9,
+ WCD9335_RX10,
+ WCD9335_RX11,
+ WCD9335_RX12,
+ WCD9335_RX_MAX,
+};
+
+/*
+ * Rx path gain offsets
+ */
+enum {
+ RX_GAIN_OFFSET_M1P5_DB,
+ RX_GAIN_OFFSET_0_DB,
+};
+
+struct wcd9335_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
+#define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+/* Fractional Rates */
+#define WCD9335_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100)
+
+#define WCD9335_MIX_RATES_MASK (SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
+
+#define wcd9335_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+#define wcd9335_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+#define wcd9335_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
+
+/*
+ * Timeout in milli seconds and it is the wait time for
+ * slim channel removal interrupt to receive.
+ */
+#define WCD9335_SLIM_CLOSE_TIMEOUT 1000
+#define WCD9335_SLIM_IRQ_OVERFLOW (1 << 0)
+#define WCD9335_SLIM_IRQ_UNDERFLOW (1 << 1)
+#define WCD9335_SLIM_IRQ_PORT_CLOSED (1 << 2)
+#define wcd9335_MCLK_CLK_12P288MHZ 12288000
+#define wcd9335_MCLK_CLK_9P6MHZ 9600000
+
+#define WCD9335_SLIM_NUM_PORT_REG 3
+#define WCD9335_SLIM_PGD_PORT_INT_TX_EN0 (WCD9335_SLIM_PGD_PORT_INT_EN0 + 2)
+#define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE))
+
+#define SLIM_BW_CLK_GEAR_9 6200000
+#define SLIM_BW_UNVOTE 0
+
+#define wcd9335_DIG_CORE_REG_MIN WCD9335_CDC_ANC0_CLK_RESET_CTL
+#define wcd9335_DIG_CORE_REG_MAX 0xDFF
+
+#define CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25)
+
+/* SVS Scaling enable/disable */
+static int svs_scaling_enabled = 1;
+/* SVS buck setting */
+static int sido_buck_svs_voltage = SIDO_VOLTAGE_SVS_MV;
+
+enum {
+ VI_SENSE_1,
+ VI_SENSE_2,
+ AIF4_SWITCH_VALUE,
+ AUDIO_NOMINAL,
+ CPE_NOMINAL,
+ HPH_PA_DELAY,
+ SB_CLK_GEAR,
+ ANC_MIC_AMIC1,
+ ANC_MIC_AMIC2,
+ ANC_MIC_AMIC3,
+ ANC_MIC_AMIC4,
+ ANC_MIC_AMIC5,
+ ANC_MIC_AMIC6,
+};
+
+enum {
+ INTn_1_MIX_INP_SEL_ZERO = 0,
+ INTn_1_MIX_INP_SEL_DEC0,
+ INTn_1_MIX_INP_SEL_DEC1,
+ INTn_1_MIX_INP_SEL_IIR0,
+ INTn_1_MIX_INP_SEL_IIR1,
+ INTn_1_MIX_INP_SEL_RX0,
+ INTn_1_MIX_INP_SEL_RX1,
+ INTn_1_MIX_INP_SEL_RX2,
+ INTn_1_MIX_INP_SEL_RX3,
+ INTn_1_MIX_INP_SEL_RX4,
+ INTn_1_MIX_INP_SEL_RX5,
+ INTn_1_MIX_INP_SEL_RX6,
+ INTn_1_MIX_INP_SEL_RX7,
+
+};
+
+#define IS_VALID_NATIVE_FIFO_PORT(inp) \
+ ((inp >= INTn_1_MIX_INP_SEL_RX0) && \
+ (inp <= INTn_1_MIX_INP_SEL_RX3))
+
+enum {
+ INTn_2_INP_SEL_ZERO = 0,
+ INTn_2_INP_SEL_RX0,
+ INTn_2_INP_SEL_RX1,
+ INTn_2_INP_SEL_RX2,
+ INTn_2_INP_SEL_RX3,
+ INTn_2_INP_SEL_RX4,
+ INTn_2_INP_SEL_RX5,
+ INTn_2_INP_SEL_RX6,
+ INTn_2_INP_SEL_RX7,
+ INTn_2_INP_SEL_PROXIMITY,
+};
+
+enum {
+ INTERP_EAR = 0,
+ INTERP_HPHL,
+ INTERP_HPHR,
+ INTERP_LO1,
+ INTERP_LO2,
+ INTERP_LO3,
+ INTERP_LO4,
+ INTERP_SPKR1,
+ INTERP_SPKR2,
+};
+
+struct interp_sample_rate {
+ int sample_rate;
+ int rate_val;
+};
+
+static struct interp_sample_rate int_prim_sample_rate_val[] = {
+ {8000, 0x0}, /* 8K */
+ {16000, 0x1}, /* 16K */
+ {24000, -EINVAL},/* 24K */
+ {32000, 0x3}, /* 32K */
+ {48000, 0x4}, /* 48K */
+ {96000, 0x5}, /* 96K */
+ {192000, 0x6}, /* 192K */
+ {384000, 0x7}, /* 384K */
+ {44100, 0x8}, /* 44.1K */
+};
+
+static struct interp_sample_rate int_mix_sample_rate_val[] = {
+ {48000, 0x4}, /* 48K */
+ {96000, 0x5}, /* 96K */
+ {192000, 0x6}, /* 192K */
+};
+
+static const struct wcd_slim_ch wcd9335_rx_chs[WCD9335_RX_MAX] = {
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER, 0), /* 16 */
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 1, 1), /* 17 */
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 2, 2), /* 18 */
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 3, 3), /* 19 */
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 4, 4), /* 20 */
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 5, 5), /* 21 */
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 6, 6),
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 7, 7),
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 8, 8),
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 9, 9),
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 10, 10),
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 11, 11),
+ WCD_SLIM_CH(WCD9335_RX_PORT_START_NUMBER + 12, 12),
+};
+
+enum {
+ SRC_IN_HPHL,
+ SRC_IN_LO1,
+ SRC_IN_HPHR,
+ SRC_IN_LO2,
+ SRC_IN_SPKRL,
+ SRC_IN_LO3,
+ SRC_IN_SPKRR,
+ SRC_IN_LO4,
+};
+
+static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
+static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
+static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
+
+static int wcd9335_config_compander(struct snd_soc_component *, int, int);
+static int wcd9335_codec_vote_max_bw(struct snd_soc_component *comp,
+ bool vote);
+
+static const struct wcd9335_reg_mask_val wcd9335_spkr_default[] = {
+ {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80},
+ {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80},
+ {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01},
+ {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01},
+ {WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x50},
+ {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x50},
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_spkr_mode1[] = {
+ {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x00},
+ {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x00},
+ {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x00},
+ {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x00},
+ {WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x44},
+ {WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44},
+};
+
+static void wcd9335_enable_sido_buck(struct snd_soc_component *component)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ snd_soc_component_update_bits(component, WCD9335_ANA_RCO, 0x80, 0x80);
+ snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, 0x02, 0x02);
+ /* 100us sleep needed after IREF settings */
+ usleep_range(100, 110);
+ snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, 0x04, 0x04);
+ /* 100us sleep needed after VREF settings */
+ usleep_range(100, 110);
+ wcd->sido_input_src = SIDO_SOURCE_RCO_BG;
+}
+
+static void wcd9335_cdc_sido_ccl_enable(struct wcd9335_priv *wcd, bool ccl_flag)
+{
+ struct snd_soc_component *component = wcd->component;
+
+ if (!component)
+ return;
+
+ if (!WCD9335_IS_2_0(wcd->version)) {
+ dev_dbg(component->dev, "%s: wcd version < 2p0, return\n",
+ __func__);
+ return;
+ }
+ if (ccl_flag) {
+ if (++wcd->sido_ccl_cnt == 1)
+ snd_soc_component_update_bits(component,
+ WCD9335_SIDO_SIDO_CCL_10, 0xFF, 0x6E);
+ } else {
+ if (wcd->sido_ccl_cnt == 0) {
+ dev_dbg(component->dev, "%s: sido_ccl already disabled\n",
+ __func__);
+ return;
+ }
+ if (--wcd->sido_ccl_cnt == 0)
+ snd_soc_component_update_bits(component,
+ WCD9335_SIDO_SIDO_CCL_10, 0xFF, 0x02);
+ }
+}
+
+static bool wcd9335_cdc_is_svs_enabled(struct wcd9335_priv *wcd)
+{
+ if (WCD9335_IS_2_0(wcd->version) &&
+ svs_scaling_enabled)
+ return true;
+
+ return false;
+}
+
+int wcd9335_enable_master_bias(struct wcd9335_priv *wcd)
+{
+ mutex_lock(&wcd->master_bias_lock);
+
+ wcd->master_bias_users++;
+ if (wcd->master_bias_users == 1) {
+ regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, 0x80, 0x80);
+ regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, 0x40, 0x40);
+ /*
+ * 1ms delay is required after pre-charge is enabled
+ * as per HW requirement
+ */
+ usleep_range(1000, 1100);
+ regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, 0x40, 0x00);
+ regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS, 0x20, 0x00);
+ }
+
+ mutex_unlock(&wcd->master_bias_lock);
+ return 0;
+}
+
+static int wcd9335_enable_mclk(struct wcd9335_priv *wcd)
+{
+ /* Enable mclk requires master bias to be enabled first */
+ if (wcd->master_bias_users <= 0) {
+ dev_err(wcd->dev, "Cannot turn on MCLK, BG is not enabled\n");
+ return -EINVAL;
+ }
+
+ if (((wcd->clk_mclk_users == 0) &&
+ (wcd->clk_type == WCD_CLK_MCLK)) ||
+ ((wcd->clk_mclk_users > 0) &&
+ (wcd->clk_type != WCD_CLK_MCLK))) {
+ pr_err("%s: Error enabling MCLK, clk_type: %d\n",
+ __func__,
+ wcd->clk_type);
+ return -EINVAL;
+ }
+
+ if (++wcd->clk_mclk_users == 1) {
+
+ regmap_update_bits(wcd->regmap,
+ WCD9335_ANA_CLK_TOP, 0x80, 0x80);
+ regmap_update_bits(wcd->regmap,
+ WCD9335_ANA_CLK_TOP, 0x08, 0x00);
+ regmap_update_bits(wcd->regmap,
+ WCD9335_ANA_CLK_TOP, 0x04, 0x04);
+ regmap_update_bits(wcd->regmap,
+ WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL,
+ 0x01, 0x01);
+ regmap_update_bits(wcd->regmap,
+ WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+ 0x01, 0x01);
+ /*
+ * 10us sleep is required after clock is enabled
+ * as per HW requirement
+ */
+ usleep_range(10, 15);
+ }
+
+ wcd->clk_type = WCD_CLK_MCLK;
+
+ return 0;
+}
+
+static int wcd9335_disable_mclk(struct wcd9335_priv *wcd)
+{
+ if (wcd->clk_mclk_users <= 0) {
+ dev_err(wcd->dev, "No mclk users, cannot disable mclk\n");
+ return -EINVAL;
+ }
+
+ if (--wcd->clk_mclk_users == 0) {
+ if (wcd->clk_rco_users > 0) {
+ /* MCLK to RCO switch */
+ regmap_update_bits(wcd->regmap,
+ WCD9335_ANA_CLK_TOP,
+ 0x08, 0x08);
+ wcd->clk_type = WCD_CLK_RCO;
+ } else {
+ regmap_update_bits(wcd->regmap,
+ WCD9335_ANA_CLK_TOP,
+ 0x04, 0x00);
+ wcd->clk_type = WCD_CLK_OFF;
+ }
+
+ regmap_update_bits(wcd->regmap, WCD9335_ANA_CLK_TOP,
+ 0x80, 0x00);
+ }
+
+ return 0;
+}
+
+int wcd9335_disable_master_bias(struct wcd9335_priv *wcd)
+{
+ mutex_lock(&wcd->master_bias_lock);
+ if (wcd->master_bias_users <= 0) {
+ mutex_unlock(&wcd->master_bias_lock);
+ return -EINVAL;
+ }
+
+ wcd->master_bias_users--;
+ if (wcd->master_bias_users == 0) {
+ regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS,
+ 0x80, 0x00);
+ regmap_update_bits(wcd->regmap, WCD9335_ANA_BIAS,
+ 0x20, 0x00);
+ }
+ mutex_unlock(&wcd->master_bias_lock);
+ return 0;
+}
+
+static int wcd9335_cdc_req_mclk_enable(struct wcd9335_priv *wcd,
+ bool enable)
+{
+ int ret = 0;
+
+ if (enable) {
+ wcd9335_cdc_sido_ccl_enable(wcd, true);
+ ret = clk_prepare_enable(wcd->ext_clk);
+ if (ret) {
+ dev_err(wcd->dev, "%s: ext clk enable failed\n",
+ __func__);
+ goto err;
+ }
+ /* get BG */
+ wcd9335_enable_master_bias(wcd);
+ /* get MCLK */
+ wcd9335_enable_mclk(wcd);
+
+ } else {
+ /* put MCLK */
+ wcd9335_disable_mclk(wcd);
+ /* put BG */
+ wcd9335_disable_master_bias(wcd);
+ clk_disable_unprepare(wcd->ext_clk);
+ wcd9335_cdc_sido_ccl_enable(wcd, false);
+ }
+err:
+ return ret;
+}
+
+static int wcd9335_cdc_check_sido_value(enum wcd9335_sido_voltage req_mv)
+{
+ if ((req_mv != SIDO_VOLTAGE_SVS_MV) &&
+ (req_mv != SIDO_VOLTAGE_NOMINAL_MV))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void wcd9335_codec_apply_sido_voltage(
+ struct wcd9335_priv *wcd,
+ enum wcd9335_sido_voltage req_mv)
+{
+ u32 vout_d_val;
+ struct snd_soc_component *component = wcd->component;
+ int ret;
+
+ if (!component)
+ return;
+
+ if (!wcd9335_cdc_is_svs_enabled(wcd))
+ return;
+
+ if ((sido_buck_svs_voltage != SIDO_VOLTAGE_SVS_MV) &&
+ (sido_buck_svs_voltage != SIDO_VOLTAGE_NOMINAL_MV))
+ sido_buck_svs_voltage = SIDO_VOLTAGE_SVS_MV;
+
+ ret = wcd9335_cdc_check_sido_value(req_mv);
+ if (ret < 0) {
+ dev_err(component->dev, "%s: requested mv=%d not in range\n",
+ __func__, req_mv);
+ return;
+ }
+ if (req_mv == wcd->sido_voltage) {
+ dev_err(component->dev, "%s: Already at requested mv=%d\n",
+ __func__, req_mv);
+ return;
+ }
+ if (req_mv == sido_buck_svs_voltage) {
+ if (test_bit(AUDIO_NOMINAL, &wcd->status_mask) ||
+ test_bit(CPE_NOMINAL, &wcd->status_mask)) {
+ dev_err(component->dev,
+ "%s: nominal client running, status_mask=%lu\n",
+ __func__, wcd->status_mask);
+ return;
+ }
+ }
+ /* compute the vout_d step value */
+ vout_d_val = CALCULATE_VOUT_D(req_mv);
+ snd_soc_component_write(component, WCD9335_ANA_BUCK_VOUT_D, vout_d_val & 0xFF);
+ snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL, 0x80, 0x80);
+
+ /* 1 msec sleep required after SIDO Vout_D voltage change */
+ usleep_range(1000, 1100);
+ wcd->sido_voltage = req_mv;
+ snd_soc_component_update_bits(component, WCD9335_ANA_BUCK_CTL,
+ 0x80, 0x00);
+}
+
+static int wcd9335_codec_update_sido_voltage(
+ struct wcd9335_priv *wcd,
+ enum wcd9335_sido_voltage req_mv)
+{
+ int ret = 0;
+
+ if (!wcd9335_cdc_is_svs_enabled(wcd))
+ return ret;
+
+ mutex_lock(&wcd->sido_lock);
+ /* enable mclk before setting SIDO voltage */
+ ret = wcd9335_cdc_req_mclk_enable(wcd, true);
+ if (ret) {
+ dev_err(wcd->dev, "%s: ext clk enable failed\n",
+ __func__);
+ goto err;
+ }
+ wcd9335_codec_apply_sido_voltage(wcd, req_mv);
+ wcd9335_cdc_req_mclk_enable(wcd, false);
+
+err:
+ mutex_unlock(&wcd->sido_lock);
+ return ret;
+}
+
+static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_component *component = snd_soc_dapm_to_component(dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ ucontrol->value.enumerated.item[0] = wcd->rx_port_value;
+
+ return 0;
+}
+
+static const char *const slim_rx_mux_text[] = {
+ "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB", "AIF4_PB", "AIF_MIX1_PB"
+};
+
+static int wcd_slim_rx_vport_validation(u32 port_id,
+ struct list_head *codec_dai_list)
+{
+ struct wcd_slim_ch *ch;
+ int ret = 0;
+
+ list_for_each_entry(ch,
+ codec_dai_list, list) {
+ if (ch->port == port_id) {
+ ret = -EINVAL;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kcontrol);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);//to_component(dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ struct snd_soc_dapm_update *update = NULL;
+ u32 port_id = widget->shift;
+
+ wcd->rx_port_value = ucontrol->value.enumerated.item[0];
+
+ if (wcd->intf_type != WCD_INTERFACE_TYPE_SLIMBUS) {
+ if (wcd->rx_port_value > 2) {
+ dev_err(component->dev, "%s: invalid AIF for I2C mode\n",
+ __func__);
+ goto err;
+ }
+ }
+ /* value need to match the Virtual port and AIF number */
+ switch (wcd->rx_port_value) {
+ case 0:
+
+ list_del_init(&wcd->slim_data->rx_chs[port_id].list);
+ break;
+ case 1:
+ if (wcd_slim_rx_vport_validation(port_id +
+ WCD9335_RX_PORT_START_NUMBER,
+ &wcd->dai[AIF1_PB].wcd_slim_ch_list)) {
+ goto rtn;
+ }
+ list_add_tail(&wcd->slim_data->rx_chs[port_id].list,
+ &wcd->dai[AIF1_PB].wcd_slim_ch_list);
+ break;
+ case 2:
+ if (wcd_slim_rx_vport_validation(port_id +
+ WCD9335_RX_PORT_START_NUMBER,
+ &wcd->dai[AIF2_PB].wcd_slim_ch_list)) {
+ goto rtn;
+ }
+ list_add_tail(&wcd->slim_data->rx_chs[port_id].list,
+ &wcd->dai[AIF2_PB].wcd_slim_ch_list);
+ break;
+ case 3:
+ if (wcd_slim_rx_vport_validation(port_id +
+ WCD9335_RX_PORT_START_NUMBER,
+ &wcd->dai[AIF3_PB].wcd_slim_ch_list)) {
+ goto rtn;
+ }
+ list_add_tail(&wcd->slim_data->rx_chs[port_id].list,
+ &wcd->dai[AIF3_PB].wcd_slim_ch_list);
+ break;
+ case 4:
+ if (wcd_slim_rx_vport_validation(port_id +
+ WCD9335_RX_PORT_START_NUMBER,
+ &wcd->dai[AIF4_PB].wcd_slim_ch_list)) {
+ goto rtn;
+ }
+ list_add_tail(&wcd->slim_data->rx_chs[port_id].list,
+ &wcd->dai[AIF4_PB].wcd_slim_ch_list);
+ break;
+ case 5:
+ if (wcd_slim_rx_vport_validation(port_id +
+ WCD9335_RX_PORT_START_NUMBER,
+ &wcd->dai[AIF_MIX1_PB].wcd_slim_ch_list)) {
+ goto rtn;
+ }
+ list_add_tail(&wcd->slim_data->rx_chs[port_id].list,
+ &wcd->dai[AIF_MIX1_PB].wcd_slim_ch_list);
+ break;
+ default:
+ dev_err(wcd->dev, "Unknown AIF %d\n", wcd->rx_port_value);
+ goto err;
+ }
+rtn:
+ snd_soc_dapm_mux_update_power(widget->dapm, kcontrol,
+ wcd->rx_port_value, e, update);
+
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static const struct soc_enum slim_rx_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
+
+static const struct snd_kcontrol_new slim_rx_mux[WCD9335_RX_MAX] = {
+ SOC_DAPM_ENUM_EXT("SLIM RX0 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+ SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum,
+ slim_rx_mux_get, slim_rx_mux_put),
+};
+
+static const struct snd_kcontrol_new rx_int1_spline_mix_switch[] = {
+ SOC_DAPM_SINGLE("HPHL Switch", SND_SOC_NOPM, 0, 1, 0),
+ SOC_DAPM_SINGLE("HPHL Native Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int2_spline_mix_switch[] = {
+ SOC_DAPM_SINGLE("HPHR Switch", SND_SOC_NOPM, 0, 1, 0),
+ SOC_DAPM_SINGLE("HPHR Native Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int3_spline_mix_switch[] = {
+ SOC_DAPM_SINGLE("LO1 Switch", SND_SOC_NOPM, 0, 1, 0),
+ SOC_DAPM_SINGLE("LO1 Native Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int4_spline_mix_switch[] = {
+ SOC_DAPM_SINGLE("LO2 Switch", SND_SOC_NOPM, 0, 1, 0),
+ SOC_DAPM_SINGLE("LO2 Native Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int5_spline_mix_switch[] = {
+ SOC_DAPM_SINGLE("LO3 Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int6_spline_mix_switch[] = {
+ SOC_DAPM_SINGLE("LO4 Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int7_spline_mix_switch[] = {
+ SOC_DAPM_SINGLE("SPKRL Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new rx_int8_spline_mix_switch[] = {
+ SOC_DAPM_SINGLE("SPKRR Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static void wcd9335_codec_enable_int_port(struct wcd_slim_codec_dai_data *dai,
+ struct snd_soc_component *component)
+{
+ struct wcd_slim_ch *ch;
+ int port_num = 0;
+ unsigned short reg = 0;
+ unsigned int val = 0;
+ struct wcd9335_priv *wcd;
+
+ wcd = dev_get_drvdata(component->dev);
+ list_for_each_entry(ch, &dai->wcd_slim_ch_list, list) {
+ if (ch->port >= WCD9335_RX_PORT_START_NUMBER) {
+ port_num = ch->port - WCD9335_RX_PORT_START_NUMBER;
+ reg = WCD9335_SLIM_PGD_PORT_INT_EN0 + (port_num / 8);
+ regmap_read(wcd->if_regmap,
+ reg, &val);
+
+ if (!(val & BYTE_BIT_MASK(port_num))) {
+ val |= BYTE_BIT_MASK(port_num);
+ regmap_write(wcd->if_regmap, reg, val);
+ regmap_read(
+ wcd->if_regmap, reg, &val);
+ }
+ } else {
+ port_num = ch->port;
+ reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 + (port_num / 8);
+ regmap_read(wcd->if_regmap,
+ reg, &val);
+ if (!(val & BYTE_BIT_MASK(port_num))) {
+ val |= BYTE_BIT_MASK(port_num);
+ regmap_write(wcd->if_regmap,
+ reg, val);
+ regmap_read(
+ wcd->if_regmap, reg, &val);
+ }
+ }
+ }
+}
+
+int wcd_slim_get_slave_port(unsigned int ch_num)
+{
+ int ret = 0;
+
+ ret = (ch_num - BASE_CH_NUM);
+ if (ret < 0) {
+ pr_err("%s: Error:- Invalid slave port found = %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static int wcd9335_codec_enable_slim_chmask(struct wcd_slim_codec_dai_data *dai,
+ bool up)
+{
+ int ret = 0;
+ struct wcd_slim_ch *ch;
+
+ if (up) {
+ list_for_each_entry(ch, &dai->wcd_slim_ch_list, list) {
+ ret = wcd_slim_get_slave_port(ch->ch_num);
+ if (ret < 0) {
+ pr_err("%s: Invalid slave port ID: %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ } else {
+ set_bit(ret, &dai->ch_mask);
+ }
+ }
+ } else {
+ ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
+ msecs_to_jiffies(
+ WCD9335_SLIM_CLOSE_TIMEOUT));
+ if (!ret) {
+ pr_err("%s: Slim close tx/rx wait timeout, ch_mask:0x%lx\n",
+ __func__, dai->ch_mask);
+ ret = -ETIMEDOUT;
+ } else {
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static int wcd_slim_stream_enable(struct wcd_slim_data *wcd,
+ struct wcd_slim_codec_dai_data *dai_data);
+static int wcd_slim_stream_prepare(struct wcd9335_priv *wcd,
+ struct wcd_slim_codec_dai_data *dai_data);
+
+static int wcd9335_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int ret = 0;
+ struct wcd_slim_codec_dai_data *dai;
+
+ /* Execute the callback only if interface type is slimbus */
+ if (wcd->intf_type != WCD_INTERFACE_TYPE_SLIMBUS)
+ return 0;
+
+ dai = &wcd->dai[w->shift];
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ wcd9335_codec_enable_int_port(dai, component);
+ (void) wcd9335_codec_enable_slim_chmask(dai, true);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd9335_codec_vote_max_bw(component, true);
+
+ wcd9335_codec_enable_slim_chmask(dai, false);
+ wcd9335_codec_vote_max_bw(component, false);
+ slim_stream_unprepare(dai->sruntime);
+ slim_stream_disable(dai->sruntime);
+
+ break;
+ }
+ return ret;
+}
+
+static int wcd9335_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ int comp = ((struct soc_mixer_control *)
+ kcontrol->private_value)->shift;
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ ucontrol->value.integer.value[0] = wcd->comp_enabled[comp];
+ return 0;
+}
+
+static int wcd9335_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int comp = ((struct soc_mixer_control *) kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ wcd->comp_enabled[comp] = value;
+
+ /* Any specific register configuration for compander */
+ switch (comp) {
+ case COMPANDER_1:
+ /* Set Gain Source Select based on compander enable/disable */
+ snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, 0x20,
+ (value ? 0x00:0x20));
+ break;
+ case COMPANDER_2:
+ snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, 0x20,
+ (value ? 0x00:0x20));
+ break;
+ case COMPANDER_3:
+ break;
+ case COMPANDER_4:
+ break;
+ case COMPANDER_5:
+ snd_soc_component_update_bits(component, WCD9335_SE_LO_LO3_GAIN, 0x20,
+ (value ? 0x00:0x20));
+ break;
+ case COMPANDER_6:
+ snd_soc_component_update_bits(component, WCD9335_SE_LO_LO4_GAIN, 0x20,
+ (value ? 0x00:0x20));
+ break;
+ case COMPANDER_7:
+ break;
+ case COMPANDER_8:
+ break;
+ default:
+ /*
+ * if compander is not enabled for any interpolator,
+ * it does not cause any audio failure, so do not
+ * return error in this case, but just print a log
+ */
+ dev_warn(component->dev, "%s: unknown compander: %d\n",
+ __func__, comp);
+ };
+ return 0;
+}
+
+static void wcd9335_codec_init_flyback(struct snd_soc_component *component)
+{
+ snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, 0xC0, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, 0xC0, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, 0x0F, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_RX_BIAS_FLYB_BUFF, 0xF0, 0x00);
+}
+
+static int wcd9335_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd->rx_bias_count++;
+ if (wcd->rx_bias_count == 1) {
+ if (WCD9335_IS_2_0(wcd->version))
+ wcd9335_codec_init_flyback(component);
+ snd_soc_component_update_bits(component, WCD9335_ANA_RX_SUPPLIES,
+ 0x01, 0x01);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd->rx_bias_count--;
+ if (!wcd->rx_bias_count)
+ snd_soc_component_update_bits(component, WCD9335_ANA_RX_SUPPLIES,
+ 0x01, 0x00);
+ break;
+ };
+
+ return 0;
+}
+
+static void wcd9335_codec_hph_post_pa_config(struct wcd9335_priv *wcd,
+ int mode, int event)
+{
+ u8 scale_val = 0;
+
+ if (!WCD9335_IS_2_0(wcd->version))
+ return;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ switch (mode) {
+ case CLS_H_HIFI:
+ scale_val = 0x3;
+ break;
+ case CLS_H_LOHIFI:
+ scale_val = 0x1;
+ break;
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ scale_val = 0x6;
+ break;
+ }
+
+ if (scale_val)
+ snd_soc_component_update_bits(wcd->component, WCD9335_HPH_PA_CTL1, 0x0E,
+ scale_val << 1);
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ if (wcd->comp_enabled[COMPANDER_1] ||
+ wcd->comp_enabled[COMPANDER_2]) {
+ /* GAIN Source Selection */
+ snd_soc_component_update_bits(wcd->component, WCD9335_HPH_L_EN,
+ 0x20, 0x00);
+ snd_soc_component_update_bits(wcd->component, WCD9335_HPH_R_EN,
+ 0x20, 0x00);
+ snd_soc_component_update_bits(wcd->component, WCD9335_HPH_AUTO_CHOP,
+ 0x20, 0x20);
+ }
+ snd_soc_component_update_bits(wcd->component, WCD9335_HPH_L_EN, 0x1F,
+ wcd->hph_l_gain);
+ snd_soc_component_update_bits(wcd->component, WCD9335_HPH_R_EN, 0x1F,
+ wcd->hph_r_gain);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(wcd->component, WCD9335_HPH_AUTO_CHOP, 0x20,
+ 0x00);
+ }
+}
+
+static int wcd9335_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int hph_mode = wcd->hph_mode;
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ set_bit(HPH_PA_DELAY, &wcd->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 7ms sleep is required after PA is enabled as per
+ * HW requirement
+ */
+ if (test_bit(HPH_PA_DELAY, &wcd->status_mask)) {
+ usleep_range(7000, 7100);
+ clear_bit(HPH_PA_DELAY, &wcd->status_mask);
+ }
+ wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event);
+ snd_soc_component_update_bits(component, WCD9335_CDC_RX2_RX_PATH_CTL,
+ 0x10, 0x00);
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_component_read32(component, WCD9335_CDC_RX2_RX_PATH_MIX_CTL)) &
+ 0x10)
+ snd_soc_component_update_bits(component,
+ WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
+ 0x10, 0x00);
+
+ break;
+
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* 5ms sleep is required after PA is disabled as per
+ * HW requirement
+ */
+ usleep_range(5000, 5500);
+ break;
+ };
+
+ return ret;
+}
+
+static int wcd9335_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int hph_mode = wcd->hph_mode;
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ set_bit(HPH_PA_DELAY, &wcd->status_mask);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /*
+ * 7ms sleep is required after PA is enabled as per
+ * HW requirement
+ */
+ if (test_bit(HPH_PA_DELAY, &wcd->status_mask)) {
+ usleep_range(7000, 7100);
+ clear_bit(HPH_PA_DELAY, &wcd->status_mask);
+ }
+
+ wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event);
+ snd_soc_component_update_bits(component, WCD9335_CDC_RX1_RX_PATH_CTL,
+ 0x10, 0x00);
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_component_read32(component, WCD9335_CDC_RX1_RX_PATH_MIX_CTL)) &
+ 0x10)
+ snd_soc_component_update_bits(component,
+ WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
+ 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ wcd9335_codec_hph_post_pa_config(wcd, hph_mode, event);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* 5ms sleep is required after PA is disabled as per
+ * HW requirement
+ */
+ usleep_range(5000, 5500);
+ break;
+ };
+
+ return ret;
+}
+
+static int wcd9335_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ u16 lineout_vol_reg = 0, lineout_mix_vol_reg = 0;
+ int ret = 0;
+
+ if (w->reg == WCD9335_ANA_LO_1_2) {
+ if (w->shift == 7) {
+ lineout_vol_reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+ lineout_mix_vol_reg = WCD9335_CDC_RX3_RX_PATH_MIX_CTL;
+ } else if (w->shift == 6) {
+ lineout_vol_reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+ lineout_mix_vol_reg = WCD9335_CDC_RX4_RX_PATH_MIX_CTL;
+ }
+ } else if (w->reg == WCD9335_ANA_LO_3_4) {
+ if (w->shift == 7) {
+ lineout_vol_reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+ lineout_mix_vol_reg = WCD9335_CDC_RX5_RX_PATH_MIX_CTL;
+ } else if (w->shift == 6) {
+ lineout_vol_reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+ lineout_mix_vol_reg = WCD9335_CDC_RX6_RX_PATH_MIX_CTL;
+ }
+ } else {
+ dev_err(component->dev, "%s: Error enabling lineout PA\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* 5ms sleep is required after PA is enabled as per
+ * HW requirement
+ */
+ usleep_range(5000, 5500);
+ snd_soc_component_update_bits(component, lineout_vol_reg,
+ 0x10, 0x00);
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_component_read32(component, lineout_mix_vol_reg)) & 0x10)
+ snd_soc_component_update_bits(component,
+ lineout_mix_vol_reg,
+ 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* 5ms sleep is required after PA is disabled as per
+ * HW requirement
+ */
+ usleep_range(5000, 5500);
+ break;
+ };
+
+ return ret;
+}
+
+static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ /* 5ms sleep is required after PA is enabled as per
+ * HW requirement
+ */
+ usleep_range(5000, 5500);
+ snd_soc_component_update_bits(component, WCD9335_CDC_RX0_RX_PATH_CTL,
+ 0x10, 0x00);
+ /* Remove mix path mute if it is enabled */
+ if ((snd_soc_component_read32(component, WCD9335_CDC_RX0_RX_PATH_MIX_CTL)) &
+ 0x10)
+ snd_soc_component_update_bits(component,
+ WCD9335_CDC_RX0_RX_PATH_MIX_CTL,
+ 0x10, 0x00);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* 5ms sleep is required after PA is disabled as per
+ * HW requirement
+ */
+ usleep_range(5000, 5500);
+
+ break;
+ };
+
+ return ret;
+}
+
+static void wcd9335_codec_hph_mode_gain_opt(struct snd_soc_component *component,
+ u8 gain)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ u8 hph_l_en, hph_r_en;
+ u8 l_val, r_val;
+ u8 hph_pa_status;
+ bool is_hphl_pa, is_hphr_pa;
+
+ hph_pa_status = snd_soc_component_read32(component, WCD9335_ANA_HPH);
+ is_hphl_pa = hph_pa_status >> 7;
+ is_hphr_pa = (hph_pa_status & 0x40) >> 6;
+
+ hph_l_en = snd_soc_component_read32(component, WCD9335_HPH_L_EN);
+ hph_r_en = snd_soc_component_read32(component, WCD9335_HPH_R_EN);
+
+ l_val = (hph_l_en & 0xC0) | 0x20 | gain;
+ r_val = (hph_r_en & 0xC0) | 0x20 | gain;
+
+ /*
+ * Set HPH_L & HPH_R gain source selection to REGISTER
+ * for better click and pop only if corresponding PAs are
+ * not enabled. Also cache the values of the HPHL/R
+ * PA gains to be applied after PAs are enabled
+ */
+ if ((l_val != hph_l_en) && !is_hphl_pa) {
+ snd_soc_component_write(component, WCD9335_HPH_L_EN, l_val);
+ wcd->hph_l_gain = hph_l_en & 0x1F;
+ }
+
+ if ((r_val != hph_r_en) && !is_hphr_pa) {
+ snd_soc_component_write(component, WCD9335_HPH_R_EN, r_val);
+ wcd->hph_r_gain = hph_r_en & 0x1F;
+ }
+}
+
+static void wcd9335_codec_hph_lohifi_config(struct snd_soc_component *component,
+ int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_component_update_bits(component, WCD9335_RX_BIAS_HPH_PA, 0x0F, 0x06);
+ snd_soc_component_update_bits(component, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2,
+ 0xF0, 0x40);
+ snd_soc_component_update_bits(component, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
+ wcd9335_codec_hph_mode_gain_opt(component, 0x11);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
+ snd_soc_component_write(component, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A);
+ snd_soc_component_update_bits(component, WCD9335_RX_BIAS_HPH_PA, 0x0F, 0x0A);
+ }
+}
+
+static void wcd9335_codec_hph_lp_config(struct snd_soc_component *component,
+ int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
+ wcd9335_codec_hph_mode_gain_opt(component, 0x10);
+ snd_soc_component_update_bits(component, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x04, 0x04);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x20, 0x20);
+ snd_soc_component_update_bits(component, WCD9335_HPH_RDAC_LDO_CTL, 0x07,
+ 0x01);
+ snd_soc_component_update_bits(component, WCD9335_HPH_RDAC_LDO_CTL, 0x70,
+ 0x10);
+ snd_soc_component_update_bits(component, WCD9335_RX_BIAS_HPH_RDAC_LDO,
+ 0x0F, 0x01);
+ snd_soc_component_update_bits(component, WCD9335_RX_BIAS_HPH_RDAC_LDO,
+ 0xF0, 0x10);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_write(component, WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x88);
+ snd_soc_component_write(component, WCD9335_HPH_RDAC_LDO_CTL, 0x33);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x20, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x04, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
+ snd_soc_component_update_bits(component, WCD9335_HPH_R_EN, 0xC0, 0x80);
+ snd_soc_component_update_bits(component, WCD9335_HPH_L_EN, 0xC0, 0x80);
+ }
+}
+
+static void wcd9335_codec_hph_hifi_config(struct snd_soc_component *component,
+ int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_component_update_bits(component, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x03);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x08, 0x08);
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C);
+ wcd9335_codec_hph_mode_gain_opt(component, 0x11);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, WCD9335_HPH_PA_CTL2, 0x08, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_HPH_CNP_WG_CTL, 0x07, 0x02);
+ }
+}
+
+static void wcd9335_codec_hph_mode_config(struct snd_soc_component *component,
+ int event, int mode)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ if (!WCD9335_IS_2_0(wcd->version))
+ return;
+
+ switch (mode) {
+ case CLS_H_LP:
+ wcd9335_codec_hph_lp_config(component, event);
+ break;
+ case CLS_H_LOHIFI:
+ wcd9335_codec_hph_lohifi_config(component, event);
+ break;
+ case CLS_H_HIFI:
+ wcd9335_codec_hph_hifi_config(component, event);
+ break;
+ }
+}
+
+static int wcd9335_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int hph_mode = wcd->hph_mode;
+ u8 dem_inp;
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ /* Read DEM INP Select */
+ dem_inp = snd_soc_component_read32(component, WCD9335_CDC_RX2_RX_PATH_SEC0) &
+ 0x03;
+ if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+ (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+ dev_err(component->dev, "%s: DEM Input not set correctly, hph_mode: %d\n",
+ __func__, hph_mode);
+ return -EINVAL;
+ }
+
+ wcd_clsh_fsm(component, &wcd->clsh_d,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHR,
+ ((hph_mode == CLS_H_LOHIFI) ?
+ CLS_H_HIFI : hph_mode));
+
+ wcd9335_codec_hph_mode_config(component, event, hph_mode);
+
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* 1000us required as per HW requirement */
+ usleep_range(1000, 1100);
+ if ((hph_mode == CLS_H_LP) &&
+ (WCD9335_IS_1_1(wcd->version))) {
+ snd_soc_component_update_bits(component, WCD9335_HPH_L_DAC_CTL,
+ 0x03, 0x03);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if ((hph_mode == CLS_H_LP) &&
+ (WCD9335_IS_1_1(wcd->version))) {
+ snd_soc_component_update_bits(component, WCD9335_HPH_L_DAC_CTL,
+ 0x03, 0x00);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* 1000us required as per HW requirement */
+ usleep_range(1000, 1100);
+
+ if (!(wcd_clsh_get_clsh_state(&wcd->clsh_d) &
+ WCD_CLSH_STATE_HPHL))
+ wcd9335_codec_hph_mode_config(component, event, hph_mode);
+
+ wcd_clsh_fsm(component, &wcd->clsh_d,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHR,
+ ((hph_mode == CLS_H_LOHIFI) ?
+ CLS_H_HIFI : hph_mode));
+ break;
+ };
+
+ return ret;
+}
+
+static int wcd9335_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int hph_mode = wcd->hph_mode;
+ u8 dem_inp;
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ /* Read DEM INP Select */
+ dem_inp = snd_soc_component_read32(component, WCD9335_CDC_RX1_RX_PATH_SEC0) &
+ 0x03;
+ if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) ||
+ (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) {
+ dev_err(component->dev, "%s: DEM Input not set correctly, hph_mode: %d\n",
+ __func__, hph_mode);
+ return -EINVAL;
+ }
+ wcd_clsh_fsm(component, &wcd->clsh_d,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_HPHL,
+ ((hph_mode == CLS_H_LOHIFI) ?
+ CLS_H_HIFI : hph_mode));
+
+ wcd9335_codec_hph_mode_config(component, event, hph_mode);
+
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ /* 1000us required as per HW requirement */
+ usleep_range(1000, 1100);
+ if ((hph_mode == CLS_H_LP) &&
+ (WCD9335_IS_1_1(wcd->version))) {
+ snd_soc_component_update_bits(component, WCD9335_HPH_L_DAC_CTL,
+ 0x03, 0x03);
+ }
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ if ((hph_mode == CLS_H_LP) &&
+ (WCD9335_IS_1_1(wcd->version))) {
+ snd_soc_component_update_bits(component, WCD9335_HPH_L_DAC_CTL,
+ 0x03, 0x00);
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ /* 1000us required as per HW requirement */
+ usleep_range(1000, 1100);
+
+ if (!(wcd_clsh_get_clsh_state(&wcd->clsh_d) &
+ WCD_CLSH_STATE_HPHR))
+ wcd9335_codec_hph_mode_config(component, event, hph_mode);
+ wcd_clsh_fsm(component, &wcd->clsh_d,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_HPHL,
+ ((hph_mode == CLS_H_LOHIFI) ?
+ CLS_H_HIFI : hph_mode));
+ break;
+ };
+
+ return ret;
+}
+
+static int wcd9335_codec_lineout_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd_clsh_fsm(component, &wcd->clsh_d,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_LO,
+ CLS_AB);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd_clsh_fsm(component, &wcd->clsh_d,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_LO,
+ CLS_AB);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget wcd9335_dapm_i2s_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("RX_I2S_CTL", WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+ 0, 0, NULL, 0),
+};
+
+static int wcd9335_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int ret = 0;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ wcd_clsh_fsm(component, &wcd->clsh_d,
+ WCD_CLSH_EVENT_PRE_DAC,
+ WCD_CLSH_STATE_EAR,
+ CLS_H_NORMAL);
+
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd_clsh_fsm(component, &wcd->clsh_d,
+ WCD_CLSH_EVENT_POST_PA,
+ WCD_CLSH_STATE_EAR,
+ CLS_H_NORMAL);
+ break;
+ };
+
+ return ret;
+}
+
+static u16 wcd9335_interp_get_primary_reg(u16 reg, u16 *ind)
+{
+ u16 prim_int_reg;
+
+ switch (reg) {
+ case WCD9335_CDC_RX0_RX_PATH_CTL:
+ case WCD9335_CDC_RX0_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX0_RX_PATH_CTL;
+ *ind = 0;
+ break;
+ case WCD9335_CDC_RX1_RX_PATH_CTL:
+ case WCD9335_CDC_RX1_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX1_RX_PATH_CTL;
+ *ind = 1;
+ break;
+ case WCD9335_CDC_RX2_RX_PATH_CTL:
+ case WCD9335_CDC_RX2_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX2_RX_PATH_CTL;
+ *ind = 2;
+ break;
+ case WCD9335_CDC_RX3_RX_PATH_CTL:
+ case WCD9335_CDC_RX3_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+ *ind = 3;
+ break;
+ case WCD9335_CDC_RX4_RX_PATH_CTL:
+ case WCD9335_CDC_RX4_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+ *ind = 4;
+ break;
+ case WCD9335_CDC_RX5_RX_PATH_CTL:
+ case WCD9335_CDC_RX5_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+ *ind = 5;
+ break;
+ case WCD9335_CDC_RX6_RX_PATH_CTL:
+ case WCD9335_CDC_RX6_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+ *ind = 6;
+ break;
+ case WCD9335_CDC_RX7_RX_PATH_CTL:
+ case WCD9335_CDC_RX7_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX7_RX_PATH_CTL;
+ *ind = 7;
+ break;
+ case WCD9335_CDC_RX8_RX_PATH_CTL:
+ case WCD9335_CDC_RX8_RX_PATH_MIX_CTL:
+ prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL;
+ *ind = 8;
+ break;
+ };
+
+ return prim_int_reg;
+}
+
+static void wcd9335_codec_hd2_control(struct snd_soc_component *component,
+ u16 prim_int_reg, int event)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ u16 hd2_scale_reg;
+ u16 hd2_enable_reg = 0;
+
+ if (!WCD9335_IS_2_0(wcd->version))
+ return;
+
+ if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) {
+ hd2_scale_reg = WCD9335_CDC_RX1_RX_PATH_SEC3;
+ hd2_enable_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
+ }
+ if (prim_int_reg == WCD9335_CDC_RX2_RX_PATH_CTL) {
+ hd2_scale_reg = WCD9335_CDC_RX2_RX_PATH_SEC3;
+ hd2_enable_reg = WCD9335_CDC_RX2_RX_PATH_CFG0;
+ }
+
+ if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) {
+ snd_soc_component_update_bits(component, hd2_scale_reg, 0x3C, 0x10);
+ snd_soc_component_update_bits(component, hd2_scale_reg, 0x03, 0x01);
+ snd_soc_component_update_bits(component, hd2_enable_reg, 0x04, 0x04);
+ }
+
+ if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, hd2_enable_reg, 0x04, 0x00);
+ snd_soc_component_update_bits(component, hd2_scale_reg, 0x03, 0x00);
+ snd_soc_component_update_bits(component, hd2_scale_reg, 0x3C, 0x00);
+ }
+}
+
+static int wcd9335_codec_enable_prim_interpolator(
+ struct snd_soc_component *component,
+ u16 reg, int event)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ u16 prim_int_reg, ind = 0;
+
+ prim_int_reg = wcd9335_interp_get_primary_reg(reg, &ind);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ wcd->prim_int_users[ind]++;
+ if (wcd->prim_int_users[ind] == 1) {
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 0x10, 0x10);
+ wcd9335_codec_hd2_control(component, prim_int_reg, event);
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 1 << 0x5, 1 << 0x5);
+ }
+ if ((reg != prim_int_reg) && ((snd_soc_component_read32(component, prim_int_reg)) & 0x10))
+ snd_soc_component_update_bits(component, reg, 0x10, 0x10);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd->prim_int_users[ind]--;
+ if (wcd->prim_int_users[ind] == 0) {
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 1 << 0x5, 0 << 0x5);
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 0x40, 0x40);
+ snd_soc_component_update_bits(component, prim_int_reg,
+ 0x40, 0x00);
+ wcd9335_codec_hd2_control(component, prim_int_reg, event);
+ }
+ break;
+ };
+
+ return 0;
+}
+
+static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ u16 gain_reg;
+ int offset_val = 0;
+ int val = 0;
+
+ switch (w->reg) {
+ case WCD9335_CDC_RX0_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX0_RX_VOL_MIX_CTL;
+ break;
+ case WCD9335_CDC_RX1_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX1_RX_VOL_MIX_CTL;
+ break;
+ case WCD9335_CDC_RX2_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX2_RX_VOL_MIX_CTL;
+ break;
+ case WCD9335_CDC_RX3_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX3_RX_VOL_MIX_CTL;
+ break;
+ case WCD9335_CDC_RX4_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX4_RX_VOL_MIX_CTL;
+ break;
+ case WCD9335_CDC_RX5_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX5_RX_VOL_MIX_CTL;
+ break;
+ case WCD9335_CDC_RX6_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX6_RX_VOL_MIX_CTL;
+ break;
+ case WCD9335_CDC_RX7_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX7_RX_VOL_MIX_CTL;
+ break;
+ case WCD9335_CDC_RX8_RX_PATH_MIX_CTL:
+ gain_reg = WCD9335_CDC_RX8_RX_VOL_MIX_CTL;
+ break;
+ default:
+ dev_err(component->dev, "%s: No gain register avail for %s\n",
+ __func__, w->name);
+ return 0;
+ };
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ val = snd_soc_component_read32(component, gain_reg);
+ val += offset_val;
+ snd_soc_component_write(component, gain_reg, val);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ break;
+ };
+
+ return 0;
+}
+
+static int __tasha_cdc_native_clk_enable(struct wcd9335_priv *wcd,
+ bool enable)
+{
+ int ret = 0;
+ struct snd_soc_component *component = wcd->component;
+
+ if (!wcd->native_clk) {
+ dev_err(wcd->dev, "%s: wcd native clock is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (enable) {
+ ret = clk_prepare_enable(wcd->native_clk);
+ if (ret) {
+ dev_err(wcd->dev, "%s: native clk enable failed\n",
+ __func__);
+ goto err;
+ }
+ if (++wcd->native_clk_users == 1) {
+ snd_soc_component_update_bits(component, WCD9335_CLOCK_TEST_CTL,
+ 0x10, 0x10);
+ snd_soc_component_update_bits(component, WCD9335_CLOCK_TEST_CTL,
+ 0x80, 0x80);
+ snd_soc_component_update_bits(component, WCD9335_CODEC_RPM_CLK_GATE,
+ 0x04, 0x00);
+ snd_soc_component_update_bits(component,
+ WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+ 0x02, 0x02);
+ }
+ } else {
+ if (wcd->native_clk_users &&
+ (--wcd->native_clk_users == 0)) {
+ snd_soc_component_update_bits(component,
+ WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL,
+ 0x02, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_CODEC_RPM_CLK_GATE,
+ 0x04, 0x04);
+ snd_soc_component_update_bits(component, WCD9335_CLOCK_TEST_CTL,
+ 0x80, 0x00);
+ snd_soc_component_update_bits(component, WCD9335_CLOCK_TEST_CTL,
+ 0x10, 0x00);
+ }
+ clk_disable_unprepare(wcd->native_clk);
+ }
+
+err:
+ return ret;
+}
+
+static int wcd9335_codec_get_native_fifo_sync_mask(struct snd_soc_component *component,
+ int interp_n)
+{
+ int mask = 0;
+ u16 reg;
+ u8 val1, val2, inp0 = 0;
+ u8 inp1 = 0, inp2 = 0;
+
+ reg = WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 + (2 * interp_n) - 2;
+
+ val1 = snd_soc_component_read32(component, reg);
+ val2 = snd_soc_component_read32(component, reg + 1);
+
+ inp0 = val1 & 0x0F;
+ inp1 = (val1 >> 4) & 0x0F;
+ inp2 = (val2 >> 4) & 0x0F;
+
+ if (IS_VALID_NATIVE_FIFO_PORT(inp0))
+ mask |= (1 << (inp0 - 5));
+ if (IS_VALID_NATIVE_FIFO_PORT(inp1))
+ mask |= (1 << (inp1 - 5));
+ if (IS_VALID_NATIVE_FIFO_PORT(inp2))
+ mask |= (1 << (inp2 - 5));
+
+ if (!mask)
+ dev_err(component->dev, "native fifo err,int:%d,inp0:%d,inp1:%d,inp2:%d\n",
+ interp_n, inp0, inp1, inp2);
+ return mask;
+}
+
+static int wcd9335_enable_native_supply(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ int mask;
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ u16 interp_reg;
+
+ if (w->shift < INTERP_HPHL || w->shift > INTERP_LO2)
+ return -EINVAL;
+
+ interp_reg = WCD9335_CDC_RX1_RX_PATH_CTL + 20 * (w->shift - 1);
+
+ mask = wcd9335_codec_get_native_fifo_sync_mask(component, w->shift);
+ if (!mask)
+ return -EINVAL;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Adjust interpolator rate to 44P1_NATIVE */
+ snd_soc_component_update_bits(component, interp_reg, 0x0F, 0x09);
+ __tasha_cdc_native_clk_enable(wcd, true);
+ snd_soc_component_update_bits(component, WCD9335_DATA_HUB_NATIVE_FIFO_SYNC,
+ mask, mask);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_component_update_bits(component, WCD9335_DATA_HUB_NATIVE_FIFO_SYNC,
+ mask, 0x0);
+ __tasha_cdc_native_clk_enable(wcd, false);
+ /* Adjust interpolator rate to default */
+ snd_soc_component_update_bits(component, interp_reg, 0x0F, 0x04);
+ break;
+ }
+
+ return 0;
+}
+
+static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ u16 gain_reg;
+ u16 reg;
+ int val;
+ int offset_val = 0;
+
+ if (!(strcmp(w->name, "RX INT0 INTERP"))) {
+ reg = WCD9335_CDC_RX0_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX0_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT1 INTERP"))) {
+ reg = WCD9335_CDC_RX1_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX1_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT2 INTERP"))) {
+ reg = WCD9335_CDC_RX2_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX2_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT3 INTERP"))) {
+ reg = WCD9335_CDC_RX3_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX3_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT4 INTERP"))) {
+ reg = WCD9335_CDC_RX4_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX4_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT5 INTERP"))) {
+ reg = WCD9335_CDC_RX5_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX5_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT6 INTERP"))) {
+ reg = WCD9335_CDC_RX6_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX6_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT7 INTERP"))) {
+ reg = WCD9335_CDC_RX7_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX7_RX_VOL_CTL;
+ } else if (!(strcmp(w->name, "RX INT8 INTERP"))) {
+ reg = WCD9335_CDC_RX8_RX_PATH_CTL;
+ gain_reg = WCD9335_CDC_RX8_RX_VOL_CTL;
+ } else {
+ dev_err(component->dev, "%s: Interpolator reg not found\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ if (!test_bit(SB_CLK_GEAR, &wcd->status_mask)) {
+ wcd9335_codec_vote_max_bw(component, true);
+ set_bit(SB_CLK_GEAR, &wcd->status_mask);
+ }
+ /* Reset if needed */
+ wcd9335_codec_enable_prim_interpolator(component, reg, event);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ wcd9335_config_compander(component, w->shift, event);
+ val = snd_soc_component_read32(component, gain_reg);
+ val += offset_val;
+ snd_soc_component_write(component, gain_reg, val);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ wcd9335_config_compander(component, w->shift, event);
+ wcd9335_codec_enable_prim_interpolator(component, reg, event);
+ break;
+ };
+
+ return 0;
+}
+
+static const char * const rx_cf_text[] = {
+ "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ",
+ "CF_NEG_3DB_0P48HZ"
+};
+
+static const char * const wcd9335_ear_pa_gain_text[] = {
+ "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
+ "G_0_DB", "G_M2P5_DB", "UNDEFINED", "G_M12_DB"
+};
+
+static const struct soc_enum wcd9335_ear_pa_gain_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wcd9335_ear_pa_gain_text),
+ wcd9335_ear_pa_gain_text);
+
+static const char * const spl_src0_mux_text[] = {
+ "ZERO", "SRC_IN_HPHL", "SRC_IN_LO1",
+};
+
+static const struct soc_enum cf_int0_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int0_2_enum, WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int1_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int1_2_enum, WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int2_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int2_2_enum, WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int3_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int3_2_enum, WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int4_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int4_2_enum, WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int5_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int5_2_enum, WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int6_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int6_2_enum, WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int7_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int7_2_enum, WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct soc_enum cf_int8_1_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CFG2, 0, 4, rx_cf_text);
+
+static SOC_ENUM_SINGLE_DECL(cf_int8_2_enum, WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 2,
+ rx_cf_text);
+
+static const struct snd_soc_dapm_route audio_i2s_map[] = {
+ {"SLIM RX0 MUX", NULL, "RX_I2S_CTL"},
+ {"SLIM RX1 MUX", NULL, "RX_I2S_CTL"},
+ {"SLIM RX2 MUX", NULL, "RX_I2S_CTL"},
+ {"SLIM RX3 MUX", NULL, "RX_I2S_CTL"},
+};
+
+static const struct snd_soc_dapm_route wcd9335_audio_map[] = {
+ /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
+ {"SLIM RX0 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
+ {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
+ /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
+ {"SLIM RX0 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
+ {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
+ /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
+ {"SLIM RX0 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
+ {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
+ /* SLIM_MUX("AIF4_PB", "AIF4 PB"),*/
+ {"SLIM RX0 MUX", "AIF4_PB", "AIF4 PB"},
+ {"SLIM RX1 MUX", "AIF4_PB", "AIF4 PB"},
+ {"SLIM RX2 MUX", "AIF4_PB", "AIF4 PB"},
+ {"SLIM RX3 MUX", "AIF4_PB", "AIF4 PB"},
+ {"SLIM RX4 MUX", "AIF4_PB", "AIF4 PB"},
+ {"SLIM RX5 MUX", "AIF4_PB", "AIF4 PB"},
+ {"SLIM RX6 MUX", "AIF4_PB", "AIF4 PB"},
+ {"SLIM RX7 MUX", "AIF4_PB", "AIF4 PB"},
+
+ /* SLIM_MUX("AIF_MIX1_PB", "AIF MIX1 PB"),*/
+ {"SLIM RX0 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+ {"SLIM RX1 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+ {"SLIM RX2 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+ {"SLIM RX3 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+ {"SLIM RX4 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+ {"SLIM RX5 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+ {"SLIM RX6 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+ {"SLIM RX7 MUX", "AIF_MIX1_PB", "AIF MIX1 PB"},
+
+ {"SLIM RX0", NULL, "SLIM RX0 MUX"},
+ {"SLIM RX1", NULL, "SLIM RX1 MUX"},
+ {"SLIM RX2", NULL, "SLIM RX2 MUX"},
+ {"SLIM RX3", NULL, "SLIM RX3 MUX"},
+ {"SLIM RX4", NULL, "SLIM RX4 MUX"},
+ {"SLIM RX5", NULL, "SLIM RX5 MUX"},
+ {"SLIM RX6", NULL, "SLIM RX6 MUX"},
+ {"SLIM RX7", NULL, "SLIM RX7 MUX"},
+
+ /* MIXing path INT1 */
+ {"RX INT1_2 MUX", "RX0", "SLIM RX0"},
+ {"RX INT1_2 MUX", "RX1", "SLIM RX1"},
+ {"RX INT1_2 MUX", "RX2", "SLIM RX2"},
+ {"RX INT1_2 MUX", "RX3", "SLIM RX3"},
+ {"RX INT1_2 MUX", "RX4", "SLIM RX4"},
+ {"RX INT1_2 MUX", "RX5", "SLIM RX5"},
+ {"RX INT1_2 MUX", "RX6", "SLIM RX6"},
+ {"RX INT1_2 MUX", "RX7", "SLIM RX7"},
+
+ {"RX INT1_1 MIX1 INP0", "RX0", "SLIM RX0"},
+ {"RX INT1_1 MIX1 INP0", "RX1", "SLIM RX1"},
+ {"RX INT1_1 MIX1 INP0", "RX2", "SLIM RX2"},
+ {"RX INT1_1 MIX1 INP0", "RX3", "SLIM RX3"},
+ {"RX INT1_1 MIX1 INP0", "RX4", "SLIM RX4"},
+ {"RX INT1_1 MIX1 INP0", "RX5", "SLIM RX5"},
+ {"RX INT1_1 MIX1 INP0", "RX6", "SLIM RX6"},
+ {"RX INT1_1 MIX1 INP0", "RX7", "SLIM RX7"},
+ {"RX INT1_1 MIX1 INP0", "IIR0", "IIR0"},
+ {"RX INT1_1 MIX1 INP0", "IIR1", "IIR1"},
+
+ {"RX INT1_1 MIX1 INP1", "RX0", "SLIM RX0"},
+ {"RX INT1_1 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX INT1_1 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX INT1_1 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX INT1_1 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX INT1_1 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX INT1_1 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX INT1_1 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX INT1_1 MIX1 INP1", "IIR0", "IIR0"},
+ {"RX INT1_1 MIX1 INP1", "IIR1", "IIR1"},
+
+ {"RX INT1_1 MIX1 INP2", "RX0", "SLIM RX0"},
+ {"RX INT1_1 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX INT1_1 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX INT1_1 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX INT1_1 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX INT1_1 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX INT1_1 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX INT1_1 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX INT1_1 MIX1 INP2", "IIR0", "IIR0"},
+ {"RX INT1_1 MIX1 INP2", "IIR1", "IIR1"},
+
+ {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP0"},
+ {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP1"},
+ {"RX INT1_1 MIX1", NULL, "RX INT1_1 MIX1 INP2"},
+
+ //{"SPL SRC0 MUX", "SRC_IN_HPHL", "RX INT1_1 MIX1"},
+// {"RX INT1 SPLINE MIX", "HPHL Switch", "SPL SRC0 MUX"},
+ {"RX INT1 SPLINE MIX", "HPHL Native Switch", "RX INT1 NATIVE SUPPLY"},
+ {"RX INT1 SPLINE MIX", NULL, "RX INT1_1 MIX1"},
+
+ {"RX INT1 SEC MIX", NULL, "RX INT1_2 MUX"},
+ {"RX INT1 SEC MIX", NULL, "RX INT1 SPLINE MIX"},
+
+ {"RX INT1 MIX2", NULL, "RX INT1 SEC MIX"},
+
+ {"RX INT1 INTERP", NULL, "RX INT1 MIX2"},
+ {"RX INT1 DEM MUX", "CLSH_DSM_OUT", "RX INT1 INTERP"},
+ {"RX INT1 DAC", NULL, "RX INT1 DEM MUX"},
+ {"RX INT1 DAC", NULL, "RX_BIAS"},
+
+ {"HPHL PA", NULL, "RX INT1 DAC"},
+ {"HPHL", NULL, "HPHL PA"},
+
+ /* MIXing path INT2 */
+ {"RX INT2_2 MUX", "RX0", "SLIM RX0"},
+ {"RX INT2_2 MUX", "RX1", "SLIM RX1"},
+ {"RX INT2_2 MUX", "RX2", "SLIM RX2"},
+ {"RX INT2_2 MUX", "RX3", "SLIM RX3"},
+ {"RX INT2_2 MUX", "RX4", "SLIM RX4"},
+ {"RX INT2_2 MUX", "RX5", "SLIM RX5"},
+ {"RX INT2_2 MUX", "RX6", "SLIM RX6"},
+ {"RX INT2_2 MUX", "RX7", "SLIM RX7"},
+
+ {"RX INT2_1 MIX1 INP0", "RX0", "SLIM RX0"},
+ {"RX INT2_1 MIX1 INP0", "RX1", "SLIM RX1"},
+ {"RX INT2_1 MIX1 INP0", "RX2", "SLIM RX2"},
+ {"RX INT2_1 MIX1 INP0", "RX3", "SLIM RX3"},
+ {"RX INT2_1 MIX1 INP0", "RX4", "SLIM RX4"},
+ {"RX INT2_1 MIX1 INP0", "RX5", "SLIM RX5"},
+ {"RX INT2_1 MIX1 INP0", "RX6", "SLIM RX6"},
+ {"RX INT2_1 MIX1 INP0", "RX7", "SLIM RX7"},
+ {"RX INT2_1 MIX1 INP0", "IIR0", "IIR0"},
+ {"RX INT2_1 MIX1 INP0", "IIR1", "IIR1"},
+ {"RX INT2_1 MIX1 INP1", "RX0", "SLIM RX0"},
+ {"RX INT2_1 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX INT2_1 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX INT2_1 MIX1 INP1", "RX3", "SLIM RX3"},
+ {"RX INT2_1 MIX1 INP1", "RX4", "SLIM RX4"},
+ {"RX INT2_1 MIX1 INP1", "RX5", "SLIM RX5"},
+ {"RX INT2_1 MIX1 INP1", "RX6", "SLIM RX6"},
+ {"RX INT2_1 MIX1 INP1", "RX7", "SLIM RX7"},
+ {"RX INT2_1 MIX1 INP1", "IIR0", "IIR0"},
+ {"RX INT2_1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX INT2_1 MIX1 INP2", "RX0", "SLIM RX0"},
+ {"RX INT2_1 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX INT2_1 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX INT2_1 MIX1 INP2", "RX3", "SLIM RX3"},
+ {"RX INT2_1 MIX1 INP2", "RX4", "SLIM RX4"},
+ {"RX INT2_1 MIX1 INP2", "RX5", "SLIM RX5"},
+ {"RX INT2_1 MIX1 INP2", "RX6", "SLIM RX6"},
+ {"RX INT2_1 MIX1 INP2", "RX7", "SLIM RX7"},
+ {"RX INT2_1 MIX1 INP2", "IIR0", "IIR0"},
+ {"RX INT2_1 MIX1 INP2", "IIR1", "IIR1"},
+
+ {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP0"},
+ {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP1"},
+ {"RX INT2_1 MIX1", NULL, "RX INT2_1 MIX1 INP2"},
+
+// {"SPL SRC1 MUX", "SRC_IN_HPHR", "RX INT2_1 MIX1"},
+ {"RX INT2 SPLINE MIX", NULL, "RX INT2_1 MIX1"},
+// {"RX INT2 SPLINE MIX", "HPHR Switch", "SPL SRC1 MUX"},
+ {"RX INT2 SPLINE MIX", "HPHR Native Switch", "RX INT2 NATIVE SUPPLY"},
+
+ {"RX INT2 SEC MIX", NULL, "RX INT2_2 MUX"},
+ {"RX INT2 SEC MIX", NULL, "RX INT2 SPLINE MIX"},
+ {"RX INT2 MIX2", NULL, "RX INT2 SEC MIX"},
+ {"RX INT2 INTERP", NULL, "RX INT2 MIX2"},
+ {"RX INT2 DEM MUX", "CLSH_DSM_OUT", "RX INT2 INTERP"},
+ {"RX INT2 DAC", NULL, "RX INT2 DEM MUX"},
+ {"RX INT2 DAC", NULL, "RX_BIAS"},
+ {"HPHR PA", NULL, "RX INT2 DAC"},
+ {"HPHR", NULL, "HPHR PA"},
+};
+
+static int wcd9335_rx_hph_mode_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ ucontrol->value.integer.value[0] = wcd->hph_mode;
+ return 0;
+}
+
+static int wcd9335_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ u32 mode_val;
+
+ mode_val = ucontrol->value.enumerated.item[0];
+
+ if (mode_val == 0) {
+ dev_warn(component->dev, "%s:Invalid HPH Mode, default to Cls-H HiFi\n",
+ __func__);
+ mode_val = CLS_H_HIFI;
+ }
+ wcd->hph_mode = mode_val;
+ return 0;
+}
+
+static int wcd9335_ear_pa_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+
+ ear_pa_gain = snd_soc_component_read32(component, WCD9335_ANA_EAR);
+
+ ear_pa_gain = (ear_pa_gain & 0x70) >> 4;
+
+ ucontrol->value.integer.value[0] = ear_pa_gain;
+
+ return 0;
+}
+
+static int wcd9335_ear_pa_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ u8 ear_pa_gain;
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+
+ ear_pa_gain = ucontrol->value.integer.value[0] << 4;
+
+ snd_soc_component_update_bits(component, WCD9335_ANA_EAR, 0x70, ear_pa_gain);
+ return 0;
+}
+static const char * const rx_hph_mode_mux_text[] = {
+ "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI"
+};
+
+static const struct soc_enum rx_hph_mode_mux_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text),
+ rx_hph_mode_mux_text);
+
+static const struct snd_kcontrol_new wcd9335_snd_controls[] = {
+ /* -84dB min - 40dB max */
+ SOC_SINGLE_SX_TLV("RX0 Digital Volume", WCD9335_CDC_RX0_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX1 Digital Volume", WCD9335_CDC_RX1_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX2 Digital Volume", WCD9335_CDC_RX2_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX3 Digital Volume", WCD9335_CDC_RX3_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX4 Digital Volume", WCD9335_CDC_RX4_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX5 Digital Volume", WCD9335_CDC_RX5_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX6 Digital Volume", WCD9335_CDC_RX6_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX7 Digital Volume", WCD9335_CDC_RX7_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX8 Digital Volume", WCD9335_CDC_RX8_RX_VOL_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX0 Mix Digital Volume",
+ WCD9335_CDC_RX0_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX1 Mix Digital Volume",
+ WCD9335_CDC_RX1_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX2 Mix Digital Volume",
+ WCD9335_CDC_RX2_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX3 Mix Digital Volume",
+ WCD9335_CDC_RX3_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX4 Mix Digital Volume",
+ WCD9335_CDC_RX4_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX5 Mix Digital Volume",
+ WCD9335_CDC_RX5_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX6 Mix Digital Volume",
+ WCD9335_CDC_RX6_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX7 Mix Digital Volume",
+ WCD9335_CDC_RX7_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_SINGLE_SX_TLV("RX8 Mix Digital Volume",
+ WCD9335_CDC_RX8_RX_VOL_MIX_CTL,
+ 0, -84, 40, digital_gain),
+ SOC_ENUM("RX INT0_1 HPF cut off", cf_int0_1_enum),
+ SOC_ENUM("RX INT0_2 HPF cut off", cf_int0_2_enum),
+ SOC_ENUM("RX INT1_1 HPF cut off", cf_int1_1_enum),
+ SOC_ENUM("RX INT1_2 HPF cut off", cf_int1_2_enum),
+ SOC_ENUM("RX INT2_1 HPF cut off", cf_int2_1_enum),
+ SOC_ENUM("RX INT2_2 HPF cut off", cf_int2_2_enum),
+ SOC_ENUM("RX INT3_1 HPF cut off", cf_int3_1_enum),
+ SOC_ENUM("RX INT3_2 HPF cut off", cf_int3_2_enum),
+ SOC_ENUM("RX INT4_1 HPF cut off", cf_int4_1_enum),
+ SOC_ENUM("RX INT4_2 HPF cut off", cf_int4_2_enum),
+ SOC_ENUM("RX INT5_1 HPF cut off", cf_int5_1_enum),
+ SOC_ENUM("RX INT5_2 HPF cut off", cf_int5_2_enum),
+ SOC_ENUM("RX INT6_1 HPF cut off", cf_int6_1_enum),
+ SOC_ENUM("RX INT6_2 HPF cut off", cf_int6_2_enum),
+ SOC_ENUM("RX INT7_1 HPF cut off", cf_int7_1_enum),
+ SOC_ENUM("RX INT7_2 HPF cut off", cf_int7_2_enum),
+ SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum),
+ SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum),
+ SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
+ wcd9335_get_compander, wcd9335_set_compander),
+ SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
+ wcd9335_get_compander, wcd9335_set_compander),
+ SOC_SINGLE_EXT("COMP3 Switch", SND_SOC_NOPM, COMPANDER_3, 1, 0,
+ wcd9335_get_compander, wcd9335_set_compander),
+ SOC_SINGLE_EXT("COMP4 Switch", SND_SOC_NOPM, COMPANDER_4, 1, 0,
+ wcd9335_get_compander, wcd9335_set_compander),
+ SOC_SINGLE_EXT("COMP5 Switch", SND_SOC_NOPM, COMPANDER_5, 1, 0,
+ wcd9335_get_compander, wcd9335_set_compander),
+ SOC_SINGLE_EXT("COMP6 Switch", SND_SOC_NOPM, COMPANDER_6, 1, 0,
+ wcd9335_get_compander, wcd9335_set_compander),
+ SOC_SINGLE_EXT("COMP7 Switch", SND_SOC_NOPM, COMPANDER_7, 1, 0,
+ wcd9335_get_compander, wcd9335_set_compander),
+ SOC_SINGLE_EXT("COMP8 Switch", SND_SOC_NOPM, COMPANDER_8, 1, 0,
+ wcd9335_get_compander, wcd9335_set_compander),
+ SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum,
+ wcd9335_rx_hph_mode_get, wcd9335_rx_hph_mode_put),
+
+ /* Gain Controls */
+ SOC_ENUM_EXT("EAR PA Gain", wcd9335_ear_pa_gain_enum,
+ wcd9335_ear_pa_gain_get, wcd9335_ear_pa_gain_put),
+
+ SOC_SINGLE_TLV("HPHL Volume", WCD9335_HPH_L_EN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("HPHR Volume", WCD9335_HPH_R_EN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT1 Volume", WCD9335_DIFF_LO_LO1_COMPANDER,
+ 3, 16, 1, line_gain),
+ SOC_SINGLE_TLV("LINEOUT2 Volume", WCD9335_DIFF_LO_LO2_COMPANDER,
+ 3, 16, 1, line_gain),
+ SOC_SINGLE_TLV("LINEOUT3 Volume", WCD9335_SE_LO_LO3_GAIN, 0, 20, 1,
+ line_gain),
+ SOC_SINGLE_TLV("LINEOUT4 Volume", WCD9335_SE_LO_LO4_GAIN, 0, 20, 1,
+ line_gain),
+};
+
+static int wcd9335_int_dem_inp_mux_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int val;
+ unsigned short look_ahead_dly_reg = 0;
+
+ val = ucontrol->value.enumerated.item[0];
+ if (val >= e->items)
+ return -EINVAL;
+
+ if (e->reg == WCD9335_CDC_RX0_RX_PATH_SEC0)
+ look_ahead_dly_reg = WCD9335_CDC_RX0_RX_PATH_CFG0;
+ else if (e->reg == WCD9335_CDC_RX1_RX_PATH_SEC0)
+ look_ahead_dly_reg = WCD9335_CDC_RX1_RX_PATH_CFG0;
+ else if (e->reg == WCD9335_CDC_RX2_RX_PATH_SEC0)
+ look_ahead_dly_reg = WCD9335_CDC_RX2_RX_PATH_CFG0;
+
+ /* Set Look Ahead Delay */
+ snd_soc_component_update_bits(component, look_ahead_dly_reg,
+ 0x08, (val ? 0x08 : 0x00));
+ /* Set DEM INP Select */
+ return snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
+}
+
+static int wcd9335_config_compander(struct snd_soc_component *component, int interp_n,
+ int event)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int comp;
+ u16 comp_ctl0_reg, rx_path_cfg0_reg;
+
+ /* EAR does not have compander */
+ if (!interp_n)
+ return 0;
+
+ comp = interp_n - 1;
+ if (!wcd->comp_enabled[comp])
+ return 0;
+
+ comp_ctl0_reg = WCD9335_CDC_COMPANDER1_CTL0 + (comp * 8);
+ rx_path_cfg0_reg = WCD9335_CDC_RX1_RX_PATH_CFG0 + (comp * 20);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ /* Enable Compander Clock */
+
+ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x01, 0x01);
+ /* Reset comander */
+ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x02, 0x02);
+ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x02, 0x00);
+ /* Enables DRE in this path */
+ snd_soc_component_update_bits(component, rx_path_cfg0_reg, 0x02, 0x02);
+ }
+
+ if (SND_SOC_DAPM_EVENT_OFF(event)) {
+ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x04, 0x04);
+ snd_soc_component_update_bits(component, rx_path_cfg0_reg, 0x02, 0x00);
+ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x02, 0x02);
+ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x02, 0x00);
+ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x01, 0x00);
+ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x04, 0x00);
+ }
+
+ return 0;
+}
+
+static int wcd9335_codec_aif4_mixer_switch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_dapm_kcontrol_component(kcontrol);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ if (test_bit(AIF4_SWITCH_VALUE, &wcd->status_mask))
+ ucontrol->value.integer.value[0] = 1;
+ else
+ ucontrol->value.integer.value[0] = 0;
+
+ return 0;
+}
+
+static int wcd9335_codec_aif4_mixer_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct snd_soc_dapm_update *update = NULL;
+
+ if (ucontrol->value.integer.value[0]) {
+ snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, update);
+ set_bit(AIF4_SWITCH_VALUE, &wcd->status_mask);
+ } else {
+ snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, update);
+ clear_bit(AIF4_SWITCH_VALUE, &wcd->status_mask);
+ }
+
+ return 1;
+}
+
+static int _wcd9335_codec_enable_mclk(struct snd_soc_component *component, int enable)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int ret = 0;
+
+ if (!wcd->ext_clk) {
+ dev_err(wcd->dev, "%s: wcd ext clock is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ if (enable) {
+ ret = wcd9335_cdc_req_mclk_enable(wcd, true);
+ if (ret)
+ return ret;
+
+ set_bit(AUDIO_NOMINAL, &wcd->status_mask);
+ wcd9335_codec_apply_sido_voltage(wcd,
+ SIDO_VOLTAGE_NOMINAL_MV);
+ } else {
+ clear_bit(AUDIO_NOMINAL, &wcd->status_mask);
+ wcd9335_codec_update_sido_voltage(wcd,
+ sido_buck_svs_voltage);
+ wcd9335_cdc_req_mclk_enable(wcd, false);
+ }
+
+ return ret;
+}
+
+static int wcd9335_codec_enable_mclk(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ return _wcd9335_codec_enable_mclk(component, true);
+ case SND_SOC_DAPM_POST_PMD:
+ return _wcd9335_codec_enable_mclk(component, false);
+ }
+
+ return 0;
+}
+static const char * const spl_src1_mux_text[] = {
+ "ZERO", "SRC_IN_HPHR", "SRC_IN_LO2",
+};
+
+static const char * const spl_src2_mux_text[] = {
+ "ZERO", "SRC_IN_LO3", "SRC_IN_SPKRL",
+};
+
+static const char * const spl_src3_mux_text[] = {
+ "ZERO", "SRC_IN_LO4", "SRC_IN_SPKRR",
+};
+
+static const char * const rx_int0_7_mix_mux_text[] = {
+ "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+ "RX6", "RX7", "PROXIMITY"
+};
+
+static const char * const rx_int_mix_mux_text[] = {
+ "ZERO", "RX0", "RX1", "RX2", "RX3", "RX4", "RX5",
+ "RX6", "RX7"
+};
+
+static const char * const rx_prim_mix_text[] = {
+ "ZERO", "DEC0", "DEC1", "IIR0", "IIR1", "RX0", "RX1", "RX2",
+ "RX3", "RX4", "RX5", "RX6", "RX7"
+};
+
+static const char * const rx_int_dem_inp_mux_text[] = {
+ "NORMAL_DSM_OUT", "CLSH_DSM_OUT",
+};
+
+static const char * const rx_int0_interp_mux_text[] = {
+ "ZERO", "RX INT0 MIX2",
+};
+
+static const char * const rx_int1_interp_mux_text[] = {
+ "ZERO", "RX INT1 MIX2",
+};
+
+static const char * const rx_int2_interp_mux_text[] = {
+ "ZERO", "RX INT2 MIX2",
+};
+
+static const char * const rx_int3_interp_mux_text[] = {
+ "ZERO", "RX INT3 MIX2",
+};
+
+static const char * const rx_int4_interp_mux_text[] = {
+ "ZERO", "RX INT4 MIX2",
+};
+
+static const char * const rx_int5_interp_mux_text[] = {
+ "ZERO", "RX INT5 MIX2",
+};
+
+static const char * const rx_int6_interp_mux_text[] = {
+ "ZERO", "RX INT6 MIX2",
+};
+
+static const char * const rx_int7_interp_mux_text[] = {
+ "ZERO", "RX INT7 MIX2",
+};
+
+static const char * const rx_int8_interp_mux_text[] = {
+ "ZERO", "RX INT8 SEC MIX"
+};
+
+static const char * const rx_echo_mux_text[] = {
+ "ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2", "RX_MIX3", "RX_MIX4",
+ "RX_MIX5", "RX_MIX6", "RX_MIX7", "RX_MIX8",
+};
+
+static const char * const anc0_fb_mux_text[] = {
+ "ZERO", "ANC_IN_HPHL", "ANC_IN_EAR", "ANC_IN_EAR_SPKR",
+ "ANC_IN_LO1"
+};
+
+static const char * const anc1_fb_mux_text[] = {
+ "ZERO", "ANC_IN_HPHR", "ANC_IN_LO2"
+};
+
+static const struct soc_enum spl_src0_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 0, 3,
+ spl_src0_mux_text);
+
+static const struct soc_enum spl_src1_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 2, 3,
+ spl_src1_mux_text);
+
+static const struct soc_enum spl_src2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 4, 3,
+ spl_src2_mux_text);
+
+static const struct soc_enum spl_src3_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0, 6, 3,
+ spl_src3_mux_text);
+
+static const struct soc_enum rx_int0_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 0, 10,
+ rx_int0_7_mix_mux_text);
+
+static const struct soc_enum rx_int1_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int2_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int3_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int4_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int5_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int6_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int7_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 0, 10,
+ rx_int0_7_mix_mux_text);
+
+static const struct soc_enum rx_int8_2_mux_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 0, 9,
+ rx_int_mix_mux_text);
+
+static const struct soc_enum rx_int0_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int1_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int2_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int3_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int4_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int5_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int6_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int7_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp0_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 0, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp1_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int8_1_mix_inp2_chain_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1, 4, 13,
+ rx_prim_mix_text);
+
+static const struct soc_enum rx_int0_dem_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_SEC0, 0,
+ ARRAY_SIZE(rx_int_dem_inp_mux_text),
+ rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int1_dem_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_SEC0, 0,
+ ARRAY_SIZE(rx_int_dem_inp_mux_text),
+ rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int2_dem_inp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_SEC0, 0,
+ ARRAY_SIZE(rx_int_dem_inp_mux_text),
+ rx_int_dem_inp_mux_text);
+
+static const struct soc_enum rx_int0_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX0_RX_PATH_CTL, 5, 2,
+ rx_int0_interp_mux_text);
+
+static const struct soc_enum rx_int1_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX1_RX_PATH_CTL, 5, 2,
+ rx_int1_interp_mux_text);
+
+static const struct soc_enum rx_int2_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX2_RX_PATH_CTL, 5, 2,
+ rx_int2_interp_mux_text);
+
+static const struct soc_enum rx_int3_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX3_RX_PATH_CTL, 5, 2,
+ rx_int3_interp_mux_text);
+
+static const struct soc_enum rx_int4_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX4_RX_PATH_CTL, 5, 2,
+ rx_int4_interp_mux_text);
+
+static const struct soc_enum rx_int5_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX5_RX_PATH_CTL, 5, 2,
+ rx_int5_interp_mux_text);
+
+static const struct soc_enum rx_int6_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX6_RX_PATH_CTL, 5, 2,
+ rx_int6_interp_mux_text);
+
+static const struct soc_enum rx_int7_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX7_RX_PATH_CTL, 5, 2,
+ rx_int7_interp_mux_text);
+
+static const struct soc_enum rx_int8_interp_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX8_RX_PATH_CTL, 5, 2,
+ rx_int8_interp_mux_text);
+
+static const struct soc_enum anc0_fb_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_ANC_CFG0, 0, 5,
+ anc0_fb_mux_text);
+
+static const struct soc_enum anc1_fb_mux_enum =
+ SOC_ENUM_SINGLE(WCD9335_CDC_RX_INP_MUX_ANC_CFG0, 3, 3,
+ anc1_fb_mux_text);
+
+static const struct snd_kcontrol_new rx_int0_dem_inp_mux =
+ SOC_DAPM_ENUM_EXT("RX INT0 DEM MUX Mux", rx_int0_dem_inp_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ wcd9335_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int1_dem_inp_mux =
+ SOC_DAPM_ENUM_EXT("RX INT1 DEM MUX Mux", rx_int1_dem_inp_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ wcd9335_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new rx_int2_dem_inp_mux =
+ SOC_DAPM_ENUM_EXT("RX INT2 DEM MUX Mux", rx_int2_dem_inp_mux_enum,
+ snd_soc_dapm_get_enum_double,
+ wcd9335_int_dem_inp_mux_put);
+
+static const struct snd_kcontrol_new spl_src0_mux =
+ SOC_DAPM_ENUM("SPL SRC0 MUX Mux", spl_src0_mux_chain_enum);
+
+static const struct snd_kcontrol_new spl_src1_mux =
+ SOC_DAPM_ENUM("SPL SRC1 MUX Mux", spl_src1_mux_chain_enum);
+
+static const struct snd_kcontrol_new spl_src2_mux =
+ SOC_DAPM_ENUM("SPL SRC2 MUX Mux", spl_src2_mux_chain_enum);
+
+static const struct snd_kcontrol_new spl_src3_mux =
+ SOC_DAPM_ENUM("SPL SRC3 MUX Mux", spl_src3_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_2_mux =
+ SOC_DAPM_ENUM("RX INT0_2 MUX Mux", rx_int0_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_2_mux =
+ SOC_DAPM_ENUM("RX INT1_2 MUX Mux", rx_int1_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_2_mux =
+ SOC_DAPM_ENUM("RX INT2_2 MUX Mux", rx_int2_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_2_mux =
+ SOC_DAPM_ENUM("RX INT3_2 MUX Mux", rx_int3_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_2_mux =
+ SOC_DAPM_ENUM("RX INT4_2 MUX Mux", rx_int4_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_2_mux =
+ SOC_DAPM_ENUM("RX INT5_2 MUX Mux", rx_int5_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_2_mux =
+ SOC_DAPM_ENUM("RX INT6_2 MUX Mux", rx_int6_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_2_mux =
+ SOC_DAPM_ENUM("RX INT7_2 MUX Mux", rx_int7_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_2_mux =
+ SOC_DAPM_ENUM("RX INT8_2 MUX Mux", rx_int8_2_mux_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT0_1 MIX1 INP0 Mux", rx_int0_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT0_1 MIX1 INP1 Mux", rx_int0_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT0_1 MIX1 INP2 Mux", rx_int0_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT1_1 MIX1 INP0 Mux", rx_int1_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT1_1 MIX1 INP1 Mux", rx_int1_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int1_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT1_1 MIX1 INP2 Mux", rx_int1_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT2_1 MIX1 INP0 Mux", rx_int2_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT2_1 MIX1 INP1 Mux", rx_int2_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int2_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT2_1 MIX1 INP2 Mux", rx_int2_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT3_1 MIX1 INP0 Mux", rx_int3_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT3_1 MIX1 INP1 Mux", rx_int3_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int3_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT3_1 MIX1 INP2 Mux", rx_int3_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT4_1 MIX1 INP0 Mux", rx_int4_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT4_1 MIX1 INP1 Mux", rx_int4_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int4_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT4_1 MIX1 INP2 Mux", rx_int4_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT5_1 MIX1 INP0 Mux", rx_int5_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT5_1 MIX1 INP1 Mux", rx_int5_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int5_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT5_1 MIX1 INP2 Mux", rx_int5_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT6_1 MIX1 INP0 Mux", rx_int6_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT6_1 MIX1 INP1 Mux", rx_int6_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int6_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT6_1 MIX1 INP2 Mux", rx_int6_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT7_1 MIX1 INP0 Mux", rx_int7_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT7_1 MIX1 INP1 Mux", rx_int7_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int7_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT7_1 MIX1 INP2 Mux", rx_int7_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp0_mux =
+ SOC_DAPM_ENUM("RX INT8_1 MIX1 INP0 Mux", rx_int8_1_mix_inp0_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp1_mux =
+ SOC_DAPM_ENUM("RX INT8_1 MIX1 INP1 Mux", rx_int8_1_mix_inp1_chain_enum);
+
+static const struct snd_kcontrol_new rx_int8_1_mix_inp2_mux =
+ SOC_DAPM_ENUM("RX INT8_1 MIX1 INP2 Mux", rx_int8_1_mix_inp2_chain_enum);
+
+static const struct snd_kcontrol_new rx_int0_interp_mux =
+ SOC_DAPM_ENUM("RX INT0 INTERP Mux", rx_int0_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int1_interp_mux =
+ SOC_DAPM_ENUM("RX INT1 INTERP Mux", rx_int1_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int2_interp_mux =
+ SOC_DAPM_ENUM("RX INT2 INTERP Mux", rx_int2_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int3_interp_mux =
+ SOC_DAPM_ENUM("RX INT3 INTERP Mux", rx_int3_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int4_interp_mux =
+ SOC_DAPM_ENUM("RX INT4 INTERP Mux", rx_int4_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int5_interp_mux =
+ SOC_DAPM_ENUM("RX INT5 INTERP Mux", rx_int5_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int6_interp_mux =
+ SOC_DAPM_ENUM("RX INT6 INTERP Mux", rx_int6_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int7_interp_mux =
+ SOC_DAPM_ENUM("RX INT7 INTERP Mux", rx_int7_interp_mux_enum);
+
+static const struct snd_kcontrol_new rx_int8_interp_mux =
+ SOC_DAPM_ENUM("RX INT8 INTERP Mux", rx_int8_interp_mux_enum);
+
+static const struct snd_kcontrol_new aif4_switch_mixer_controls =
+ SOC_SINGLE_EXT("Switch", SND_SOC_NOPM,
+ 0, 1, 0, wcd9335_codec_aif4_mixer_switch_get,
+ wcd9335_codec_aif4_mixer_switch_put);
+
+static const struct snd_kcontrol_new anc_hphl_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_hphr_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_ear_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_lineout1_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc_lineout2_switch =
+ SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux0_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux1_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux2_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux3_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux4_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux5_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux6_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux7_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new adc_us_mux8_switch =
+ SOC_DAPM_SINGLE("US_Switch", SND_SOC_NOPM, 0, 1, 0);
+
+static const struct snd_kcontrol_new anc0_fb_mux =
+ SOC_DAPM_ENUM("ANC0 FB MUX Mux", anc0_fb_mux_enum);
+
+static const struct snd_kcontrol_new anc1_fb_mux =
+ SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
+
+static const struct snd_soc_dapm_widget wcd9335_dapm_widgets[] = {
+ SND_SOC_DAPM_OUTPUT("EAR"),
+ SND_SOC_DAPM_OUTPUT("ANC EAR"),
+ SND_SOC_DAPM_OUTPUT("HPHL"),
+ SND_SOC_DAPM_OUTPUT("HPHR"),
+ SND_SOC_DAPM_OUTPUT("SPK1 OUT"),
+ SND_SOC_DAPM_OUTPUT("SPK2 OUT"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT3"),
+ SND_SOC_DAPM_OUTPUT("LINEOUT4"),
+ SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
+ AIF1_PB, 0, wcd9335_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
+ AIF2_PB, 0, wcd9335_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
+ AIF3_PB, 0, wcd9335_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_AIF_IN_E("AIF4 PB", "AIF4 Playback", 0, SND_SOC_NOPM,
+ AIF4_PB, 0, wcd9335_codec_enable_slimrx,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("SLIM RX0 MUX", SND_SOC_NOPM, WCD9335_RX0, 0,
+ &slim_rx_mux[WCD9335_RX0]),
+ SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, WCD9335_RX1, 0,
+ &slim_rx_mux[WCD9335_RX1]),
+ SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, WCD9335_RX2, 0,
+ &slim_rx_mux[WCD9335_RX2]),
+ SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, WCD9335_RX3, 0,
+ &slim_rx_mux[WCD9335_RX3]),
+ SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, WCD9335_RX4, 0,
+ &slim_rx_mux[WCD9335_RX4]),
+ SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, WCD9335_RX5, 0,
+ &slim_rx_mux[WCD9335_RX5]),
+ SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, WCD9335_RX6, 0,
+ &slim_rx_mux[WCD9335_RX6]),
+ SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, WCD9335_RX7, 0,
+ &slim_rx_mux[WCD9335_RX7]),
+ SND_SOC_DAPM_MIXER("SLIM RX0", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MUX_E("RX INT0_2 MUX", WCD9335_CDC_RX0_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int0_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("RX INT1_2 MUX", WCD9335_CDC_RX1_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int1_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("RX INT2_2 MUX", WCD9335_CDC_RX2_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int2_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("RX INT3_2 MUX", WCD9335_CDC_RX3_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int3_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("RX INT4_2 MUX", WCD9335_CDC_RX4_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int4_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("RX INT5_2 MUX", WCD9335_CDC_RX5_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int5_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("RX INT6_2 MUX", WCD9335_CDC_RX6_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int6_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("RX INT7_2 MUX", WCD9335_CDC_RX7_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int7_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX_E("RX INT8_2 MUX", WCD9335_CDC_RX8_RX_PATH_MIX_CTL,
+ 5, 0, &rx_int8_2_mux, wcd9335_codec_enable_mix_path,
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int0_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int0_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT0_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int0_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int1_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int1_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT1_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int1_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int2_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int2_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT2_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int2_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int3_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int3_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT3_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int3_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int4_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int4_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT4_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int4_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int5_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int5_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT5_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int5_1_mix_inp2_mux),
+ SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP0", SND_SOC_NOPM, 0, 0,
+ &rx_int6_1_mix_inp0_mux),
+ SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_int6_1_mix_inp1_mux),
+ SND_SOC_DAPM_MUX("RX INT6_1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_int6_1_mix_inp2_mux),
+ SND_SOC_DAPM_MIXER("RX INT0_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT0 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT1_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT1 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+ rx_int1_spline_mix_switch,
+ ARRAY_SIZE(rx_int1_spline_mix_switch)),
+ SND_SOC_DAPM_MIXER("RX INT1 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT2_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT2 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+ rx_int2_spline_mix_switch,
+ ARRAY_SIZE(rx_int2_spline_mix_switch)),
+ SND_SOC_DAPM_MIXER("RX INT2 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT3_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT3 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+ rx_int3_spline_mix_switch,
+ ARRAY_SIZE(rx_int3_spline_mix_switch)),
+ SND_SOC_DAPM_MIXER("RX INT3 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT4_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT4 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+ rx_int4_spline_mix_switch,
+ ARRAY_SIZE(rx_int4_spline_mix_switch)),
+ SND_SOC_DAPM_MIXER("RX INT4 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT5_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT5 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+ rx_int5_spline_mix_switch,
+ ARRAY_SIZE(rx_int5_spline_mix_switch)),
+ SND_SOC_DAPM_MIXER("RX INT5 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("RX INT6_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT6 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+ rx_int6_spline_mix_switch,
+ ARRAY_SIZE(rx_int6_spline_mix_switch)),
+ SND_SOC_DAPM_MIXER("RX INT6 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MIXER("RX INT7_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT7 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT7 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+ rx_int7_spline_mix_switch,
+ ARRAY_SIZE(rx_int7_spline_mix_switch)),
+
+ SND_SOC_DAPM_MIXER("RX INT8_1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT8 SEC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT8 SPLINE MIX", SND_SOC_NOPM, 0, 0,
+ rx_int8_spline_mix_switch,
+ ARRAY_SIZE(rx_int8_spline_mix_switch)),
+
+ SND_SOC_DAPM_MIXER("RX INT0 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT1 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT2 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT3 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT4 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT5 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT6 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX INT7 MIX2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_SUPPLY("RX INT1 NATIVE SUPPLY", SND_SOC_NOPM,
+ INTERP_HPHL, 0, wcd9335_enable_native_supply,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("RX INT2 NATIVE SUPPLY", SND_SOC_NOPM,
+ INTERP_HPHR, 0, wcd9335_enable_native_supply,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("RX INT3 NATIVE SUPPLY", SND_SOC_NOPM,
+ INTERP_LO1, 0, wcd9335_enable_native_supply,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_SUPPLY("RX INT4 NATIVE SUPPLY", SND_SOC_NOPM,
+ INTERP_LO2, 0, wcd9335_enable_native_supply,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+ SND_SOC_DAPM_MUX("RX INT0 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_int0_dem_inp_mux),
+ SND_SOC_DAPM_MUX("RX INT1 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_int1_dem_inp_mux),
+ SND_SOC_DAPM_MUX("RX INT2 DEM MUX", SND_SOC_NOPM, 0, 0,
+ &rx_int2_dem_inp_mux),
+
+ SND_SOC_DAPM_MUX_E("RX INT0 INTERP", SND_SOC_NOPM,
+ INTERP_EAR, 0, &rx_int0_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT1 INTERP", SND_SOC_NOPM,
+ INTERP_HPHL, 0, &rx_int1_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT2 INTERP", SND_SOC_NOPM,
+ INTERP_HPHR, 0, &rx_int2_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT3 INTERP", SND_SOC_NOPM,
+ INTERP_LO1, 0, &rx_int3_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT4 INTERP", SND_SOC_NOPM,
+ INTERP_LO2, 0, &rx_int4_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT5 INTERP", SND_SOC_NOPM,
+ INTERP_LO3, 0, &rx_int5_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT6 INTERP", SND_SOC_NOPM,
+ INTERP_LO4, 0, &rx_int6_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT7 INTERP", SND_SOC_NOPM,
+ INTERP_SPKR1, 0, &rx_int7_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX_E("RX INT8 INTERP", SND_SOC_NOPM,
+ INTERP_SPKR2, 0, &rx_int8_interp_mux,
+ wcd9335_codec_enable_interpolator,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_DAC_E("RX INT0 DAC", NULL, SND_SOC_NOPM,
+ 0, 0, wcd9335_codec_ear_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT1 DAC", NULL, WCD9335_ANA_HPH,
+ 5, 0, wcd9335_codec_hphl_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT2 DAC", NULL, WCD9335_ANA_HPH,
+ 4, 0, wcd9335_codec_hphr_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT3 DAC", NULL, SND_SOC_NOPM,
+ 0, 0, wcd9335_codec_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT4 DAC", NULL, SND_SOC_NOPM,
+ 0, 0, wcd9335_codec_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT5 DAC", NULL, SND_SOC_NOPM,
+ 0, 0, wcd9335_codec_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_DAC_E("RX INT6 DAC", NULL, SND_SOC_NOPM,
+ 0, 0, wcd9335_codec_lineout_dac_event,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("HPHL PA", WCD9335_ANA_HPH, 7, 0, NULL, 0,
+ wcd9335_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("HPHR PA", WCD9335_ANA_HPH, 6, 0, NULL, 0,
+ wcd9335_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_PGA_E("EAR PA", WCD9335_ANA_EAR, 7, 0, NULL, 0,
+ wcd9335_codec_enable_ear_pa,
+ SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT1 PA", WCD9335_ANA_LO_1_2, 7, 0, NULL, 0,
+ wcd9335_codec_enable_lineout_pa,
+ SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD9335_ANA_LO_1_2, 6, 0, NULL, 0,
+ wcd9335_codec_enable_lineout_pa,
+ SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT3 PA", WCD9335_ANA_LO_3_4, 7, 0, NULL, 0,
+ wcd9335_codec_enable_lineout_pa,
+ SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_PGA_E("LINEOUT4 PA", WCD9335_ANA_LO_3_4, 6, 0, NULL, 0,
+ wcd9335_codec_enable_lineout_pa,
+ SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+ wcd9335_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ wcd9335_codec_enable_mclk, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+};
+
+static int wcd9335_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+{
+ struct wcd9335_priv *wcd = snd_soc_component_get_drvdata(dai->component);
+ u32 i = 0;
+ struct wcd_slim_ch *ch;
+ switch (dai->id) {
+ case AIF1_PB:
+ case AIF2_PB:
+ case AIF3_PB:
+ case AIF4_PB:
+ case AIF_MIX1_PB:
+ if (!rx_slot || !rx_num) {
+ dev_err(wcd->dev, "Invalid rx_slot %p or rx_num %p\n",
+ rx_slot, rx_num);
+ return -EINVAL;
+ }
+ list_for_each_entry(ch, &wcd->dai[dai->id].wcd_slim_ch_list,
+ list) {
+ dev_err(wcd->dev ,"slot_num %u ch->ch_num %d\n",
+ i, ch->ch_num);
+ rx_slot[i++] = ch->ch_num;
+ }
+ *rx_num = i;
+ break;
+ case AIF1_CAP:
+ case AIF2_CAP:
+ case AIF3_CAP:
+ case AIF4_MAD_TX:
+ case AIF4_VIFEED:
+ if (!tx_slot || !tx_num) {
+ dev_err(wcd->dev, "Invalid tx_slot %p or tx_num %p\n",
+ tx_slot, tx_num);
+ return -EINVAL;
+ }
+ list_for_each_entry(ch, &wcd->dai[dai->id].wcd_slim_ch_list,
+ list) {
+ tx_slot[i++] = ch->ch_num;
+ }
+ *tx_num = i;
+ break;
+
+ default:
+ dev_err(wcd->dev, "Invalid DAI ID %x\n", dai->id);
+ break;
+ }
+
+ return 0;
+}
+
+static int mywcd_slim_init_slimslave(struct wcd_slim_data *wcd, u8 wcd_slim_pgd_la,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ int ret = 0;
+ int i;
+
+ if (wcd->rx_chs) {
+ wcd->num_rx_port = rx_num;
+ for (i = 0; i < rx_num; i++) {
+ wcd->rx_chs[i].ch_num = rx_slot[i];
+ INIT_LIST_HEAD(&wcd->rx_chs[i].list);
+ }
+#if 0
+ ret = wcd_slim_alloc_slim_sh_ch(wcd->slim, wcd_slim_pgd_la,
+ wcd->num_rx_port,
+ wcd->rx_chs,
+ SLIM_SINK);
+ if (ret) {
+ pr_err("%s: Failed to alloc %d rx slimbus channels\n",
+ __func__, wcd->num_rx_port);
+ kfree(wcd->rx_chs);
+ wcd->rx_chs = NULL;
+ wcd->num_rx_port = 0;
+ }
+#endif
+ } else {
+ pr_err("Not able to allocate memory for %d slimbus rx ports\n",
+ wcd->num_rx_port);
+ }
+
+ if (wcd->tx_chs) {
+ wcd->num_tx_port = tx_num;
+ for (i = 0; i < tx_num; i++) {
+ wcd->tx_chs[i].ch_num = tx_slot[i];
+ INIT_LIST_HEAD(&wcd->tx_chs[i].list);
+ }
+#if 0
+ ret = wcd_slim_alloc_slim_sh_ch(wcd->slim, wcd_slim_pgd_la,
+ wcd->num_tx_port,
+ wcd->tx_chs,
+ SLIM_SRC);
+ if (ret) {
+ pr_err("%s: Failed to alloc %d tx slimbus channels\n",
+ __func__, wcd->num_tx_port);
+ kfree(wcd->tx_chs);
+ wcd->tx_chs = NULL;
+ wcd->num_tx_port = 0;
+ }
+#endif
+ } else {
+ pr_err("Not able to allocate memory for %d slimbus tx ports\n",
+ wcd->num_tx_port);
+ }
+}
+
+static int wcd9335_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+{
+ struct wcd9335_priv *wcd;
+
+ wcd = snd_soc_component_get_drvdata(dai->component);
+
+ if (!tx_slot || !rx_slot) {
+ dev_err(wcd->dev, "Invalid tx_slot=%p, rx_slot=%p\n",
+ tx_slot, rx_slot);
+ return -EINVAL;
+ }
+
+ if (wcd->intf_type == WCD_INTERFACE_TYPE_SLIMBUS) {
+// //FIXME ..
+ mywcd_slim_init_slimslave(wcd->slim_data, wcd->slim->laddr,
+ tx_num, tx_slot, rx_num, rx_slot);
+ }
+ return 0;
+}
+
+static int wcd9335_set_mix_interpolator_rate(struct snd_soc_dai *dai,
+ u8 int_mix_fs_rate_reg_val,
+ u32 sample_rate)
+{
+ u8 int_2_inp;
+ u32 j;
+ u16 int_mux_cfg1, int_fs_reg;
+ u8 int_mux_cfg1_val;
+ struct snd_soc_component *component = dai->component;
+ struct wcd_slim_ch *ch;
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ list_for_each_entry(ch, &wcd->dai[dai->id].wcd_slim_ch_list, list) {
+ int_2_inp = ch->port + INTn_2_INP_SEL_RX0 -
+ WCD9335_RX_PORT_START_NUMBER;
+ if ((int_2_inp < INTn_2_INP_SEL_RX0) ||
+ (int_2_inp > INTn_2_INP_SEL_RX7)) {
+ pr_err("%s: Invalid RX%u port, Dai ID is %d\n",
+ __func__,
+ (ch->port - WCD9335_RX_PORT_START_NUMBER),
+ dai->id);
+ return -EINVAL;
+ }
+
+ int_mux_cfg1 = WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1;
+ for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) {
+ int_mux_cfg1_val = snd_soc_component_read32(component, int_mux_cfg1) &
+ 0x0F;
+ if (int_mux_cfg1_val == int_2_inp) {
+ int_fs_reg = WCD9335_CDC_RX0_RX_PATH_MIX_CTL +
+ 20 * j;
+ snd_soc_component_update_bits(component, int_fs_reg,
+ 0x0F, int_mix_fs_rate_reg_val);
+ }
+ int_mux_cfg1 += 2;
+ }
+ }
+ return 0;
+}
+
+static int wcd9335_set_prim_interpolator_rate(struct snd_soc_dai *dai,
+ u8 int_prim_fs_rate_reg_val,
+ u32 sample_rate)
+{
+ u8 int_1_mix1_inp;
+ u32 j;
+ u16 int_mux_cfg0, int_mux_cfg1;
+ u16 int_fs_reg;
+ u8 int_mux_cfg0_val, int_mux_cfg1_val;
+ u8 inp0_sel, inp1_sel, inp2_sel;
+ struct snd_soc_component *component = dai->component;
+ struct wcd_slim_ch *ch;
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ list_for_each_entry(ch, &wcd->dai[dai->id].wcd_slim_ch_list, list) {
+ int_1_mix1_inp = ch->port + INTn_1_MIX_INP_SEL_RX0 -
+ WCD9335_RX_PORT_START_NUMBER;
+ if ((int_1_mix1_inp < INTn_1_MIX_INP_SEL_RX0) ||
+ (int_1_mix1_inp > INTn_1_MIX_INP_SEL_RX7)) {
+ pr_err("%s: Invalid RX%u port, Dai ID is %d\n",
+ __func__,
+ (ch->port - WCD9335_RX_PORT_START_NUMBER),
+ dai->id);
+ return -EINVAL;
+ }
+
+ int_mux_cfg0 = WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0;
+
+ /*
+ * Loop through all interpolator MUX inputs and find out
+ * to which interpolator input, the slim rx port
+ * is connected
+ */
+ for (j = 0; j < WCD9335_NUM_INTERPOLATORS; j++) {
+ int_mux_cfg1 = int_mux_cfg0 + 1;
+
+ int_mux_cfg0_val = snd_soc_component_read32(component, int_mux_cfg0);
+ int_mux_cfg1_val = snd_soc_component_read32(component, int_mux_cfg1);
+ inp0_sel = int_mux_cfg0_val & 0x0F;
+ inp1_sel = (int_mux_cfg0_val >> 4) & 0x0F;
+ inp2_sel = (int_mux_cfg1_val >> 4) & 0x0F;
+ if ((inp0_sel == int_1_mix1_inp) ||
+ (inp1_sel == int_1_mix1_inp) ||
+ (inp2_sel == int_1_mix1_inp)) {
+ int_fs_reg = WCD9335_CDC_RX0_RX_PATH_CTL +
+ 20 * j;
+ /* sample_rate is in Hz */
+ if ((j == 0) && (sample_rate == 44100)) {
+ pr_info("%s: Cannot set 44.1KHz on INT0\n",
+ __func__);
+ } else
+ snd_soc_component_update_bits(component, int_fs_reg,
+ 0x0F, int_prim_fs_rate_reg_val);
+ }
+ int_mux_cfg0 += 2;
+ }
+ }
+
+ return 0;
+}
+
+static int wcd9335_set_interpolator_rate(struct snd_soc_dai *dai,
+ u32 sample_rate)
+{
+ int rate_val = 0;
+ int i, ret;
+
+ /* set mixing path rate */
+ for (i = 0; i < ARRAY_SIZE(int_mix_sample_rate_val); i++) {
+ if (sample_rate ==
+ int_mix_sample_rate_val[i].sample_rate) {
+ rate_val =
+ int_mix_sample_rate_val[i].rate_val;
+ break;
+ }
+ }
+ if ((i == ARRAY_SIZE(int_mix_sample_rate_val)) ||
+ (rate_val < 0))
+ goto prim_rate;
+ ret = wcd9335_set_mix_interpolator_rate(dai,
+ (u8) rate_val, sample_rate);
+prim_rate:
+ /* set primary path sample rate */
+ for (i = 0; i < ARRAY_SIZE(int_prim_sample_rate_val); i++) {
+ if (sample_rate ==
+ int_prim_sample_rate_val[i].sample_rate) {
+ rate_val =
+ int_prim_sample_rate_val[i].rate_val;
+ break;
+ }
+ }
+ if ((i == ARRAY_SIZE(int_prim_sample_rate_val)) ||
+ (rate_val < 0))
+ return -EINVAL;
+ ret = wcd9335_set_prim_interpolator_rate(dai,
+ (u8) rate_val, sample_rate);
+ return ret;
+}
+
+static int wcd_slim_stream_enable(struct wcd_slim_data *wcd,
+ struct wcd_slim_codec_dai_data *dai_data)
+{
+ struct slim_stream_config *cfg = &dai_data->sconfig;
+ struct list_head *wcd_slim_ch_list = &dai_data->wcd_slim_ch_list;
+ unsigned int rate = dai_data->rate;
+ unsigned int bit_width = dai_data->bit_width;
+ u8 ch_cnt = 0;
+ u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
+ u8 payload = 0;
+ u16 codec_port = 0;
+ int ret;
+// struct slim_ch prop;
+ struct wcd_slim_ch *rx;
+ int size = ARRAY_SIZE(ch_h);
+ int count = 0;
+ int i =0;
+
+ cfg->ch_count = 0;
+ /* Configure slave interface device */
+ list_for_each_entry(rx, wcd_slim_ch_list, list) {
+ payload |= 1 << rx->shift;
+ }
+#if 0
+ list_for_each_entry(rx, wcd_slim_ch_list, list) {
+ codec_port = rx->port;
+ pr_debug("%s: codec_port %d rx 0x%p, payload %d\n"
+ "wcd->rx_port_ch_reg_base0 0x%x\n"
+ "wcd->port_rx_cfg_reg_base 0x%x\n",
+ __func__, codec_port, rx, payload,
+ wcd->rx_port_ch_reg_base,
+ wcd->port_rx_cfg_reg_base);
+
+ /* look for the valid port range and chose the
+ * payload accordingly
+ */
+ /* write to interface device */
+ ret = regmap_write(wcd->if_regmap,
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0(
+ wcd->rx_port_ch_reg_base, codec_port),
+ payload);
+
+ if (ret < 0) {
+ pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+ __func__,
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0(
+ wcd->rx_port_ch_reg_base, codec_port),
+ payload, ret);
+ return ret;
+ }
+ /* configure the slave port for water mark and enable*/
+ ret = regmap_write(wcd->if_regmap,
+ SB_PGD_PORT_CFG_BYTE_ADDR(
+ wcd->port_rx_cfg_reg_base, codec_port),
+ WATER_MARK_VAL);
+ if (ret < 0) {
+ pr_err("%s:watermark set failure for port[%d] ret[%d]",
+ __func__, codec_port, ret);
+ }
+ }
+#endif
+ if (!dai_data->sruntime)
+ pr_err("SLIM runtime is NULL...............................\n");
+
+ slim_stream_enable(dai_data->sruntime);
+
+ return 0;
+
+}
+
+static int wcd_slim_stream_prepare(struct wcd9335_priv *wcd,
+ struct wcd_slim_codec_dai_data *dai_data)
+
+{
+ struct slim_stream_config *cfg = &dai_data->sconfig;
+ struct list_head *wcd_slim_ch_list = &dai_data->wcd_slim_ch_list;
+ unsigned int rate = dai_data->rate;
+ unsigned int bit_width = dai_data->bit_width;
+ struct wcd_slim_data *wcd_sd = wcd->slim_data;
+ u8 ch_cnt = 0;
+ u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
+ u8 payload = 0;
+ u16 codec_port = 0;
+ int ret;
+ struct wcd_slim_ch *rx;
+ int size = ARRAY_SIZE(ch_h);
+ int count = 0;
+ int i =0;
+
+ cfg->ch_count = 0;
+ /* Configure slave interface device */
+ list_for_each_entry(rx, wcd_slim_ch_list, list) {
+ payload |= 1 << rx->shift;
+ cfg->port_mask |= 1 << (rx->shift + 0x10);
+ cfg->ch_count++;
+
+ }
+
+ cfg->chs = kcalloc(cfg->ch_count, sizeof(unsigned int), GFP_KERNEL);
+ if (!cfg->chs)
+ return -ENOMEM;
+
+ /* slim_define_ch api */
+ cfg->prot = SLIM_HARD_ISO;
+ cfg->rate = rate;
+ cfg->bps = bit_width;
+ i = 0;
+ list_for_each_entry(rx, wcd_slim_ch_list, list) {
+ codec_port = rx->port;
+ cfg->chs[i++] = rx->ch_num;
+
+ /* look for the valid port range and chose the
+ * payload accordingly
+ */
+ /* write to interface device */
+ ret = regmap_write(wcd_sd->if_regmap,
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0(
+ wcd_sd->rx_port_ch_reg_base, codec_port),
+ payload);
+
+ if (ret < 0) {
+ pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
+ __func__,
+ SB_PGD_RX_PORT_MULTI_CHANNEL_0(
+ wcd_sd->rx_port_ch_reg_base, codec_port),
+ payload, ret);
+ return ret;
+ }
+ /* configure the slave port for water mark and enable*/
+ ret = regmap_write(wcd_sd->if_regmap,
+ SB_PGD_PORT_CFG_BYTE_ADDR(
+ wcd_sd->port_rx_cfg_reg_base, codec_port),
+ WATER_MARK_VAL);
+ if (ret < 0) {
+ pr_err("%s:watermark set failure for port[%d] ret[%d]",
+ __func__, codec_port, ret);
+ }
+ }
+ dai_data->sruntime = slim_stream_allocate(wcd->slim, cfg);
+ slim_stream_prepare(dai_data->sruntime);
+
+ return 0;
+
+}
+
+static int wcd9335_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+
+ struct wcd9335_priv *wcd = snd_soc_component_get_drvdata(dai->component);
+ struct wcd_slim_codec_dai_data *dai_data = &wcd->dai[dai->id];
+
+ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
+ test_bit(SB_CLK_GEAR, &wcd->status_mask)) {
+ wcd9335_codec_vote_max_bw(dai->component, false);
+ clear_bit(SB_CLK_GEAR, &wcd->status_mask);
+ }
+ wcd_slim_stream_enable(wcd->slim_data, &wcd->dai[dai->id]);
+
+ return 0;
+}
+
+static int wcd9335_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct wcd9335_priv *wcd = snd_soc_component_get_drvdata(dai->component);
+ struct snd_soc_component *component = dai->component;
+ int rx_fs_rate = -EINVAL;
+ int i2s_bit_mode = 0;
+ int ret;
+
+ switch (substream->stream) {
+ case SNDRV_PCM_STREAM_PLAYBACK:
+ ret = wcd9335_set_interpolator_rate(dai, params_rate(params));
+ if (ret) {
+ dev_err(wcd->dev, "cannot set sample rate: %u\n",
+ params_rate(params));
+ return ret;
+ }
+ switch (params_width(params)) {
+ case 16:
+ wcd->dai[dai->id].bit_width = 16;
+ i2s_bit_mode = 0x01;
+ break;
+ case 24:
+ wcd->dai[dai->id].bit_width = 24;
+ i2s_bit_mode = 0x00;
+ break;
+ }
+ wcd->dai[dai->id].rate = params_rate(params);
+ if (wcd->intf_type == WCD_INTERFACE_TYPE_I2C) {
+ switch (params_rate(params)) {
+ case 8000:
+ rx_fs_rate = 0;
+ break;
+ case 16000:
+ rx_fs_rate = 1;
+ break;
+ case 32000:
+ rx_fs_rate = 2;
+ break;
+ case 48000:
+ rx_fs_rate = 3;
+ break;
+ case 96000:
+ rx_fs_rate = 4;
+ break;
+ case 192000:
+ rx_fs_rate = 5;
+ break;
+ default:
+ dev_err(wcd->dev,
+ "%s: Invalid RX sample rate: %d\n",
+ __func__, params_rate(params));
+ return -EINVAL;
+ };
+ snd_soc_component_update_bits(component,
+ WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+ 0x20, i2s_bit_mode << 5);
+ snd_soc_component_update_bits(component,
+ WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+ 0x1c, (rx_fs_rate << 2));
+ }
+ break;
+ default:
+ dev_err(wcd->dev, "Invalid stream type %d\n",
+ substream->stream);
+ return -EINVAL;
+ };
+ if (dai->id == AIF4_VIFEED)
+ wcd->dai[dai->id].bit_width = 32;
+
+ wcd_slim_stream_prepare(wcd, &wcd->dai[dai->id]);
+
+ return 0;
+}
+
+static int wcd9335_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct wcd9335_priv *wcd = snd_soc_component_get_drvdata(dai->component);
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* CPU is master */
+ if (wcd->intf_type == WCD_INTERFACE_TYPE_I2C) {
+ if (dai->id == AIF1_CAP)
+ snd_soc_component_update_bits(dai->component,
+ WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL,
+ 0x2, 0);
+ else if (dai->id == AIF1_PB)
+ snd_soc_component_update_bits(dai->component,
+ WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+ 0x2, 0);
+ }
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* CPU is slave */
+ if (wcd->intf_type == WCD_INTERFACE_TYPE_I2C) {
+ if (dai->id == AIF1_CAP)
+ snd_soc_component_update_bits(dai->component,
+ WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL,
+ 0x2, 0x2);
+ else if (dai->id == AIF1_PB)
+ snd_soc_component_update_bits(dai->component,
+ WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL,
+ 0x2, 0x2);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct snd_soc_dai_ops wcd9335_dai_ops = {
+ .hw_params = wcd9335_hw_params,
+ .prepare = wcd9335_prepare,
+ .set_fmt = wcd9335_set_dai_fmt,
+ .set_channel_map = wcd9335_set_channel_map,
+ .get_channel_map = wcd9335_get_channel_map,
+};
+
+static struct snd_soc_dai_driver wcd9335_slim_dai[] = {
+ [0] = {
+ .name = "wcd9335_rx1",
+ .id = AIF1_PB,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+ .formats = wcd9335_FORMATS_S16_S24_LE,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd9335_dai_ops,
+ },
+ [1] = {
+ .name = "wcd9335_rx2",
+ .id = AIF2_PB,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+ .formats = wcd9335_FORMATS_S16_S24_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd9335_dai_ops,
+ },
+ [2] = {
+ .name = "wcd9335_rx3",
+ .id = AIF3_PB,
+ .playback = {
+ .stream_name = "AIF3 Playback",
+ .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+ .formats = wcd9335_FORMATS_S16_S24_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd9335_dai_ops,
+ },
+ [3] = {
+ .name = "wcd9335_rx4",
+ .id = AIF4_PB,
+ .playback = {
+ .stream_name = "AIF4 Playback",
+ .rates = WCD9335_RATES_MASK | WCD9335_FRAC_RATES_MASK,
+ .formats = wcd9335_FORMATS_S16_S24_LE,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd9335_dai_ops,
+ },
+};
+
+static struct snd_soc_dai_driver wcd9335_i2s_dai[] = {
+ [AIF1_PB] = {
+ .name = "wcd9335_i2s_rx1",
+ .id = AIF1_PB,
+ .playback = {
+ .stream_name = "AIF1 Playback",
+ .rates = WCD9335_RATES_MASK,
+ .formats = wcd9335_FORMATS_S16_S24_LE,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd9335_dai_ops,
+ },
+ [AIF2_PB] = {
+ .name = "wcd9335_i2s_rx2",
+ .id = AIF2_PB,
+ .playback = {
+ .stream_name = "AIF2 Playback",
+ .rates = WCD9335_RATES_MASK,
+ .formats = wcd9335_FORMATS_S16_S24_LE,
+ .rate_max = 192000,
+ .rate_min = 8000,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &wcd9335_dai_ops,
+ },
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_reg_update_reset_val_1_1[] = {
+ {WCD9335_RCO_CTRL_2, 0xFF, 0x47},
+ {WCD9335_FLYBACK_VNEG_DAC_CTRL_4, 0xFF, 0x60},
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init_val_1_1[] = {
+ {WCD9335_FLYBACK_VNEG_DAC_CTRL_1, 0xFF, 0x65},
+ {WCD9335_FLYBACK_VNEG_DAC_CTRL_2, 0xFF, 0x52},
+ {WCD9335_FLYBACK_VNEG_DAC_CTRL_3, 0xFF, 0xAF},
+ {WCD9335_FLYBACK_VNEG_DAC_CTRL_4, 0xFF, 0x60},
+ {WCD9335_FLYBACK_VNEG_CTRL_3, 0xFF, 0xF4},
+ {WCD9335_FLYBACK_VNEG_CTRL_9, 0xFF, 0x40},
+ {WCD9335_FLYBACK_VNEG_CTRL_2, 0xFF, 0x4F},
+ {WCD9335_FLYBACK_EN, 0xFF, 0x6E},
+ {WCD9335_CDC_RX2_RX_PATH_SEC0, 0xF8, 0xF8},
+ {WCD9335_CDC_RX1_RX_PATH_SEC0, 0xF8, 0xF8},
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init_val_1_0[] = {
+ {WCD9335_FLYBACK_VNEG_CTRL_3, 0xFF, 0x54},
+ {WCD9335_CDC_RX2_RX_PATH_SEC0, 0xFC, 0xFC},
+ {WCD9335_CDC_RX1_RX_PATH_SEC0, 0xFC, 0xFC},
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init_val_2_0[] = {
+ {WCD9335_RCO_CTRL_2, 0x0F, 0x08},
+ {WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10},
+ {WCD9335_FLYBACK_CTRL_1, 0x20, 0x20},
+ {WCD9335_HPH_OCP_CTL, 0xFF, 0x5A},
+ {WCD9335_HPH_L_TEST, 0x01, 0x01},
+ {WCD9335_HPH_R_TEST, 0x01, 0x01},
+ {WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12},
+ {WCD9335_CDC_BOOST0_BOOST_CFG2, 0x1C, 0x08},
+ {WCD9335_CDC_COMPANDER7_CTL7, 0x1E, 0x18},
+ {WCD9335_CDC_BOOST1_BOOST_CFG1, 0x3F, 0x12},
+ {WCD9335_CDC_BOOST1_BOOST_CFG2, 0x1C, 0x08},
+ {WCD9335_CDC_COMPANDER8_CTL7, 0x1E, 0x18},
+ {WCD9335_CDC_TX0_TX_PATH_SEC7, 0xFF, 0x45},
+ {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xFC, 0xF4},
+ {WCD9335_HPH_REFBUFF_LP_CTL, 0x08, 0x08},
+ {WCD9335_HPH_REFBUFF_LP_CTL, 0x06, 0x02},
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_codec_reg_defaults[] = {
+ {WCD9335_CODEC_RPM_CLK_GATE, 0x03, 0x00},
+ {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x03, 0x01},
+ {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x04, 0x04},
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_codec_reg_i2c_defaults[] = {
+ {WCD9335_ANA_CLK_TOP, 0x20, 0x20},
+ {WCD9335_CODEC_RPM_CLK_GATE, 0x03, 0x01},
+ {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x03, 0x00},
+ {WCD9335_CODEC_RPM_CLK_MCLK_CFG, 0x05, 0x05},
+ {WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG, 0x01, 0x01},
+ {WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG, 0x01, 0x01},
+ {WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG, 0x01, 0x01},
+ {WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG, 0x01, 0x01},
+ {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG, 0x05, 0x05},
+ {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG, 0x05, 0x05},
+ {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG, 0x05, 0x05},
+ {WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG, 0x05, 0x05},
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init_common_val[] = {
+ /* Rbuckfly/R_EAR(32) */
+ {WCD9335_CDC_CLSH_K2_MSB, 0x0F, 0x00},
+ {WCD9335_CDC_CLSH_K2_LSB, 0xFF, 0x60},
+ {WCD9335_CPE_SS_DMIC_CFG, 0x80, 0x00},
+ {WCD9335_CDC_BOOST0_BOOST_CTL, 0x70, 0x50},
+ {WCD9335_CDC_BOOST1_BOOST_CTL, 0x70, 0x50},
+ {WCD9335_CDC_RX7_RX_PATH_CFG1, 0x08, 0x08},
+ {WCD9335_CDC_RX8_RX_PATH_CFG1, 0x08, 0x08},
+ {WCD9335_ANA_LO_1_2, 0x3C, 0X3C},
+ {WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ, 0x70, 0x00},
+ {WCD9335_DIFF_LO_COM_PA_FREQ, 0x70, 0x40},
+ {WCD9335_SOC_MAD_AUDIO_CTL_2, 0x03, 0x03},
+ {WCD9335_CDC_TOP_TOP_CFG1, 0x02, 0x02},
+ {WCD9335_CDC_TOP_TOP_CFG1, 0x01, 0x01},
+ {WCD9335_EAR_CMBUFF, 0x08, 0x00},
+ {WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80},
+ {WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80},
+ {WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01},
+ {WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01},
+ {WCD9335_CDC_RX0_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX1_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX2_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX3_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX4_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX5_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX6_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX7_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX8_RX_PATH_CFG0, 0x01, 0x01},
+ {WCD9335_CDC_RX0_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_CDC_RX1_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_CDC_RX2_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_CDC_RX3_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_CDC_RX4_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_CDC_RX5_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_CDC_RX6_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_CDC_RX7_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_CDC_RX8_RX_PATH_MIX_CFG, 0x01, 0x01},
+ {WCD9335_VBADC_IBIAS_FE, 0x0C, 0x08},
+};
+
+static const struct wcd9335_reg_mask_val wcd9335_codec_reg_init_1_x_val[] = {
+ /* Enable TX HPF Filter & Linear Phase */
+ {WCD9335_CDC_TX0_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_TX1_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_TX2_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_TX3_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_TX4_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_TX5_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_TX6_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_TX7_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_TX8_TX_PATH_CFG0, 0x11, 0x11},
+ {WCD9335_CDC_RX0_RX_PATH_SEC0, 0xF8, 0xF8},
+ {WCD9335_CDC_RX0_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX1_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX2_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX3_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX4_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX5_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX6_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX7_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX8_RX_PATH_SEC1, 0x08, 0x08},
+ {WCD9335_CDC_RX0_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_RX1_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_RX2_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_RX3_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_RX4_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_RX5_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_RX6_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_RX7_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_RX8_RX_PATH_MIX_SEC0, 0x08, 0x08},
+ {WCD9335_CDC_TX0_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_TX1_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_TX2_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_TX3_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_TX4_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_TX5_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_TX6_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_TX7_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_TX8_TX_PATH_SEC2, 0x01, 0x01},
+ {WCD9335_CDC_RX3_RX_PATH_SEC0, 0xF8, 0xF0},
+ {WCD9335_CDC_RX4_RX_PATH_SEC0, 0xF8, 0xF0},
+ {WCD9335_CDC_RX5_RX_PATH_SEC0, 0xF8, 0xF8},
+ {WCD9335_CDC_RX6_RX_PATH_SEC0, 0xF8, 0xF8},
+ {WCD9335_RX_OCP_COUNT, 0xFF, 0xFF},
+ {WCD9335_HPH_OCP_CTL, 0xF0, 0x70},
+ {WCD9335_CPE_SS_CPAR_CFG, 0xFF, 0x00},
+ {WCD9335_FLYBACK_VNEG_CTRL_1, 0xFF, 0x63},
+ {WCD9335_FLYBACK_VNEG_CTRL_4, 0xFF, 0x7F},
+ {WCD9335_CLASSH_CTRL_VCL_1, 0xFF, 0x60},
+ {WCD9335_CLASSH_CTRL_CCL_5, 0xFF, 0x40},
+ {WCD9335_RX_TIMER_DIV, 0xFF, 0x32},
+ {WCD9335_SE_LO_COM2, 0xFF, 0x01},
+ {WCD9335_MBHC_ZDET_ANA_CTL, 0x0F, 0x07},
+ {WCD9335_RX_BIAS_HPH_PA, 0xF0, 0x60},
+ {WCD9335_HPH_RDAC_LDO_CTL, 0x88, 0x88},
+ {WCD9335_HPH_L_EN, 0x20, 0x20},
+ {WCD9335_HPH_R_EN, 0x20, 0x20},
+ {WCD9335_DIFF_LO_CORE_OUT_PROG, 0xFC, 0xD8},
+ {WCD9335_CDC_RX5_RX_PATH_SEC3, 0xBD, 0xBD},
+ {WCD9335_CDC_RX6_RX_PATH_SEC3, 0xBD, 0xBD},
+};
+
+static int wcd9335_enable_efuse_sensing(struct snd_soc_component *component)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ _wcd9335_codec_enable_mclk(component, true);
+
+ if (!WCD9335_IS_2_0(wcd->version))
+ snd_soc_component_update_bits(component, WCD9335_CHIP_TIER_CTRL_EFUSE_CTL,
+ 0x1E, 0x02);
+ snd_soc_component_update_bits(component, WCD9335_CHIP_TIER_CTRL_EFUSE_CTL,
+ 0x01, 0x01);
+ /*
+ * 5ms sleep required after enabling efuse control
+ * before checking the status.
+ */
+ usleep_range(5000, 5500);
+ if (!(snd_soc_component_read32(component, WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) & 0x01))
+ WARN(1, "%s: Efuse sense is not complete\n", __func__);
+
+ if (WCD9335_IS_2_0(wcd->version)) {
+ if (!(snd_soc_component_read32(component, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0) & 0x40))
+ snd_soc_component_update_bits(component, WCD9335_HPH_R_ATEST, 0x04, 0x00);
+ wcd9335_enable_sido_buck(component);
+ }
+
+ _wcd9335_codec_enable_mclk(component, false);
+
+ return 0;
+}
+
+static void wcd9335_codec_init(struct snd_soc_component *component)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init_common_val); i++)
+ snd_soc_component_update_bits(component,
+ wcd9335_codec_reg_init_common_val[i].reg,
+ wcd9335_codec_reg_init_common_val[i].mask,
+ wcd9335_codec_reg_init_common_val[i].val);
+
+ if (WCD9335_IS_1_1(wcd->version) ||
+ WCD9335_IS_1_0(wcd->version))
+ for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init_1_x_val); i++)
+ snd_soc_component_update_bits(component,
+ wcd9335_codec_reg_init_1_x_val[i].reg,
+ wcd9335_codec_reg_init_1_x_val[i].mask,
+ wcd9335_codec_reg_init_1_x_val[i].val);
+
+ if (WCD9335_IS_1_1(wcd->version)) {
+ for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init_val_1_1); i++)
+ snd_soc_component_update_bits(component,
+ wcd9335_codec_reg_init_val_1_1[i].reg,
+ wcd9335_codec_reg_init_val_1_1[i].mask,
+ wcd9335_codec_reg_init_val_1_1[i].val);
+ } else if (WCD9335_IS_1_0(wcd->version)) {
+ for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init_val_1_0); i++)
+ snd_soc_component_update_bits(component,
+ wcd9335_codec_reg_init_val_1_0[i].reg,
+ wcd9335_codec_reg_init_val_1_0[i].mask,
+ wcd9335_codec_reg_init_val_1_0[i].val);
+ } else if (WCD9335_IS_2_0(wcd->version)) {
+ for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_init_val_2_0); i++)
+ snd_soc_component_update_bits(component,
+ wcd9335_codec_reg_init_val_2_0[i].reg,
+ wcd9335_codec_reg_init_val_2_0[i].mask,
+ wcd9335_codec_reg_init_val_2_0[i].val);
+ }
+
+ wcd9335_enable_efuse_sensing(component);
+}
+
+static void wcd9335_update_reg_defaults(struct wcd9335_priv *wcd)
+{
+ u32 i;
+ for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_defaults); i++)
+ regmap_update_bits(wcd->regmap,
+ wcd9335_codec_reg_defaults[i].reg,
+ wcd9335_codec_reg_defaults[i].mask,
+ wcd9335_codec_reg_defaults[i].val);
+
+ if (wcd->intf_type == WCD_INTERFACE_TYPE_I2C)
+ for (i = 0; i < ARRAY_SIZE(wcd9335_codec_reg_i2c_defaults); i++)
+ regmap_update_bits(wcd->regmap,
+ wcd9335_codec_reg_i2c_defaults[i].reg,
+ wcd9335_codec_reg_i2c_defaults[i].mask,
+ wcd9335_codec_reg_i2c_defaults[i].val);
+
+ return;
+}
+
+static irqreturn_t wcd9335_slimbus_irq(int irq, void *data)
+{
+ struct wcd9335_priv *wcd = data;
+ unsigned long status = 0;
+ int i, j, port_id, k;
+ u32 bit;
+ unsigned int val, int_val = 0;
+ bool tx, cleared;
+ unsigned short reg = 0;
+
+ for (i = WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
+ i <= WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
+ regmap_read(wcd->if_regmap, i, &val);
+ status |= ((u32)val << (8 * j));
+ }
+
+ for_each_set_bit(j, &status, 32) {
+ tx = (j >= 16 ? true : false);
+ port_id = (tx ? j - 16 : j);
+ regmap_read(wcd->if_regmap,
+ WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 + j, &val);
+ if (val) {
+ if (!tx)
+ reg = WCD9335_SLIM_PGD_PORT_INT_EN0 +
+ (port_id / 8);
+ else
+ reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 +
+ (port_id / 8);
+ regmap_read(
+ wcd->if_regmap, reg, &int_val);
+ /*
+ * Ignore interrupts for ports for which the
+ * interrupts are not specifically enabled.
+ */
+ if (!(int_val & (1 << (port_id % 8))))
+ continue;
+ }
+ if (val & WCD9335_SLIM_IRQ_OVERFLOW)
+ pr_err_ratelimited(
+ "%s: overflow error on %s port %d, value %x\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val);
+ if (val & WCD9335_SLIM_IRQ_UNDERFLOW)
+ pr_err_ratelimited(
+ "%s: underflow error on %s port %d, value %x\n",
+ __func__, (tx ? "TX" : "RX"), port_id, val);
+ if ((val & WCD9335_SLIM_IRQ_OVERFLOW) ||
+ (val & WCD9335_SLIM_IRQ_UNDERFLOW)) {
+ if (!tx)
+ reg = WCD9335_SLIM_PGD_PORT_INT_EN0 +
+ (port_id / 8);
+ else
+ reg = WCD9335_SLIM_PGD_PORT_INT_TX_EN0 +
+ (port_id / 8);
+ regmap_read(
+ wcd->if_regmap, reg, &int_val);
+ if (int_val & (1 << (port_id % 8))) {
+ int_val = int_val ^ (1 << (port_id % 8));
+ regmap_write(wcd->if_regmap,
+ reg, int_val);
+ }
+ }
+ if (val & WCD9335_SLIM_IRQ_PORT_CLOSED) {
+ /*
+ * INT SOURCE register starts from RX to TX
+ * but port number in the ch_mask is in opposite way
+ */
+ bit = (tx ? j - 16 : j + 16);
+ for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
+ if (test_and_clear_bit(bit,
+ &wcd->dai[k].ch_mask)) {
+ cleared = true;
+ if (!wcd->dai[k].ch_mask)
+ wake_up(&wcd->dai[k].dai_wait);
+ /*
+ * There are cases when multiple DAIs
+ * might be using the same slimbus
+ * channel. Hence don't break here.
+ */
+ }
+ }
+ WARN(!cleared,
+ "Couldn't find slimbus %s port %d for closing\n",
+ (tx ? "TX" : "RX"), port_id);
+ }
+ regmap_write(wcd->if_regmap,
+ WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 +
+ (j / 8),
+ 1 << (j % 8));
+ }
+
+ return IRQ_HANDLED;
+}
+
+static inline int wcd9335_request_irq(struct wcd9335_priv *w, int irq,
+ irq_handler_t handler, const char *name,
+ void *data)
+{
+ return request_threaded_irq(regmap_irq_get_virq(w->irq_data, irq),
+ NULL, handler, IRQF_TRIGGER_RISING, name,
+ data);
+}
+
+static int wcd9335_setup_irqs(struct wcd9335_priv *wcd)
+{
+ int i, ret = 0;
+
+ ret = wcd9335_request_irq(wcd, WCD9335_IRQ_SLIMBUS,
+ wcd9335_slimbus_irq, "SLIMBUS Slave", wcd);
+ if (ret) {
+ dev_err(wcd->dev, "Failed to request SLIMBUS irq \n");
+ return ret;
+ }
+
+ for (i = 0; i < WCD9335_SLIM_NUM_PORT_REG; i++)
+ regmap_write(wcd->if_regmap, WCD9335_SLIM_PGD_PORT_INT_EN0 + i,
+ 0xFF);
+
+ return ret;
+}
+
+static void wcd9335_cleanup_irqs(struct wcd9335_priv *w)
+{
+ free_irq(regmap_irq_get_virq(w->irq_data, WCD9335_IRQ_SLIMBUS), w);
+}
+
+static int wcd9335_codec_slim_reserve_bw(struct snd_soc_component *component,
+ u32 bw_ops, bool commit)
+{
+//truct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ return 0;
+//FIXME return slim_reservemsg_bw(wcd->slim, bw_ops, commit);
+}
+
+static int wcd9335_codec_vote_max_bw(struct snd_soc_component *component,
+ bool vote)
+{
+ return wcd9335_codec_slim_reserve_bw(component,
+ vote ? SLIM_BW_CLK_GEAR_9 : SLIM_BW_UNVOTE, true);
+}
+
+static int wcd9335_codec_set_sysclk(struct snd_soc_component *comp,
+ int clk_id, int source,
+ unsigned int freq, int dir)
+{
+// struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+
+ return 0;
+}
+
+static int wcd9335_codec_probe(struct snd_soc_component *component)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
+ struct wcd9335_priv *wcd = dev_get_drvdata(component->dev);
+ int i;
+
+ snd_soc_component_init_regmap(component, wcd->regmap);
+ wcd->clsh_d.codec_version = wcd->version;
+ /* Class-H Init*/
+ wcd_clsh_init(&wcd->clsh_d);
+ /* Default HPH Mode to Class-H HiFi */
+ wcd->hph_mode = CLS_H_HIFI;
+ wcd->component = component;
+
+ if (wcd->mclk_rate == wcd9335_MCLK_CLK_12P288MHZ)
+ snd_soc_component_update_bits(component, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+ 0x03, 0x00);
+ else if (wcd->mclk_rate == wcd9335_MCLK_CLK_9P6MHZ)
+ snd_soc_component_update_bits(component, WCD9335_CODEC_RPM_CLK_MCLK_CFG,
+ 0x03, 0x01);
+
+ wcd9335_codec_init(component);
+
+ if (wcd->intf_type == WCD_INTERFACE_TYPE_I2C) {
+ snd_soc_dapm_new_controls(dapm, wcd9335_dapm_i2s_widgets,
+ ARRAY_SIZE(wcd9335_dapm_i2s_widgets));
+ snd_soc_dapm_add_routes(dapm, audio_i2s_map,
+ ARRAY_SIZE(audio_i2s_map));
+ for (i = 0; i < ARRAY_SIZE(wcd9335_i2s_dai); i++) {
+ INIT_LIST_HEAD(&wcd->dai[i].wcd_slim_ch_list);
+ init_waitqueue_head(&wcd->dai[i].dai_wait);
+ }
+ } else if (wcd->intf_type == WCD_INTERFACE_TYPE_SLIMBUS) {
+ for (i = 0; i < NUM_CODEC_DAIS; i++) {
+ INIT_LIST_HEAD(&wcd->dai[i].wcd_slim_ch_list);
+ init_waitqueue_head(&wcd->dai[i].dai_wait);
+ }
+ }
+
+ return wcd9335_setup_irqs(wcd);
+}
+
+static void wcd9335_codec_remove(struct snd_soc_component *comp)
+{
+ struct wcd9335_priv *wcd = dev_get_drvdata(comp->dev);
+
+ wcd9335_cleanup_irqs(wcd);
+}
+
+static struct snd_soc_component_driver wcd9335_component_drv = {
+ .probe = wcd9335_codec_probe,
+ .remove = wcd9335_codec_remove,
+ .set_sysclk = wcd9335_codec_set_sysclk,
+ .controls = wcd9335_snd_controls,
+ .num_controls = ARRAY_SIZE(wcd9335_snd_controls),
+ .dapm_widgets = wcd9335_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wcd9335_dapm_widgets),
+ .dapm_routes = wcd9335_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(wcd9335_audio_map),
+};
+
+int wcd9335_probe(struct platform_device *pdev)
+{
+ struct wcd9335 *control = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ int ret = 0;
+ struct wcd9335_priv *wcd;
+ int clk1_gpio;
+
+ //FIXME
+// clk1_gpio = of_get_named_gpio(control->dev->of_node, "qcom,clk1-gpio", 0);
+// gpio_request(clk1_gpio, "CLK1");
+// gpio_direction_output(clk1_gpio, 0);
+
+ wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL);
+ if (!wcd)
+ return -ENOMEM;
+
+ wcd->slim_data = &control->slim_data;
+
+ wcd->slim_data->rx_chs = devm_kzalloc(dev, sizeof(wcd9335_rx_chs), GFP_KERNEL);
+ if (!wcd->slim_data->rx_chs)
+ return -ENOMEM;
+
+ memcpy(wcd->slim_data->rx_chs, wcd9335_rx_chs, sizeof(wcd9335_rx_chs));
+
+ dev_set_drvdata(dev, wcd);
+
+ wcd->mclk_rate = control->mclk_rate;
+ wcd->regmap = control->regmap;
+ wcd->if_regmap = control->ifd_regmap;
+ wcd->slim = control->slim;
+ wcd->slim_slave = control->slim_slave;
+ wcd->irq_data = control->irq_data;
+ wcd->version = control->version;
+ wcd->intf_type = control->intf_type;
+ wcd->dev = dev;
+ wcd->ext_clk = control->ext_clk;
+ wcd->native_clk = control->native_clk;
+
+ mutex_init(&wcd->sido_lock);
+
+ mutex_init(&wcd->codec_bg_clk_lock);
+ mutex_init(&wcd->master_bias_lock);
+ wcd->sido_input_src = SIDO_SOURCE_INTERNAL;
+
+ wcd->sido_voltage = SIDO_VOLTAGE_NOMINAL_MV;
+ set_bit(AUDIO_NOMINAL, &wcd->status_mask);
+
+ if (wcd->intf_type == WCD_INTERFACE_TYPE_SLIMBUS)
+ ret = snd_soc_register_component(dev, &wcd9335_component_drv,
+ wcd9335_slim_dai,
+ ARRAY_SIZE(wcd9335_slim_dai));
+ else if (wcd->intf_type == WCD_INTERFACE_TYPE_I2C)
+ ret = snd_soc_register_component(dev, &wcd9335_component_drv,
+ wcd9335_i2s_dai,
+ ARRAY_SIZE(wcd9335_i2s_dai));
+ else
+ ret = -EINVAL;
+
+ if (ret) {
+ dev_err(dev, "Codec registration failed\n");
+ return ret;
+ }
+
+ /* Update codec register default values */
+ //FIXME Need to go into the regmap defaults.
+ wcd9335_update_reg_defaults(wcd);
+
+ return ret;
+
+}
+
+static int wcd9335_remove(struct platform_device *pdev)
+{
+ struct wcd9335_priv *wcd;
+
+ wcd = platform_get_drvdata(pdev);
+
+ clk_put(wcd->ext_clk);
+ if (wcd->native_clk)
+ clk_put(wcd->native_clk);
+ devm_kfree(&pdev->dev, wcd);
+ snd_soc_unregister_component(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id wcd9335_of_match[] = {
+ { .compatible = "qcom,wcd9335", } ,
+ {}
+};
+static struct platform_driver wcd9335_codec_driver = {
+ .probe = wcd9335_probe,
+ .remove = wcd9335_remove,
+ .driver = {
+ .name = "wcd9335_codec",
+ .owner = THIS_MODULE,
+ .of_match_table = wcd9335_of_match,
+ },
+};
+
+module_platform_driver(wcd9335_codec_driver);
+MODULE_DESCRIPTION("WCD9335 Codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/wcd9335.h b/sound/soc/codecs/wcd9335.h
new file mode 100644
index 000000000000..5aaa56455c04
--- /dev/null
+++ b/sound/soc/codecs/wcd9335.h
@@ -0,0 +1,228 @@
+#ifndef __WCD9335_H__
+#define __WCD9335_H__
+
+#include <linux/slimbus.h>
+#include <linux/regulator/consumer.h>
+#include "wcd-slim.h"
+#include "wcd-clsh.h"
+
+#define WCD_INTERFACE_TYPE_SLIMBUS 1
+#define WCD_INTERFACE_TYPE_I2C 2
+
+#define WCD9XXX_MCLK_CLK_12P288MHZ 12288000
+#define WCD9XXX_MCLK_CLK_9P6HZ 9600000
+#define SLIMBUS_PRESENT_TIMEOUT 100
+#define WCD9335_MAX_SUPPLY 8
+
+#define WCD9335_VERSION_1_0 0
+#define WCD9335_VERSION_1_1 1
+#define WCD9335_VERSION_2_0 2
+#define WCD9335_IS_1_0(ver) \
+ ((ver == WCD9335_VERSION_1_0) ? 1 : 0)
+#define WCD9335_IS_1_1(ver) \
+ ((ver == WCD9335_VERSION_1_1) ? 1 : 0)
+#define WCD9335_IS_2_0(ver) \
+ ((ver == WCD9335_VERSION_2_0) ? 1 : 0)
+
+enum {
+ COMPANDER_1, /* HPH_L */
+ COMPANDER_2, /* HPH_R */
+ COMPANDER_3, /* LO1_DIFF */
+ COMPANDER_4, /* LO2_DIFF */
+ COMPANDER_5, /* LO3_SE */
+ COMPANDER_6, /* LO4_SE */
+ COMPANDER_7, /* SWR SPK CH1 */
+ COMPANDER_8, /* SWR SPK CH2 */
+ COMPANDER_MAX,
+};
+
+enum {
+ /* INTR_REG 0 */
+ WCD9335_IRQ_SLIMBUS = 0,
+ WCD9335_IRQ_FLL_LOCK_LOSS = 1,
+ WCD9335_IRQ_HPH_PA_OCPL_FAULT,
+ WCD9335_IRQ_HPH_PA_OCPR_FAULT,
+ WCD9335_IRQ_EAR_PA_OCP_FAULT,
+ WCD9335_IRQ_HPH_PA_CNPL_COMPLETE,
+ WCD9335_IRQ_HPH_PA_CNPR_COMPLETE,
+ WCD9335_IRQ_EAR_PA_CNP_COMPLETE,
+ /* INTR_REG 1 */
+ WCD9335_IRQ_MBHC_SW_DET,
+ WCD9335_IRQ_MBHC_ELECT_INS_REM_DET,
+ WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
+ WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
+ WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
+ WCD9335_IRQ_RESERVED_0,
+ WCD9335_IRQ_RESERVED_1,
+ WCD9335_IRQ_RESERVED_2,
+ /* INTR_REG 2 */
+ WCD9335_IRQ_LINE_PA1_CNP_COMPLETE,
+ WCD9335_IRQ_LINE_PA2_CNP_COMPLETE,
+ WCD9335_IRQ_LINE_PA3_CNP_COMPLETE,
+ WCD9335_IRQ_LINE_PA4_CNP_COMPLETE,
+ WCD9335_IRQ_SOUNDWIRE,
+ WCD9335_IRQ_VDD_DIG_RAMP_COMPLETE,
+ WCD9335_IRQ_RCO_ERROR,
+ WCD9335_IRQ_SVA_ERROR,
+ /* INTR_REG 3 */
+ WCD9335_IRQ_MAD_AUDIO,
+ WCD9335_IRQ_MAD_BEACON,
+ WCD9335_IRQ_MAD_ULTRASOUND,
+ WCD9335_IRQ_VBAT_ATTACK,
+ WCD9335_IRQ_VBAT_RESTORE,
+ WCD9335_IRQ_SVA_OUTBOX1,
+ WCD9335_IRQ_SVA_OUTBOX2,
+ WCD9335_NUM_IRQS,
+};
+
+enum {
+ AIF1_PB = 0,
+ AIF1_CAP,
+ AIF2_PB,
+ AIF2_CAP,
+ AIF3_PB,
+ AIF3_CAP,
+ AIF4_PB,
+ AIF_MIX1_PB,
+ AIF4_MAD_TX,
+ AIF4_VIFEED,
+ NUM_CODEC_DAIS,
+};
+
+#define WCD9335_NUM_INTERPOLATORS 9
+enum wcd9335_sido_voltage {
+ SIDO_VOLTAGE_SVS_MV = 950,
+ SIDO_VOLTAGE_NOMINAL_MV = 1100,
+};
+
+enum {
+ SPLINE_SRC0,
+ SPLINE_SRC1,
+ SPLINE_SRC2,
+ SPLINE_SRC3,
+ SPLINE_SRC_MAX,
+};
+
+enum wcd_clock_type {
+ WCD_CLK_OFF,
+ WCD_CLK_RCO,
+ WCD_CLK_MCLK,
+};
+
+enum {
+ SIDO_SOURCE_INTERNAL,
+ SIDO_SOURCE_RCO_BG,
+};
+
+struct wcd9335_slim_ch {
+ int id;
+};
+
+struct wcd_slim_codec_dai_data {
+ u32 rate; /* sample rate */
+ u32 bit_width; /* sit width 16,24,32 */
+ struct list_head wcd_slim_ch_list; /* channel list */
+ u16 grph; /* slimbus group handle */
+ unsigned long ch_mask;
+ unsigned long port_mask;
+ wait_queue_head_t dai_wait; //FIXME
+ struct slim_stream_config sconfig;
+ struct slim_stream_runtime *sruntime;
+};
+
+struct wcd9335 {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *irq_data;
+
+ /* data */
+ int irq;
+ struct clk *ext_clk;
+ struct clk *native_clk;
+ int clk1_gpio;
+ int reset_gpio;
+ int irq_gpio;
+ int mclk_rate;
+ int num_of_supplies;
+ struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
+
+ u8 version;
+ u8 intf_type;
+ /* slimbus specific*/
+ struct wcd_slim_data slim_data;
+
+ struct slim_device *slim;
+ struct slim_device *slim_ifd;
+ struct regmap *ifd_regmap;
+ struct slim_device *slim_slave;
+};
+
+#define WCD9XXX_RCO_CALIBRATION_DELAY_INC_US 5000
+
+struct wcd9335_priv {
+ struct device *dev;
+ struct regmap *regmap;
+ struct regmap_irq_chip_data *irq_data;
+
+ /* data */
+ struct clk *ext_clk;
+ struct clk *native_clk;
+ u32 mclk_rate;
+ u8 version;
+
+
+ /* slimbus specific */
+
+ struct slim_device *slim;
+ struct slim_device *slim_slave;
+ struct regmap *if_regmap;
+ struct wcd_slim_data *slim_data;
+
+ u32 num_rx_port;
+ u32 num_tx_port;
+ struct wcd_slim_codec_dai_data dai[NUM_CODEC_DAIS];
+
+ /* Codec specifics */
+ const struct wcd_slim_codec_type *codec_type;
+ struct snd_soc_component *component;
+ u32 rx_bias_count;
+ /*track tasha interface type*/
+ u8 intf_type;
+ /*compander*/
+ int comp_enabled[COMPANDER_MAX];
+ /* class h specific data */
+ struct wcd_clsh_cdc_data clsh_d;
+ enum wcd9335_sido_voltage sido_voltage;
+ int sido_ccl_cnt;
+ /* to track the status */
+ unsigned long status_mask;
+ /* Port values for Rx and Tx codec_dai */
+ unsigned int rx_port_value;
+ unsigned int tx_port_value;
+ /* Tasha Interpolator Mode Select for EAR, HPH_L and HPH_R */
+ u32 hph_mode;
+ u16 prim_int_users[WCD9335_NUM_INTERPOLATORS];
+ int spl_src_users[SPLINE_SRC_MAX];
+// struct wcd_slim_resmgr_v2 *resmgr;
+///
+ int master_bias_users;
+ int clk_mclk_users;
+ int clk_rco_users;
+
+ struct mutex codec_bg_clk_lock;
+ struct mutex master_bias_lock;
+ enum wcd_clock_type clk_type;
+
+ int sido_input_src;
+///
+ struct mutex sido_lock;
+ struct mutex micb_lock;
+ int native_clk_users;
+ int power_active_ref;
+ int hph_l_gain;
+ int hph_r_gain;
+};
+
+int wcd9335_regmap_register_patch(struct regmap *regmap, int version);
+
+#endif /* __WCD9335_H__ */
diff --git a/sound/soc/codecs/wcd9335_registers.h b/sound/soc/codecs/wcd9335_registers.h
new file mode 100644
index 000000000000..9fa1d1502a5c
--- /dev/null
+++ b/sound/soc/codecs/wcd9335_registers.h
@@ -0,0 +1,1350 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _WCD9335_REGISTERS_H
+#define _WCD9335_REGISTERS_H
+#include "wcd9335.h"
+
+#define WCD9335_PAGE_SIZE 256
+#define WCD9335_NUM_PAGES 256
+
+
+extern const u8 *wcd9335_reg[WCD9335_NUM_PAGES];
+
+enum {
+ PAGE_0 = 0,
+ PAGE_1,
+ PAGE_2,
+ PAGE_6 = 6,
+ PAGE_10 = 0xA,
+ PAGE_11,
+ PAGE_12,
+ PAGE_13,
+ PAGE_0X80,
+};
+
+/* Page-0 Registers */
+#define WCD9335_PAGE0_PAGE_REGISTER 0x0000
+#define WCD9335_CODEC_RPM_CLK_BYPASS 0x0001
+#define WCD9335_CODEC_RPM_CLK_GATE 0x0002
+#define WCD9335_CODEC_RPM_CLK_MCLK_CFG 0x0003
+#define WCD9335_CODEC_RPM_RST_CTL 0x0009
+#define WCD9335_CODEC_RPM_PWR_CDC_DIG_HM_CTL 0x0011
+#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_1 0x0012
+#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_2 0x0013
+#define WCD9335_CODEC_RPM_PWR_CPE_DEEPSLP_3 0x0014
+#define WCD9335_CODEC_RPM_PWR_CPE_IRAM_SHUTDOWN 0x0015
+#define WCD9335_CODEC_RPM_PWR_CPE_DRAM1_SHUTDOWN 0x0016
+#define WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_1 0x0017
+#define WCD9335_CODEC_RPM_PWR_CPE_DRAM0_SHUTDOWN_2 0x0018
+#define WCD9335_CODEC_RPM_INT_MASK 0x001d
+#define WCD9335_CODEC_RPM_INT_STATUS 0x001e
+#define WCD9335_CODEC_RPM_INT_CLEAR 0x001f
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE0 0x0021
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE1 0x0022
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE2 0x0023
+#define WCD9335_CHIP_TIER_CTRL_CHIP_ID_BYTE3 0x0024
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_CTL 0x0025
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_TEST0 0x0026
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_TEST1 0x0027
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0 0x0029
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 0x002a
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 0x002b
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT3 0x002c
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT4 0x002d
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT5 0x002e
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT6 0x002f
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT7 0x0030
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT8 0x0031
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT9 0x0032
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT10 0x0033
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT11 0x0034
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT12 0x0035
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT13 0x0036
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT14 0x0037
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT15 0x0038
+#define WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS 0x0039
+#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_NONNEGO 0x003a
+#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_1 0x003b
+#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_2 0x003c
+#define WCD9335_CHIP_TIER_CTRL_I2C_SLAVE_ID_3 0x003d
+#define WCD9335_CHIP_TIER_CTRL_ANA_WAIT_STATE_CTL 0x003e
+#define WCD9335_CHIP_TIER_CTRL_I2C_ACTIVE 0x003f
+#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CTL 0x0041
+#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_STATUS 0x0042
+#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_MSB 0x0043
+#define WCD9335_CHIP_TIER_CTRL_PROC1_MON_CNT_LSB 0x0044
+#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CTL 0x0045
+#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_STATUS 0x0046
+#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_MSB 0x0047
+#define WCD9335_CHIP_TIER_CTRL_PROC2_MON_CNT_LSB 0x0048
+#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CTL 0x0049
+#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_STATUS 0x004a
+#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_MSB 0x004b
+#define WCD9335_CHIP_TIER_CTRL_PROC3_MON_CNT_LSB 0x004c
+#define WCD9335_DATA_HUB_DATA_HUB_RX_I2S_CTL 0x0051
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_CTL 0x0052
+#define WCD9335_DATA_HUB_DATA_HUB_I2S_CLK 0x0053
+#define WCD9335_DATA_HUB_DATA_HUB_RX0_INP_CFG 0x0054
+#define WCD9335_DATA_HUB_DATA_HUB_RX1_INP_CFG 0x0055
+#define WCD9335_DATA_HUB_DATA_HUB_RX2_INP_CFG 0x0056
+#define WCD9335_DATA_HUB_DATA_HUB_RX3_INP_CFG 0x0057
+#define WCD9335_DATA_HUB_DATA_HUB_RX4_INP_CFG 0x0058
+#define WCD9335_DATA_HUB_DATA_HUB_RX5_INP_CFG 0x0059
+#define WCD9335_DATA_HUB_DATA_HUB_RX6_INP_CFG 0x005a
+#define WCD9335_DATA_HUB_DATA_HUB_RX7_INP_CFG 0x005b
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX0_INP_CFG 0x0061
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX1_INP_CFG 0x0062
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX2_INP_CFG 0x0063
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX3_INP_CFG 0x0064
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX4_INP_CFG 0x0065
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX5_INP_CFG 0x0066
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX6_INP_CFG 0x0067
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX7_INP_CFG 0x0068
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX8_INP_CFG 0x0069
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX9_INP_CFG 0x006a
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX10_INP_CFG 0x006b
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX11_INP_CFG 0x006c
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX13_INP_CFG 0x006e
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX14_INP_CFG 0x006f
+#define WCD9335_DATA_HUB_DATA_HUB_SB_TX15_INP_CFG 0x0070
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_L_CFG 0x0071
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD0_R_CFG 0x0072
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_L_CFG 0x0073
+#define WCD9335_DATA_HUB_DATA_HUB_TX_I2S_SD1_R_CFG 0x0074
+#define WCD9335_DATA_HUB_NATIVE_FIFO_SYNC 0x0075
+#define WCD9335_DATA_HUB_NATIVE_FIFO_STATUS 0x007D
+#define WCD9335_INTR_CFG 0x0081
+#define WCD9335_INTR_CLR_COMMIT 0x0082
+#define WCD9335_INTR_PIN1_MASK0 0x0089
+#define WCD9335_INTR_PIN1_MASK1 0x008a
+#define WCD9335_INTR_PIN1_MASK2 0x008b
+#define WCD9335_INTR_PIN1_MASK3 0x008c
+#define WCD9335_INTR_PIN1_STATUS0 0x0091
+#define WCD9335_INTR_PIN1_STATUS1 0x0092
+#define WCD9335_INTR_PIN1_STATUS2 0x0093
+#define WCD9335_INTR_PIN1_STATUS3 0x0094
+#define WCD9335_INTR_PIN1_CLEAR0 0x0099
+#define WCD9335_INTR_PIN1_CLEAR1 0x009a
+#define WCD9335_INTR_PIN1_CLEAR2 0x009b
+#define WCD9335_INTR_PIN1_CLEAR3 0x009c
+#define WCD9335_INTR_PIN2_MASK0 0x00a1
+#define WCD9335_INTR_PIN2_MASK1 0x00a2
+#define WCD9335_INTR_PIN2_MASK2 0x00a3
+#define WCD9335_INTR_PIN2_MASK3 0x00a4
+#define WCD9335_INTR_PIN2_STATUS0 0x00a9
+#define WCD9335_INTR_PIN2_STATUS1 0x00aa
+#define WCD9335_INTR_PIN2_STATUS2 0x00ab
+#define WCD9335_INTR_PIN2_STATUS3 0x00ac
+#define WCD9335_INTR_PIN2_CLEAR0 0x00b1
+#define WCD9335_INTR_PIN2_CLEAR1 0x00b2
+#define WCD9335_INTR_PIN2_CLEAR2 0x00b3
+#define WCD9335_INTR_PIN2_CLEAR3 0x00b4
+#define WCD9335_INTR_LEVEL0 0x00e1
+#define WCD9335_INTR_LEVEL1 0x00e2
+#define WCD9335_INTR_LEVEL2 0x00e3
+#define WCD9335_INTR_LEVEL3 0x00e4
+#define WCD9335_INTR_BYPASS0 0x00e9
+#define WCD9335_INTR_BYPASS1 0x00ea
+#define WCD9335_INTR_BYPASS2 0x00eb
+#define WCD9335_INTR_BYPASS3 0x00ec
+#define WCD9335_INTR_SET0 0x00f1
+#define WCD9335_INTR_SET1 0x00f2
+#define WCD9335_INTR_SET2 0x00f3
+#define WCD9335_INTR_SET3 0x00f4
+
+/* Page-1 Registers */
+#define WCD9335_PAGE1_PAGE_REGISTER 0x0100
+#define WCD9335_CPE_FLL_USER_CTL_0 0x0101
+#define WCD9335_CPE_FLL_USER_CTL_1 0x0102
+#define WCD9335_CPE_FLL_USER_CTL_2 0x0103
+#define WCD9335_CPE_FLL_USER_CTL_3 0x0104
+#define WCD9335_CPE_FLL_USER_CTL_4 0x0105
+#define WCD9335_CPE_FLL_USER_CTL_5 0x0106
+#define WCD9335_CPE_FLL_USER_CTL_6 0x0107
+#define WCD9335_CPE_FLL_USER_CTL_7 0x0108
+#define WCD9335_CPE_FLL_USER_CTL_8 0x0109
+#define WCD9335_CPE_FLL_USER_CTL_9 0x010a
+#define WCD9335_CPE_FLL_L_VAL_CTL_0 0x010b
+#define WCD9335_CPE_FLL_L_VAL_CTL_1 0x010c
+#define WCD9335_CPE_FLL_DSM_FRAC_CTL_0 0x010d
+#define WCD9335_CPE_FLL_DSM_FRAC_CTL_1 0x010e
+#define WCD9335_CPE_FLL_CONFIG_CTL_0 0x010f
+#define WCD9335_CPE_FLL_CONFIG_CTL_1 0x0110
+#define WCD9335_CPE_FLL_CONFIG_CTL_2 0x0111
+#define WCD9335_CPE_FLL_CONFIG_CTL_3 0x0112
+#define WCD9335_CPE_FLL_CONFIG_CTL_4 0x0113
+#define WCD9335_CPE_FLL_TEST_CTL_0 0x0114
+#define WCD9335_CPE_FLL_TEST_CTL_1 0x0115
+#define WCD9335_CPE_FLL_TEST_CTL_2 0x0116
+#define WCD9335_CPE_FLL_TEST_CTL_3 0x0117
+#define WCD9335_CPE_FLL_TEST_CTL_4 0x0118
+#define WCD9335_CPE_FLL_TEST_CTL_5 0x0119
+#define WCD9335_CPE_FLL_TEST_CTL_6 0x011a
+#define WCD9335_CPE_FLL_TEST_CTL_7 0x011b
+#define WCD9335_CPE_FLL_FREQ_CTL_0 0x011c
+#define WCD9335_CPE_FLL_FREQ_CTL_1 0x011d
+#define WCD9335_CPE_FLL_FREQ_CTL_2 0x011e
+#define WCD9335_CPE_FLL_FREQ_CTL_3 0x011f
+#define WCD9335_CPE_FLL_SSC_CTL_0 0x0120
+#define WCD9335_CPE_FLL_SSC_CTL_1 0x0121
+#define WCD9335_CPE_FLL_SSC_CTL_2 0x0122
+#define WCD9335_CPE_FLL_SSC_CTL_3 0x0123
+#define WCD9335_CPE_FLL_FLL_MODE 0x0124
+#define WCD9335_CPE_FLL_STATUS_0 0x0125
+#define WCD9335_CPE_FLL_STATUS_1 0x0126
+#define WCD9335_CPE_FLL_STATUS_2 0x0127
+#define WCD9335_CPE_FLL_STATUS_3 0x0128
+#define WCD9335_I2S_FLL_USER_CTL_0 0x0141
+#define WCD9335_I2S_FLL_USER_CTL_1 0x0142
+#define WCD9335_I2S_FLL_USER_CTL_2 0x0143
+#define WCD9335_I2S_FLL_USER_CTL_3 0x0144
+#define WCD9335_I2S_FLL_USER_CTL_4 0x0145
+#define WCD9335_I2S_FLL_USER_CTL_5 0x0146
+#define WCD9335_I2S_FLL_USER_CTL_6 0x0147
+#define WCD9335_I2S_FLL_USER_CTL_7 0x0148
+#define WCD9335_I2S_FLL_USER_CTL_8 0x0149
+#define WCD9335_I2S_FLL_USER_CTL_9 0x014a
+#define WCD9335_I2S_FLL_L_VAL_CTL_0 0x014b
+#define WCD9335_I2S_FLL_L_VAL_CTL_1 0x014c
+#define WCD9335_I2S_FLL_DSM_FRAC_CTL_0 0x014d
+#define WCD9335_I2S_FLL_DSM_FRAC_CTL_1 0x014e
+#define WCD9335_I2S_FLL_CONFIG_CTL_0 0x014f
+#define WCD9335_I2S_FLL_CONFIG_CTL_1 0x0150
+#define WCD9335_I2S_FLL_CONFIG_CTL_2 0x0151
+#define WCD9335_I2S_FLL_CONFIG_CTL_3 0x0152
+#define WCD9335_I2S_FLL_CONFIG_CTL_4 0x0153
+#define WCD9335_I2S_FLL_TEST_CTL_0 0x0154
+#define WCD9335_I2S_FLL_TEST_CTL_1 0x0155
+#define WCD9335_I2S_FLL_TEST_CTL_2 0x0156
+#define WCD9335_I2S_FLL_TEST_CTL_3 0x0157
+#define WCD9335_I2S_FLL_TEST_CTL_4 0x0158
+#define WCD9335_I2S_FLL_TEST_CTL_5 0x0159
+#define WCD9335_I2S_FLL_TEST_CTL_6 0x015a
+#define WCD9335_I2S_FLL_TEST_CTL_7 0x015b
+#define WCD9335_I2S_FLL_FREQ_CTL_0 0x015c
+#define WCD9335_I2S_FLL_FREQ_CTL_1 0x015d
+#define WCD9335_I2S_FLL_FREQ_CTL_2 0x015e
+#define WCD9335_I2S_FLL_FREQ_CTL_3 0x015f
+#define WCD9335_I2S_FLL_SSC_CTL_0 0x0160
+#define WCD9335_I2S_FLL_SSC_CTL_1 0x0161
+#define WCD9335_I2S_FLL_SSC_CTL_2 0x0162
+#define WCD9335_I2S_FLL_SSC_CTL_3 0x0163
+#define WCD9335_I2S_FLL_FLL_MODE 0x0164
+#define WCD9335_I2S_FLL_STATUS_0 0x0165
+#define WCD9335_I2S_FLL_STATUS_1 0x0166
+#define WCD9335_I2S_FLL_STATUS_2 0x0167
+#define WCD9335_I2S_FLL_STATUS_3 0x0168
+#define WCD9335_SB_FLL_USER_CTL_0 0x0181
+#define WCD9335_SB_FLL_USER_CTL_1 0x0182
+#define WCD9335_SB_FLL_USER_CTL_2 0x0183
+#define WCD9335_SB_FLL_USER_CTL_3 0x0184
+#define WCD9335_SB_FLL_USER_CTL_4 0x0185
+#define WCD9335_SB_FLL_USER_CTL_5 0x0186
+#define WCD9335_SB_FLL_USER_CTL_6 0x0187
+#define WCD9335_SB_FLL_USER_CTL_7 0x0188
+#define WCD9335_SB_FLL_USER_CTL_8 0x0189
+#define WCD9335_SB_FLL_USER_CTL_9 0x018a
+#define WCD9335_SB_FLL_L_VAL_CTL_0 0x018b
+#define WCD9335_SB_FLL_L_VAL_CTL_1 0x018c
+#define WCD9335_SB_FLL_DSM_FRAC_CTL_0 0x018d
+#define WCD9335_SB_FLL_DSM_FRAC_CTL_1 0x018e
+#define WCD9335_SB_FLL_CONFIG_CTL_0 0x018f
+#define WCD9335_SB_FLL_CONFIG_CTL_1 0x0190
+#define WCD9335_SB_FLL_CONFIG_CTL_2 0x0191
+#define WCD9335_SB_FLL_CONFIG_CTL_3 0x0192
+#define WCD9335_SB_FLL_CONFIG_CTL_4 0x0193
+#define WCD9335_SB_FLL_TEST_CTL_0 0x0194
+#define WCD9335_SB_FLL_TEST_CTL_1 0x0195
+#define WCD9335_SB_FLL_TEST_CTL_2 0x0196
+#define WCD9335_SB_FLL_TEST_CTL_3 0x0197
+#define WCD9335_SB_FLL_TEST_CTL_4 0x0198
+#define WCD9335_SB_FLL_TEST_CTL_5 0x0199
+#define WCD9335_SB_FLL_TEST_CTL_6 0x019a
+#define WCD9335_SB_FLL_TEST_CTL_7 0x019b
+#define WCD9335_SB_FLL_FREQ_CTL_0 0x019c
+#define WCD9335_SB_FLL_FREQ_CTL_1 0x019d
+#define WCD9335_SB_FLL_FREQ_CTL_2 0x019e
+#define WCD9335_SB_FLL_FREQ_CTL_3 0x019f
+#define WCD9335_SB_FLL_SSC_CTL_0 0x01a0
+#define WCD9335_SB_FLL_SSC_CTL_1 0x01a1
+#define WCD9335_SB_FLL_SSC_CTL_2 0x01a2
+#define WCD9335_SB_FLL_SSC_CTL_3 0x01a3
+#define WCD9335_SB_FLL_FLL_MODE 0x01a4
+#define WCD9335_SB_FLL_STATUS_0 0x01a5
+#define WCD9335_SB_FLL_STATUS_1 0x01a6
+#define WCD9335_SB_FLL_STATUS_2 0x01a7
+#define WCD9335_SB_FLL_STATUS_3 0x01a8
+
+/* Page-2 Registers */
+#define WCD9335_PAGE2_PAGE_REGISTER 0x0200
+#define WCD9335_CPE_SS_MEM_PTR_0 0x0201
+#define WCD9335_CPE_SS_MEM_PTR_1 0x0202
+#define WCD9335_CPE_SS_MEM_PTR_2 0x0203
+#define WCD9335_CPE_SS_MEM_CTRL 0x0205
+#define WCD9335_CPE_SS_MEM_BANK_0 0x0206
+#define WCD9335_CPE_SS_MEM_BANK_1 0x0207
+#define WCD9335_CPE_SS_MEM_BANK_2 0x0208
+#define WCD9335_CPE_SS_MEM_BANK_3 0x0209
+#define WCD9335_CPE_SS_MEM_BANK_4 0x020a
+#define WCD9335_CPE_SS_MEM_BANK_5 0x020b
+#define WCD9335_CPE_SS_MEM_BANK_6 0x020c
+#define WCD9335_CPE_SS_MEM_BANK_7 0x020d
+#define WCD9335_CPE_SS_MEM_BANK_8 0x020e
+#define WCD9335_CPE_SS_MEM_BANK_9 0x020f
+#define WCD9335_CPE_SS_MEM_BANK_10 0x0210
+#define WCD9335_CPE_SS_MEM_BANK_11 0x0211
+#define WCD9335_CPE_SS_MEM_BANK_12 0x0212
+#define WCD9335_CPE_SS_MEM_BANK_13 0x0213
+#define WCD9335_CPE_SS_MEM_BANK_14 0x0214
+#define WCD9335_CPE_SS_MEM_BANK_15 0x0215
+#define WCD9335_CPE_SS_INBOX1_TRG 0x0216
+#define WCD9335_CPE_SS_INBOX2_TRG 0x0217
+#define WCD9335_CPE_SS_INBOX1_0 0x0218
+#define WCD9335_CPE_SS_INBOX1_1 0x0219
+#define WCD9335_CPE_SS_INBOX1_2 0x021a
+#define WCD9335_CPE_SS_INBOX1_3 0x021b
+#define WCD9335_CPE_SS_INBOX1_4 0x021c
+#define WCD9335_CPE_SS_INBOX1_5 0x021d
+#define WCD9335_CPE_SS_INBOX1_6 0x021e
+#define WCD9335_CPE_SS_INBOX1_7 0x021f
+#define WCD9335_CPE_SS_INBOX1_8 0x0220
+#define WCD9335_CPE_SS_INBOX1_9 0x0221
+#define WCD9335_CPE_SS_INBOX1_10 0x0222
+#define WCD9335_CPE_SS_INBOX1_11 0x0223
+#define WCD9335_CPE_SS_INBOX1_12 0x0224
+#define WCD9335_CPE_SS_INBOX1_13 0x0225
+#define WCD9335_CPE_SS_INBOX1_14 0x0226
+#define WCD9335_CPE_SS_INBOX1_15 0x0227
+#define WCD9335_CPE_SS_OUTBOX1_0 0x0228
+#define WCD9335_CPE_SS_OUTBOX1_1 0x0229
+#define WCD9335_CPE_SS_OUTBOX1_2 0x022a
+#define WCD9335_CPE_SS_OUTBOX1_3 0x022b
+#define WCD9335_CPE_SS_OUTBOX1_4 0x022c
+#define WCD9335_CPE_SS_OUTBOX1_5 0x022d
+#define WCD9335_CPE_SS_OUTBOX1_6 0x022e
+#define WCD9335_CPE_SS_OUTBOX1_7 0x022f
+#define WCD9335_CPE_SS_OUTBOX1_8 0x0230
+#define WCD9335_CPE_SS_OUTBOX1_9 0x0231
+#define WCD9335_CPE_SS_OUTBOX1_10 0x0232
+#define WCD9335_CPE_SS_OUTBOX1_11 0x0233
+#define WCD9335_CPE_SS_OUTBOX1_12 0x0234
+#define WCD9335_CPE_SS_OUTBOX1_13 0x0235
+#define WCD9335_CPE_SS_OUTBOX1_14 0x0236
+#define WCD9335_CPE_SS_OUTBOX1_15 0x0237
+#define WCD9335_CPE_SS_INBOX2_0 0x0238
+#define WCD9335_CPE_SS_INBOX2_1 0x0239
+#define WCD9335_CPE_SS_INBOX2_2 0x023a
+#define WCD9335_CPE_SS_INBOX2_3 0x023b
+#define WCD9335_CPE_SS_INBOX2_4 0x023c
+#define WCD9335_CPE_SS_INBOX2_5 0x023d
+#define WCD9335_CPE_SS_INBOX2_6 0x023e
+#define WCD9335_CPE_SS_INBOX2_7 0x023f
+#define WCD9335_CPE_SS_INBOX2_8 0x0240
+#define WCD9335_CPE_SS_INBOX2_9 0x0241
+#define WCD9335_CPE_SS_INBOX2_10 0x0242
+#define WCD9335_CPE_SS_INBOX2_11 0x0243
+#define WCD9335_CPE_SS_INBOX2_12 0x0244
+#define WCD9335_CPE_SS_INBOX2_13 0x0245
+#define WCD9335_CPE_SS_INBOX2_14 0x0246
+#define WCD9335_CPE_SS_INBOX2_15 0x0247
+#define WCD9335_CPE_SS_OUTBOX2_0 0x0248
+#define WCD9335_CPE_SS_OUTBOX2_1 0x0249
+#define WCD9335_CPE_SS_OUTBOX2_2 0x024a
+#define WCD9335_CPE_SS_OUTBOX2_3 0x024b
+#define WCD9335_CPE_SS_OUTBOX2_4 0x024c
+#define WCD9335_CPE_SS_OUTBOX2_5 0x024d
+#define WCD9335_CPE_SS_OUTBOX2_6 0x024e
+#define WCD9335_CPE_SS_OUTBOX2_7 0x024f
+#define WCD9335_CPE_SS_OUTBOX2_8 0x0250
+#define WCD9335_CPE_SS_OUTBOX2_9 0x0251
+#define WCD9335_CPE_SS_OUTBOX2_10 0x0252
+#define WCD9335_CPE_SS_OUTBOX2_11 0x0253
+#define WCD9335_CPE_SS_OUTBOX2_12 0x0254
+#define WCD9335_CPE_SS_OUTBOX2_13 0x0255
+#define WCD9335_CPE_SS_OUTBOX2_14 0x0256
+#define WCD9335_CPE_SS_OUTBOX2_15 0x0257
+#define WCD9335_CPE_SS_OUTBOX1_ACK 0x0258
+#define WCD9335_CPE_SS_OUTBOX2_ACK 0x0259
+#define WCD9335_CPE_SS_EC_BUF_INT_PERIOD 0x025a
+#define WCD9335_CPE_SS_US_BUF_INT_PERIOD 0x025b
+#define WCD9335_CPE_SS_CPARMAD_BUFRDY_INT_PERIOD 0x025c
+#define WCD9335_CPE_SS_CFG 0x025d
+#define WCD9335_CPE_SS_US_EC_MUX_CFG 0x025e
+#define WCD9335_CPE_SS_MAD_CTL 0x025f
+#define WCD9335_CPE_SS_CPAR_CTL 0x0260
+#define WCD9335_CPE_SS_TX_PP_BUF_INT_PERIOD 0x0261
+#define WCD9335_CPE_SS_TX_PP_CFG 0x0262
+#define WCD9335_CPE_SS_DMIC0_CTL 0x0263
+#define WCD9335_CPE_SS_DMIC1_CTL 0x0264
+#define WCD9335_CPE_SS_DMIC2_CTL 0x0265
+#define WCD9335_CPE_SS_DMIC_CFG 0x0266
+#define WCD9335_CPE_SS_SVA_CFG 0x0267
+#define WCD9335_CPE_SS_CPAR_CFG 0x0271
+#define WCD9335_CPE_SS_WDOG_CFG 0x0272
+#define WCD9335_CPE_SS_BACKUP_INT 0x0273
+#define WCD9335_CPE_SS_STATUS 0x0274
+#define WCD9335_CPE_SS_CPE_OCD_CFG 0x0275
+#define WCD9335_CPE_SS_SS_ERROR_INT_MASK 0x0276
+#define WCD9335_CPE_SS_SS_ERROR_INT_STATUS 0x0277
+#define WCD9335_CPE_SS_SS_ERROR_INT_CLEAR 0x0278
+#define WCD9335_SOC_MAD_MAIN_CTL_1 0x0281
+#define WCD9335_SOC_MAD_MAIN_CTL_2 0x0282
+#define WCD9335_SOC_MAD_AUDIO_CTL_1 0x0283
+#define WCD9335_SOC_MAD_AUDIO_CTL_2 0x0284
+#define WCD9335_SOC_MAD_AUDIO_CTL_3 0x0285
+#define WCD9335_SOC_MAD_AUDIO_CTL_4 0x0286
+#define WCD9335_SOC_MAD_AUDIO_CTL_5 0x0287
+#define WCD9335_SOC_MAD_AUDIO_CTL_6 0x0288
+#define WCD9335_SOC_MAD_AUDIO_CTL_7 0x0289
+#define WCD9335_SOC_MAD_AUDIO_CTL_8 0x028a
+#define WCD9335_SOC_MAD_AUDIO_IIR_CTL_PTR 0x028b
+#define WCD9335_SOC_MAD_AUDIO_IIR_CTL_VAL 0x028c
+#define WCD9335_SOC_MAD_ULTR_CTL_1 0x028d
+#define WCD9335_SOC_MAD_ULTR_CTL_2 0x028e
+#define WCD9335_SOC_MAD_ULTR_CTL_3 0x028f
+#define WCD9335_SOC_MAD_ULTR_CTL_4 0x0290
+#define WCD9335_SOC_MAD_ULTR_CTL_5 0x0291
+#define WCD9335_SOC_MAD_ULTR_CTL_6 0x0292
+#define WCD9335_SOC_MAD_ULTR_CTL_7 0x0293
+#define WCD9335_SOC_MAD_BEACON_CTL_1 0x0294
+#define WCD9335_SOC_MAD_BEACON_CTL_2 0x0295
+#define WCD9335_SOC_MAD_BEACON_CTL_3 0x0296
+#define WCD9335_SOC_MAD_BEACON_CTL_4 0x0297
+#define WCD9335_SOC_MAD_BEACON_CTL_5 0x0298
+#define WCD9335_SOC_MAD_BEACON_CTL_6 0x0299
+#define WCD9335_SOC_MAD_BEACON_CTL_7 0x029a
+#define WCD9335_SOC_MAD_BEACON_CTL_8 0x029b
+#define WCD9335_SOC_MAD_BEACON_IIR_CTL_PTR 0x029c
+#define WCD9335_SOC_MAD_BEACON_IIR_CTL_VAL 0x029d
+#define WCD9335_SOC_MAD_INP_SEL 0x029e
+
+/* Page-6 Registers */
+#define WCD9335_PAGE6_PAGE_REGISTER 0x0600
+#define WCD9335_ANA_BIAS 0x0601
+#define WCD9335_ANA_CLK_TOP 0x0602
+#define WCD9335_ANA_RCO 0x0603
+#define WCD9335_ANA_BUCK_VOUT_A 0x0604
+#define WCD9335_ANA_BUCK_VOUT_D 0x0605
+#define WCD9335_ANA_BUCK_CTL 0x0606
+#define WCD9335_ANA_BUCK_STATUS 0x0607
+#define WCD9335_ANA_RX_SUPPLIES 0x0608
+#define WCD9335_ANA_HPH 0x0609
+#define WCD9335_ANA_EAR 0x060a
+#define WCD9335_ANA_LO_1_2 0x060b
+#define WCD9335_ANA_LO_3_4 0x060c
+#define WCD9335_ANA_MAD_SETUP 0x060d
+#define WCD9335_ANA_AMIC1 0x060e
+#define WCD9335_ANA_AMIC2 0x060f
+#define WCD9335_ANA_AMIC3 0x0610
+#define WCD9335_ANA_AMIC4 0x0611
+#define WCD9335_ANA_AMIC5 0x0612
+#define WCD9335_ANA_AMIC6 0x0613
+#define WCD9335_ANA_MBHC_MECH 0x0614
+#define WCD9335_ANA_MBHC_ELECT 0x0615
+#define WCD9335_ANA_MBHC_ZDET 0x0616
+#define WCD9335_ANA_MBHC_RESULT_1 0x0617
+#define WCD9335_ANA_MBHC_RESULT_2 0x0618
+#define WCD9335_ANA_MBHC_RESULT_3 0x0619
+#define WCD9335_ANA_MBHC_BTN0 0x061a
+#define WCD9335_ANA_MBHC_BTN1 0x061b
+#define WCD9335_ANA_MBHC_BTN2 0x061c
+#define WCD9335_ANA_MBHC_BTN3 0x061d
+#define WCD9335_ANA_MBHC_BTN4 0x061e
+#define WCD9335_ANA_MBHC_BTN5 0x061f
+#define WCD9335_ANA_MBHC_BTN6 0x0620
+#define WCD9335_ANA_MBHC_BTN7 0x0621
+#define WCD9335_ANA_MICB1 0x0622
+#define WCD9335_ANA_MICB2 0x0623
+#define WCD9335_ANA_MICB2_RAMP 0x0624
+#define WCD9335_ANA_MICB3 0x0625
+#define WCD9335_ANA_MICB4 0x0626
+#define WCD9335_ANA_VBADC 0x0627
+#define WCD9335_BIAS_CTL 0x0628
+#define WCD9335_BIAS_VBG_FINE_ADJ 0x0629
+#define WCD9335_CLOCK_TEST_CTL 0x062d
+#define WCD9335_RCO_CTRL_1 0x062e
+#define WCD9335_RCO_CTRL_2 0x062f
+#define WCD9335_RCO_CAL 0x0630
+#define WCD9335_RCO_CAL_1 0x0631
+#define WCD9335_RCO_CAL_2 0x0632
+#define WCD9335_RCO_TEST_CTRL 0x0633
+#define WCD9335_RCO_CAL_OUT_1 0x0634
+#define WCD9335_RCO_CAL_OUT_2 0x0635
+#define WCD9335_RCO_CAL_OUT_3 0x0636
+#define WCD9335_RCO_CAL_OUT_4 0x0637
+#define WCD9335_RCO_CAL_OUT_5 0x0638
+#define WCD9335_SIDO_SIDO_MODE_1 0x063a
+#define WCD9335_SIDO_SIDO_MODE_2 0x063b
+#define WCD9335_SIDO_SIDO_MODE_3 0x063c
+#define WCD9335_SIDO_SIDO_MODE_4 0x063d
+#define WCD9335_SIDO_SIDO_VCL_1 0x063e
+#define WCD9335_SIDO_SIDO_VCL_2 0x063f
+#define WCD9335_SIDO_SIDO_VCL_3 0x0640
+#define WCD9335_SIDO_SIDO_CCL_1 0x0641
+#define WCD9335_SIDO_SIDO_CCL_2 0x0642
+#define WCD9335_SIDO_SIDO_CCL_3 0x0643
+#define WCD9335_SIDO_SIDO_CCL_4 0x0644
+#define WCD9335_SIDO_SIDO_CCL_5 0x0645
+#define WCD9335_SIDO_SIDO_CCL_6 0x0646
+#define WCD9335_SIDO_SIDO_CCL_7 0x0647
+#define WCD9335_SIDO_SIDO_CCL_8 0x0648
+#define WCD9335_SIDO_SIDO_CCL_9 0x0649
+#define WCD9335_SIDO_SIDO_CCL_10 0x064a
+#define WCD9335_SIDO_SIDO_FILTER_1 0x064b
+#define WCD9335_SIDO_SIDO_FILTER_2 0x064c
+#define WCD9335_SIDO_SIDO_DRIVER_1 0x064d
+#define WCD9335_SIDO_SIDO_DRIVER_2 0x064e
+#define WCD9335_SIDO_SIDO_DRIVER_3 0x064f
+#define WCD9335_SIDO_SIDO_CAL_CODE_EXT_1 0x0650
+#define WCD9335_SIDO_SIDO_CAL_CODE_EXT_2 0x0651
+#define WCD9335_SIDO_SIDO_CAL_CODE_OUT_1 0x0652
+#define WCD9335_SIDO_SIDO_CAL_CODE_OUT_2 0x0653
+#define WCD9335_SIDO_SIDO_TEST_1 0x0654
+#define WCD9335_SIDO_SIDO_TEST_2 0x0655
+#define WCD9335_MBHC_CTL_1 0x0656
+#define WCD9335_MBHC_CTL_2 0x0657
+#define WCD9335_MBHC_PLUG_DETECT_CTL 0x0658
+#define WCD9335_MBHC_ZDET_ANA_CTL 0x0659
+#define WCD9335_MBHC_ZDET_RAMP_CTL 0x065a
+#define WCD9335_MBHC_FSM_DEBUG 0x065b /* v1.x */
+#define WCD9335_MBHC_FSM_STATUS 0x065b /* v2.0 */
+#define WCD9335_MBHC_TEST_CTL 0x065c
+#define WCD9335_VBADC_SUBBLOCK_EN 0x065d
+#define WCD9335_VBADC_IBIAS_FE 0x065e
+#define WCD9335_VBADC_BIAS_ADC 0x065f
+#define WCD9335_VBADC_FE_CTRL 0x0660
+#define WCD9335_VBADC_ADC_REF 0x0661
+#define WCD9335_VBADC_ADC_IO 0x0662
+#define WCD9335_VBADC_ADC_SAR 0x0663
+#define WCD9335_VBADC_DEBUG 0x0664
+#define WCD9335_VBADC_ADC_DOUTMSB 0x0665
+#define WCD9335_VBADC_ADC_DOUTLSB 0x0666
+#define WCD9335_LDOH_MODE 0x0667
+#define WCD9335_LDOH_BIAS 0x0668
+#define WCD9335_LDOH_STB_LOADS 0x0669
+#define WCD9335_LDOH_SLOWRAMP 0x066a
+#define WCD9335_MICB1_TEST_CTL_1 0x066b
+#define WCD9335_MICB1_TEST_CTL_2 0x066c
+#define WCD9335_MICB1_TEST_CTL_3 0x066d
+#define WCD9335_MICB2_TEST_CTL_1 0x066e
+#define WCD9335_MICB2_TEST_CTL_2 0x066f
+#define WCD9335_MICB2_TEST_CTL_3 0x0670
+#define WCD9335_MICB3_TEST_CTL_1 0x0671
+#define WCD9335_MICB3_TEST_CTL_2 0x0672
+#define WCD9335_MICB3_TEST_CTL_3 0x0673
+#define WCD9335_MICB4_TEST_CTL_1 0x0674
+#define WCD9335_MICB4_TEST_CTL_2 0x0675
+#define WCD9335_MICB4_TEST_CTL_3 0x0676
+#define WCD9335_TX_COM_ADC_VCM 0x0677
+#define WCD9335_TX_COM_BIAS_ATEST 0x0678
+#define WCD9335_TX_COM_ADC_INT1_IB 0x0679
+#define WCD9335_TX_COM_ADC_INT2_IB 0x067a
+#define WCD9335_TX_COM_TXFE_DIV_CTL 0x067b
+#define WCD9335_TX_COM_TXFE_DIV_START 0x067c
+#define WCD9335_TX_COM_TXFE_DIV_STOP_9P6M 0x067d
+#define WCD9335_TX_COM_TXFE_DIV_STOP_12P288M 0x067e
+#define WCD9335_TX_1_2_TEST_EN 0x067f
+#define WCD9335_TX_1_2_ADC_IB 0x0680
+#define WCD9335_TX_1_2_ATEST_REFCTL 0x0681
+#define WCD9335_TX_1_2_TEST_CTL 0x0682
+#define WCD9335_TX_1_2_TEST_BLK_EN 0x0683
+#define WCD9335_TX_1_2_TXFE_CLKDIV 0x0684
+#define WCD9335_TX_1_2_SAR1_ERR 0x0685
+#define WCD9335_TX_1_2_SAR2_ERR 0x0686
+#define WCD9335_TX_3_4_TEST_EN 0x0687
+#define WCD9335_TX_3_4_ADC_IB 0x0688
+#define WCD9335_TX_3_4_ATEST_REFCTL 0x0689
+#define WCD9335_TX_3_4_TEST_CTL 0x068a
+#define WCD9335_TX_3_4_TEST_BLK_EN 0x068b
+#define WCD9335_TX_3_4_TXFE_CLKDIV 0x068c
+#define WCD9335_TX_3_4_SAR1_ERR 0x068d
+#define WCD9335_TX_3_4_SAR2_ERR 0x068e
+#define WCD9335_TX_5_6_TEST_EN 0x068f
+#define WCD9335_TX_5_6_ADC_IB 0x0690
+#define WCD9335_TX_5_6_ATEST_REFCTL 0x0691
+#define WCD9335_TX_5_6_TEST_CTL 0x0692
+#define WCD9335_TX_5_6_TEST_BLK_EN 0x0693
+#define WCD9335_TX_5_6_TXFE_CLKDIV 0x0694
+#define WCD9335_TX_5_6_SAR1_ERR 0x0695
+#define WCD9335_TX_5_6_SAR2_ERR 0x0696
+#define WCD9335_CLASSH_MODE_1 0x0697
+#define WCD9335_CLASSH_MODE_2 0x0698
+#define WCD9335_CLASSH_MODE_3 0x0699
+#define WCD9335_CLASSH_CTRL_VCL_1 0x069a
+#define WCD9335_CLASSH_CTRL_VCL_2 0x069b
+#define WCD9335_CLASSH_CTRL_CCL_1 0x069c
+#define WCD9335_CLASSH_CTRL_CCL_2 0x069d
+#define WCD9335_CLASSH_CTRL_CCL_3 0x069e
+#define WCD9335_CLASSH_CTRL_CCL_4 0x069f
+#define WCD9335_CLASSH_CTRL_CCL_5 0x06a0
+#define WCD9335_CLASSH_BUCK_TMUX_A_D 0x06a1
+#define WCD9335_CLASSH_BUCK_SW_DRV_CNTL 0x06a2
+#define WCD9335_CLASSH_SPARE 0x06a3
+#define WCD9335_FLYBACK_EN 0x06a4
+#define WCD9335_FLYBACK_VNEG_CTRL_1 0x06a5
+#define WCD9335_FLYBACK_VNEG_CTRL_2 0x06a6
+#define WCD9335_FLYBACK_VNEG_CTRL_3 0x06a7
+#define WCD9335_FLYBACK_VNEG_CTRL_4 0x06a8
+#define WCD9335_FLYBACK_VNEG_CTRL_5 0x06a9
+#define WCD9335_FLYBACK_VNEG_CTRL_6 0x06aa
+#define WCD9335_FLYBACK_VNEG_CTRL_7 0x06ab
+#define WCD9335_FLYBACK_VNEG_CTRL_8 0x06ac
+#define WCD9335_FLYBACK_VNEG_CTRL_9 0x06ad
+#define WCD9335_FLYBACK_VNEG_DAC_CTRL_1 0x06ae
+#define WCD9335_FLYBACK_VNEG_DAC_CTRL_2 0x06af
+#define WCD9335_FLYBACK_VNEG_DAC_CTRL_3 0x06b0
+#define WCD9335_FLYBACK_VNEG_DAC_CTRL_4 0x06b1 /* v1.x */
+#define WCD9335_FLYBACK_CTRL_1 0x06b1 /* v2.0 */
+#define WCD9335_FLYBACK_TEST_CTL 0x06b2
+#define WCD9335_RX_AUX_SW_CTL 0x06b3
+#define WCD9335_RX_PA_AUX_IN_CONN 0x06b4
+#define WCD9335_RX_TIMER_DIV 0x06b5
+#define WCD9335_RX_OCP_CTL 0x06b6
+#define WCD9335_RX_OCP_COUNT 0x06b7
+#define WCD9335_RX_BIAS_EAR_DAC 0x06b8
+#define WCD9335_RX_BIAS_EAR_AMP 0x06b9
+#define WCD9335_RX_BIAS_HPH_LDO 0x06ba
+#define WCD9335_RX_BIAS_HPH_PA 0x06bb
+#define WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2 0x06bc
+#define WCD9335_RX_BIAS_HPH_RDAC_LDO 0x06bd
+#define WCD9335_RX_BIAS_HPH_CNP1 0x06be
+#define WCD9335_RX_BIAS_HPH_LOWPOWER 0x06bf
+#define WCD9335_RX_BIAS_DIFFLO_PA 0x06c0
+#define WCD9335_RX_BIAS_DIFFLO_REF 0x06c1
+#define WCD9335_RX_BIAS_DIFFLO_LDO 0x06c2
+#define WCD9335_RX_BIAS_SELO_DAC_PA 0x06c3
+#define WCD9335_RX_BIAS_BUCK_RST 0x06c4
+#define WCD9335_RX_BIAS_BUCK_VREF_ERRAMP 0x06c5
+#define WCD9335_RX_BIAS_FLYB_ERRAMP 0x06c6
+#define WCD9335_RX_BIAS_FLYB_BUFF 0x06c7
+#define WCD9335_RX_BIAS_FLYB_MID_RST 0x06c8
+#define WCD9335_HPH_L_STATUS 0x06c9
+#define WCD9335_HPH_R_STATUS 0x06ca
+#define WCD9335_HPH_CNP_EN 0x06cb
+#define WCD9335_HPH_CNP_WG_CTL 0x06cc
+#define WCD9335_HPH_CNP_WG_TIME 0x06cd
+#define WCD9335_HPH_OCP_CTL 0x06ce
+#define WCD9335_HPH_AUTO_CHOP 0x06cf
+#define WCD9335_HPH_CHOP_CTL 0x06d0
+#define WCD9335_HPH_PA_CTL1 0x06d1
+#define WCD9335_HPH_PA_CTL2 0x06d2
+#define WCD9335_HPH_L_EN 0x06d3
+#define WCD9335_HPH_L_TEST 0x06d4
+#define WCD9335_HPH_L_ATEST 0x06d5
+#define WCD9335_HPH_R_EN 0x06d6
+#define WCD9335_HPH_R_TEST 0x06d7
+#define WCD9335_HPH_R_ATEST 0x06d8
+#define WCD9335_HPH_RDAC_CLK_CTL1 0x06d9
+#define WCD9335_HPH_RDAC_CLK_CTL2 0x06da
+#define WCD9335_HPH_RDAC_LDO_CTL 0x06db
+#define WCD9335_HPH_RDAC_CHOP_CLK_LP_CTL 0x06dc
+#define WCD9335_HPH_REFBUFF_UHQA_CTL 0x06dd
+#define WCD9335_HPH_REFBUFF_LP_CTL 0x06de
+#define WCD9335_HPH_L_DAC_CTL 0x06df
+#define WCD9335_HPH_R_DAC_CTL 0x06e0
+#define WCD9335_EAR_EN_REG 0x06e1
+#define WCD9335_EAR_CMBUFF 0x06e2
+#define WCD9335_EAR_ICTL 0x06e3
+#define WCD9335_EAR_EN_DBG_CTL 0x06e4
+#define WCD9335_EAR_CNP 0x06e5
+#define WCD9335_EAR_DAC_CTL_ATEST 0x06e6
+#define WCD9335_EAR_STATUS_REG 0x06e7
+#define WCD9335_EAR_OUT_SHORT 0x06e8
+#define WCD9335_DIFF_LO_MISC 0x06e9
+#define WCD9335_DIFF_LO_LO2_COMPANDER 0x06ea
+#define WCD9335_DIFF_LO_LO1_COMPANDER 0x06eb
+#define WCD9335_DIFF_LO_COMMON 0x06ec
+#define WCD9335_DIFF_LO_BYPASS_EN 0x06ed
+#define WCD9335_DIFF_LO_CNP 0x06ee
+#define WCD9335_DIFF_LO_CORE_OUT_PROG 0x06ef
+#define WCD9335_DIFF_LO_LDO_OUT_PROG 0x06f0
+#define WCD9335_DIFF_LO_COM_SWCAP_REFBUF_FREQ 0x06f1
+#define WCD9335_DIFF_LO_COM_PA_FREQ 0x06f2
+#define WCD9335_DIFF_LO_RESERVED_REG 0x06f3
+#define WCD9335_DIFF_LO_LO1_STATUS_1 0x06f4
+#define WCD9335_DIFF_LO_LO1_STATUS_2 0x06f5
+#define WCD9335_SE_LO_COM1 0x06f6
+#define WCD9335_SE_LO_COM2 0x06f7
+#define WCD9335_SE_LO_LO3_GAIN 0x06f8
+#define WCD9335_SE_LO_LO3_CTRL 0x06f9
+#define WCD9335_SE_LO_LO4_GAIN 0x06fa
+#define WCD9335_SE_LO_LO4_CTRL 0x06fb
+#define WCD9335_SE_LO_LO3_STATUS 0x06fe
+#define WCD9335_SE_LO_LO4_STATUS 0x06ff
+
+/* Page-10 Registers */
+#define WCD9335_PAGE10_PAGE_REGISTER 0x0a00
+#define WCD9335_CDC_ANC0_CLK_RESET_CTL 0x0a01
+#define WCD9335_CDC_ANC0_MODE_1_CTL 0x0a02
+#define WCD9335_CDC_ANC0_MODE_2_CTL 0x0a03
+#define WCD9335_CDC_ANC0_FF_SHIFT 0x0a04
+#define WCD9335_CDC_ANC0_FB_SHIFT 0x0a05
+#define WCD9335_CDC_ANC0_LPF_FF_A_CTL 0x0a06
+#define WCD9335_CDC_ANC0_LPF_FF_B_CTL 0x0a07
+#define WCD9335_CDC_ANC0_LPF_FB_CTL 0x0a08
+#define WCD9335_CDC_ANC0_SMLPF_CTL 0x0a09
+#define WCD9335_CDC_ANC0_DCFLT_SHIFT_CTL 0x0a0a
+#define WCD9335_CDC_ANC0_IIR_ADAPT_CTL 0x0a0b
+#define WCD9335_CDC_ANC0_IIR_COEFF_1_CTL 0x0a0c
+#define WCD9335_CDC_ANC0_IIR_COEFF_2_CTL 0x0a0d
+#define WCD9335_CDC_ANC0_FF_A_GAIN_CTL 0x0a0e
+#define WCD9335_CDC_ANC0_FF_B_GAIN_CTL 0x0a0f
+#define WCD9335_CDC_ANC0_FB_GAIN_CTL 0x0a10
+#define WCD9335_CDC_ANC1_CLK_RESET_CTL 0x0a19
+#define WCD9335_CDC_ANC1_MODE_1_CTL 0x0a1a
+#define WCD9335_CDC_ANC1_MODE_2_CTL 0x0a1b
+#define WCD9335_CDC_ANC1_FF_SHIFT 0x0a1c
+#define WCD9335_CDC_ANC1_FB_SHIFT 0x0a1d
+#define WCD9335_CDC_ANC1_LPF_FF_A_CTL 0x0a1e
+#define WCD9335_CDC_ANC1_LPF_FF_B_CTL 0x0a1f
+#define WCD9335_CDC_ANC1_LPF_FB_CTL 0x0a20
+#define WCD9335_CDC_ANC1_SMLPF_CTL 0x0a21
+#define WCD9335_CDC_ANC1_DCFLT_SHIFT_CTL 0x0a22
+#define WCD9335_CDC_ANC1_IIR_ADAPT_CTL 0x0a23
+#define WCD9335_CDC_ANC1_IIR_COEFF_1_CTL 0x0a24
+#define WCD9335_CDC_ANC1_IIR_COEFF_2_CTL 0x0a25
+#define WCD9335_CDC_ANC1_FF_A_GAIN_CTL 0x0a26
+#define WCD9335_CDC_ANC1_FF_B_GAIN_CTL 0x0a27
+#define WCD9335_CDC_ANC1_FB_GAIN_CTL 0x0a28
+#define WCD9335_CDC_TX0_TX_PATH_CTL 0x0a31
+#define WCD9335_CDC_TX0_TX_PATH_CFG0 0x0a32
+#define WCD9335_CDC_TX0_TX_PATH_CFG1 0x0a33
+#define WCD9335_CDC_TX0_TX_VOL_CTL 0x0a34
+#define WCD9335_CDC_TX0_TX_PATH_192_CTL 0x0a35
+#define WCD9335_CDC_TX0_TX_PATH_192_CFG 0x0a36
+#define WCD9335_CDC_TX0_TX_PATH_SEC0 0x0a37
+#define WCD9335_CDC_TX0_TX_PATH_SEC1 0x0a38
+#define WCD9335_CDC_TX0_TX_PATH_SEC2 0x0a39
+#define WCD9335_CDC_TX0_TX_PATH_SEC3 0x0a3a
+#define WCD9335_CDC_TX0_TX_PATH_SEC4 0x0a3b
+#define WCD9335_CDC_TX0_TX_PATH_SEC5 0x0a3c
+#define WCD9335_CDC_TX0_TX_PATH_SEC6 0x0a3d
+#define WCD9335_CDC_TX0_TX_PATH_SEC7 0x0a3e
+#define WCD9335_CDC_TX1_TX_PATH_CTL 0x0a41
+#define WCD9335_CDC_TX1_TX_PATH_CFG0 0x0a42
+#define WCD9335_CDC_TX1_TX_PATH_CFG1 0x0a43
+#define WCD9335_CDC_TX1_TX_VOL_CTL 0x0a44
+#define WCD9335_CDC_TX1_TX_PATH_192_CTL 0x0a45
+#define WCD9335_CDC_TX1_TX_PATH_192_CFG 0x0a46
+#define WCD9335_CDC_TX1_TX_PATH_SEC0 0x0a47
+#define WCD9335_CDC_TX1_TX_PATH_SEC1 0x0a48
+#define WCD9335_CDC_TX1_TX_PATH_SEC2 0x0a49
+#define WCD9335_CDC_TX1_TX_PATH_SEC3 0x0a4a
+#define WCD9335_CDC_TX1_TX_PATH_SEC4 0x0a4b
+#define WCD9335_CDC_TX1_TX_PATH_SEC5 0x0a4c
+#define WCD9335_CDC_TX1_TX_PATH_SEC6 0x0a4d
+#define WCD9335_CDC_TX2_TX_PATH_CTL 0x0a51
+#define WCD9335_CDC_TX2_TX_PATH_CFG0 0x0a52
+#define WCD9335_CDC_TX2_TX_PATH_CFG1 0x0a53
+#define WCD9335_CDC_TX2_TX_VOL_CTL 0x0a54
+#define WCD9335_CDC_TX2_TX_PATH_192_CTL 0x0a55
+#define WCD9335_CDC_TX2_TX_PATH_192_CFG 0x0a56
+#define WCD9335_CDC_TX2_TX_PATH_SEC0 0x0a57
+#define WCD9335_CDC_TX2_TX_PATH_SEC1 0x0a58
+#define WCD9335_CDC_TX2_TX_PATH_SEC2 0x0a59
+#define WCD9335_CDC_TX2_TX_PATH_SEC3 0x0a5a
+#define WCD9335_CDC_TX2_TX_PATH_SEC4 0x0a5b
+#define WCD9335_CDC_TX2_TX_PATH_SEC5 0x0a5c
+#define WCD9335_CDC_TX2_TX_PATH_SEC6 0x0a5d
+#define WCD9335_CDC_TX3_TX_PATH_CTL 0x0a61
+#define WCD9335_CDC_TX3_TX_PATH_CFG0 0x0a62
+#define WCD9335_CDC_TX3_TX_PATH_CFG1 0x0a63
+#define WCD9335_CDC_TX3_TX_VOL_CTL 0x0a64
+#define WCD9335_CDC_TX3_TX_PATH_192_CTL 0x0a65
+#define WCD9335_CDC_TX3_TX_PATH_192_CFG 0x0a66
+#define WCD9335_CDC_TX3_TX_PATH_SEC0 0x0a67
+#define WCD9335_CDC_TX3_TX_PATH_SEC1 0x0a68
+#define WCD9335_CDC_TX3_TX_PATH_SEC2 0x0a69
+#define WCD9335_CDC_TX3_TX_PATH_SEC3 0x0a6a
+#define WCD9335_CDC_TX3_TX_PATH_SEC4 0x0a6b
+#define WCD9335_CDC_TX3_TX_PATH_SEC5 0x0a6c
+#define WCD9335_CDC_TX3_TX_PATH_SEC6 0x0a6d
+#define WCD9335_CDC_TX4_TX_PATH_CTL 0x0a71
+#define WCD9335_CDC_TX4_TX_PATH_CFG0 0x0a72
+#define WCD9335_CDC_TX4_TX_PATH_CFG1 0x0a73
+#define WCD9335_CDC_TX4_TX_VOL_CTL 0x0a74
+#define WCD9335_CDC_TX4_TX_PATH_192_CTL 0x0a75
+#define WCD9335_CDC_TX4_TX_PATH_192_CFG 0x0a76
+#define WCD9335_CDC_TX4_TX_PATH_SEC0 0x0a77
+#define WCD9335_CDC_TX4_TX_PATH_SEC1 0x0a78
+#define WCD9335_CDC_TX4_TX_PATH_SEC2 0x0a79
+#define WCD9335_CDC_TX4_TX_PATH_SEC3 0x0a7a
+#define WCD9335_CDC_TX4_TX_PATH_SEC4 0x0a7b
+#define WCD9335_CDC_TX4_TX_PATH_SEC5 0x0a7c
+#define WCD9335_CDC_TX4_TX_PATH_SEC6 0x0a7d
+#define WCD9335_CDC_TX5_TX_PATH_CTL 0x0a81
+#define WCD9335_CDC_TX5_TX_PATH_CFG0 0x0a82
+#define WCD9335_CDC_TX5_TX_PATH_CFG1 0x0a83
+#define WCD9335_CDC_TX5_TX_VOL_CTL 0x0a84
+#define WCD9335_CDC_TX5_TX_PATH_192_CTL 0x0a85
+#define WCD9335_CDC_TX5_TX_PATH_192_CFG 0x0a86
+#define WCD9335_CDC_TX5_TX_PATH_SEC0 0x0a87
+#define WCD9335_CDC_TX5_TX_PATH_SEC1 0x0a88
+#define WCD9335_CDC_TX5_TX_PATH_SEC2 0x0a89
+#define WCD9335_CDC_TX5_TX_PATH_SEC3 0x0a8a
+#define WCD9335_CDC_TX5_TX_PATH_SEC4 0x0a8b
+#define WCD9335_CDC_TX5_TX_PATH_SEC5 0x0a8c
+#define WCD9335_CDC_TX5_TX_PATH_SEC6 0x0a8d
+#define WCD9335_CDC_TX6_TX_PATH_CTL 0x0a91
+#define WCD9335_CDC_TX6_TX_PATH_CFG0 0x0a92
+#define WCD9335_CDC_TX6_TX_PATH_CFG1 0x0a93
+#define WCD9335_CDC_TX6_TX_VOL_CTL 0x0a94
+#define WCD9335_CDC_TX6_TX_PATH_192_CTL 0x0a95
+#define WCD9335_CDC_TX6_TX_PATH_192_CFG 0x0a96
+#define WCD9335_CDC_TX6_TX_PATH_SEC0 0x0a97
+#define WCD9335_CDC_TX6_TX_PATH_SEC1 0x0a98
+#define WCD9335_CDC_TX6_TX_PATH_SEC2 0x0a99
+#define WCD9335_CDC_TX6_TX_PATH_SEC3 0x0a9a
+#define WCD9335_CDC_TX6_TX_PATH_SEC4 0x0a9b
+#define WCD9335_CDC_TX6_TX_PATH_SEC5 0x0a9c
+#define WCD9335_CDC_TX6_TX_PATH_SEC6 0x0a9d
+#define WCD9335_CDC_TX7_TX_PATH_CTL 0x0aa1
+#define WCD9335_CDC_TX7_TX_PATH_CFG0 0x0aa2
+#define WCD9335_CDC_TX7_TX_PATH_CFG1 0x0aa3
+#define WCD9335_CDC_TX7_TX_VOL_CTL 0x0aa4
+#define WCD9335_CDC_TX7_TX_PATH_192_CTL 0x0aa5
+#define WCD9335_CDC_TX7_TX_PATH_192_CFG 0x0aa6
+#define WCD9335_CDC_TX7_TX_PATH_SEC0 0x0aa7
+#define WCD9335_CDC_TX7_TX_PATH_SEC1 0x0aa8
+#define WCD9335_CDC_TX7_TX_PATH_SEC2 0x0aa9
+#define WCD9335_CDC_TX7_TX_PATH_SEC3 0x0aaa
+#define WCD9335_CDC_TX7_TX_PATH_SEC4 0x0aab
+#define WCD9335_CDC_TX7_TX_PATH_SEC5 0x0aac
+#define WCD9335_CDC_TX7_TX_PATH_SEC6 0x0aad
+#define WCD9335_CDC_TX8_TX_PATH_CTL 0x0ab1
+#define WCD9335_CDC_TX8_TX_PATH_CFG0 0x0ab2
+#define WCD9335_CDC_TX8_TX_PATH_CFG1 0x0ab3
+#define WCD9335_CDC_TX8_TX_VOL_CTL 0x0ab4
+#define WCD9335_CDC_TX8_TX_PATH_192_CTL 0x0ab5
+#define WCD9335_CDC_TX8_TX_PATH_192_CFG 0x0ab6
+#define WCD9335_CDC_TX8_TX_PATH_SEC0 0x0ab7
+#define WCD9335_CDC_TX8_TX_PATH_SEC1 0x0ab8
+#define WCD9335_CDC_TX8_TX_PATH_SEC2 0x0ab9
+#define WCD9335_CDC_TX8_TX_PATH_SEC3 0x0aba
+#define WCD9335_CDC_TX8_TX_PATH_SEC4 0x0abb
+#define WCD9335_CDC_TX8_TX_PATH_SEC5 0x0abc
+#define WCD9335_CDC_TX8_TX_PATH_SEC6 0x0abd
+#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CTL 0x0ac2
+#define WCD9335_CDC_TX9_SPKR_PROT_PATH_CFG0 0x0ac3
+#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CTL 0x0ac6
+#define WCD9335_CDC_TX10_SPKR_PROT_PATH_CFG0 0x0ac7
+#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CTL 0x0aca
+#define WCD9335_CDC_TX11_SPKR_PROT_PATH_CFG0 0x0acb
+#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CTL 0x0ace
+#define WCD9335_CDC_TX12_SPKR_PROT_PATH_CFG0 0x0acf
+
+/* Page-11 Registers */
+#define WCD9335_PAGE11_PAGE_REGISTER 0x0b00
+#define WCD9335_CDC_COMPANDER1_CTL0 0x0b01
+#define WCD9335_CDC_COMPANDER1_CTL1 0x0b02
+#define WCD9335_CDC_COMPANDER1_CTL2 0x0b03
+#define WCD9335_CDC_COMPANDER1_CTL3 0x0b04
+#define WCD9335_CDC_COMPANDER1_CTL4 0x0b05
+#define WCD9335_CDC_COMPANDER1_CTL5 0x0b06
+#define WCD9335_CDC_COMPANDER1_CTL6 0x0b07
+#define WCD9335_CDC_COMPANDER1_CTL7 0x0b08
+#define WCD9335_CDC_COMPANDER2_CTL0 0x0b09
+#define WCD9335_CDC_COMPANDER2_CTL1 0x0b0a
+#define WCD9335_CDC_COMPANDER2_CTL2 0x0b0b
+#define WCD9335_CDC_COMPANDER2_CTL3 0x0b0c
+#define WCD9335_CDC_COMPANDER2_CTL4 0x0b0d
+#define WCD9335_CDC_COMPANDER2_CTL5 0x0b0e
+#define WCD9335_CDC_COMPANDER2_CTL6 0x0b0f
+#define WCD9335_CDC_COMPANDER2_CTL7 0x0b10
+#define WCD9335_CDC_COMPANDER3_CTL0 0x0b11
+#define WCD9335_CDC_COMPANDER3_CTL1 0x0b12
+#define WCD9335_CDC_COMPANDER3_CTL2 0x0b13
+#define WCD9335_CDC_COMPANDER3_CTL3 0x0b14
+#define WCD9335_CDC_COMPANDER3_CTL4 0x0b15
+#define WCD9335_CDC_COMPANDER3_CTL5 0x0b16
+#define WCD9335_CDC_COMPANDER3_CTL6 0x0b17
+#define WCD9335_CDC_COMPANDER3_CTL7 0x0b18
+#define WCD9335_CDC_COMPANDER4_CTL0 0x0b19
+#define WCD9335_CDC_COMPANDER4_CTL1 0x0b1a
+#define WCD9335_CDC_COMPANDER4_CTL2 0x0b1b
+#define WCD9335_CDC_COMPANDER4_CTL3 0x0b1c
+#define WCD9335_CDC_COMPANDER4_CTL4 0x0b1d
+#define WCD9335_CDC_COMPANDER4_CTL5 0x0b1e
+#define WCD9335_CDC_COMPANDER4_CTL6 0x0b1f
+#define WCD9335_CDC_COMPANDER4_CTL7 0x0b20
+#define WCD9335_CDC_COMPANDER5_CTL0 0x0b21
+#define WCD9335_CDC_COMPANDER5_CTL1 0x0b22
+#define WCD9335_CDC_COMPANDER5_CTL2 0x0b23
+#define WCD9335_CDC_COMPANDER5_CTL3 0x0b24
+#define WCD9335_CDC_COMPANDER5_CTL4 0x0b25
+#define WCD9335_CDC_COMPANDER5_CTL5 0x0b26
+#define WCD9335_CDC_COMPANDER5_CTL6 0x0b27
+#define WCD9335_CDC_COMPANDER5_CTL7 0x0b28
+#define WCD9335_CDC_COMPANDER6_CTL0 0x0b29
+#define WCD9335_CDC_COMPANDER6_CTL1 0x0b2a
+#define WCD9335_CDC_COMPANDER6_CTL2 0x0b2b
+#define WCD9335_CDC_COMPANDER6_CTL3 0x0b2c
+#define WCD9335_CDC_COMPANDER6_CTL4 0x0b2d
+#define WCD9335_CDC_COMPANDER6_CTL5 0x0b2e
+#define WCD9335_CDC_COMPANDER6_CTL6 0x0b2f
+#define WCD9335_CDC_COMPANDER6_CTL7 0x0b30
+#define WCD9335_CDC_COMPANDER7_CTL0 0x0b31
+#define WCD9335_CDC_COMPANDER7_CTL1 0x0b32
+#define WCD9335_CDC_COMPANDER7_CTL2 0x0b33
+#define WCD9335_CDC_COMPANDER7_CTL3 0x0b34
+#define WCD9335_CDC_COMPANDER7_CTL4 0x0b35
+#define WCD9335_CDC_COMPANDER7_CTL5 0x0b36
+#define WCD9335_CDC_COMPANDER7_CTL6 0x0b37
+#define WCD9335_CDC_COMPANDER7_CTL7 0x0b38
+#define WCD9335_CDC_COMPANDER8_CTL0 0x0b39
+#define WCD9335_CDC_COMPANDER8_CTL1 0x0b3a
+#define WCD9335_CDC_COMPANDER8_CTL2 0x0b3b
+#define WCD9335_CDC_COMPANDER8_CTL3 0x0b3c
+#define WCD9335_CDC_COMPANDER8_CTL4 0x0b3d
+#define WCD9335_CDC_COMPANDER8_CTL5 0x0b3e
+#define WCD9335_CDC_COMPANDER8_CTL6 0x0b3f
+#define WCD9335_CDC_COMPANDER8_CTL7 0x0b40
+#define WCD9335_CDC_RX0_RX_PATH_CTL 0x0b41
+#define WCD9335_CDC_RX0_RX_PATH_CFG0 0x0b42
+#define WCD9335_CDC_RX0_RX_PATH_CFG1 0x0b43
+#define WCD9335_CDC_RX0_RX_PATH_CFG2 0x0b44
+#define WCD9335_CDC_RX0_RX_VOL_CTL 0x0b45
+#define WCD9335_CDC_RX0_RX_PATH_MIX_CTL 0x0b46
+#define WCD9335_CDC_RX0_RX_PATH_MIX_CFG 0x0b47
+#define WCD9335_CDC_RX0_RX_VOL_MIX_CTL 0x0b48
+#define WCD9335_CDC_RX0_RX_PATH_SEC0 0x0b49
+#define WCD9335_CDC_RX0_RX_PATH_SEC1 0x0b4a
+#define WCD9335_CDC_RX0_RX_PATH_SEC2 0x0b4b
+#define WCD9335_CDC_RX0_RX_PATH_SEC3 0x0b4c
+#define WCD9335_CDC_RX0_RX_PATH_SEC5 0x0b4e
+#define WCD9335_CDC_RX0_RX_PATH_SEC6 0x0b4f
+#define WCD9335_CDC_RX0_RX_PATH_SEC7 0x0b50
+#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC0 0x0b51
+#define WCD9335_CDC_RX0_RX_PATH_MIX_SEC1 0x0b52
+#define WCD9335_CDC_RX1_RX_PATH_CTL 0x0b55
+#define WCD9335_CDC_RX1_RX_PATH_CFG0 0x0b56
+#define WCD9335_CDC_RX1_RX_PATH_CFG1 0x0b57
+#define WCD9335_CDC_RX1_RX_PATH_CFG2 0x0b58
+#define WCD9335_CDC_RX1_RX_VOL_CTL 0x0b59
+#define WCD9335_CDC_RX1_RX_PATH_MIX_CTL 0x0b5a
+#define WCD9335_CDC_RX1_RX_PATH_MIX_CFG 0x0b5b
+#define WCD9335_CDC_RX1_RX_VOL_MIX_CTL 0x0b5c
+#define WCD9335_CDC_RX1_RX_PATH_SEC0 0x0b5d
+#define WCD9335_CDC_RX1_RX_PATH_SEC1 0x0b5e
+#define WCD9335_CDC_RX1_RX_PATH_SEC2 0x0b5f
+#define WCD9335_CDC_RX1_RX_PATH_SEC3 0x0b60
+#define WCD9335_CDC_RX1_RX_PATH_SEC4 0x0b61
+#define WCD9335_CDC_RX1_RX_PATH_SEC5 0x0b62
+#define WCD9335_CDC_RX1_RX_PATH_SEC6 0x0b63
+#define WCD9335_CDC_RX1_RX_PATH_SEC7 0x0b64
+#define WCD9335_CDC_RX1_RX_PATH_MIX_SEC0 0x0b65
+#define WCD9335_CDC_RX1_RX_PATH_MIX_SEC1 0x0b66
+#define WCD9335_CDC_RX2_RX_PATH_CTL 0x0b69
+#define WCD9335_CDC_RX2_RX_PATH_CFG0 0x0b6a
+#define WCD9335_CDC_RX2_RX_PATH_CFG1 0x0b6b
+#define WCD9335_CDC_RX2_RX_PATH_CFG2 0x0b6c
+#define WCD9335_CDC_RX2_RX_VOL_CTL 0x0b6d
+#define WCD9335_CDC_RX2_RX_PATH_MIX_CTL 0x0b6e
+#define WCD9335_CDC_RX2_RX_PATH_MIX_CFG 0x0b6f
+#define WCD9335_CDC_RX2_RX_VOL_MIX_CTL 0x0b70
+#define WCD9335_CDC_RX2_RX_PATH_SEC0 0x0b71
+#define WCD9335_CDC_RX2_RX_PATH_SEC1 0x0b72
+#define WCD9335_CDC_RX2_RX_PATH_SEC2 0x0b73
+#define WCD9335_CDC_RX2_RX_PATH_SEC3 0x0b74
+#define WCD9335_CDC_RX2_RX_PATH_SEC4 0x0b75
+#define WCD9335_CDC_RX2_RX_PATH_SEC5 0x0b76
+#define WCD9335_CDC_RX2_RX_PATH_SEC6 0x0b77
+#define WCD9335_CDC_RX2_RX_PATH_SEC7 0x0b78
+#define WCD9335_CDC_RX2_RX_PATH_MIX_SEC0 0x0b79
+#define WCD9335_CDC_RX2_RX_PATH_MIX_SEC1 0x0b7a
+#define WCD9335_CDC_RX3_RX_PATH_CTL 0x0b7d
+#define WCD9335_CDC_RX3_RX_PATH_CFG0 0x0b7e
+#define WCD9335_CDC_RX3_RX_PATH_CFG1 0x0b7f
+#define WCD9335_CDC_RX3_RX_PATH_CFG2 0x0b80
+#define WCD9335_CDC_RX3_RX_VOL_CTL 0x0b81
+#define WCD9335_CDC_RX3_RX_PATH_MIX_CTL 0x0b82
+#define WCD9335_CDC_RX3_RX_PATH_MIX_CFG 0x0b83
+#define WCD9335_CDC_RX3_RX_VOL_MIX_CTL 0x0b84
+#define WCD9335_CDC_RX3_RX_PATH_SEC0 0x0b85
+#define WCD9335_CDC_RX3_RX_PATH_SEC1 0x0b86
+#define WCD9335_CDC_RX3_RX_PATH_SEC2 0x0b87
+#define WCD9335_CDC_RX3_RX_PATH_SEC3 0x0b88
+#define WCD9335_CDC_RX3_RX_PATH_SEC5 0x0b8a
+#define WCD9335_CDC_RX3_RX_PATH_SEC6 0x0b8b
+#define WCD9335_CDC_RX3_RX_PATH_SEC7 0x0b8c
+#define WCD9335_CDC_RX3_RX_PATH_MIX_SEC0 0x0b8d
+#define WCD9335_CDC_RX3_RX_PATH_MIX_SEC1 0x0b8e
+#define WCD9335_CDC_RX4_RX_PATH_CTL 0x0b91
+#define WCD9335_CDC_RX4_RX_PATH_CFG0 0x0b92
+#define WCD9335_CDC_RX4_RX_PATH_CFG1 0x0b93
+#define WCD9335_CDC_RX4_RX_PATH_CFG2 0x0b94
+#define WCD9335_CDC_RX4_RX_VOL_CTL 0x0b95
+#define WCD9335_CDC_RX4_RX_PATH_MIX_CTL 0x0b96
+#define WCD9335_CDC_RX4_RX_PATH_MIX_CFG 0x0b97
+#define WCD9335_CDC_RX4_RX_VOL_MIX_CTL 0x0b98
+#define WCD9335_CDC_RX4_RX_PATH_SEC0 0x0b99
+#define WCD9335_CDC_RX4_RX_PATH_SEC1 0x0b9a
+#define WCD9335_CDC_RX4_RX_PATH_SEC2 0x0b9b
+#define WCD9335_CDC_RX4_RX_PATH_SEC3 0x0b9c
+#define WCD9335_CDC_RX4_RX_PATH_SEC5 0x0b9e
+#define WCD9335_CDC_RX4_RX_PATH_SEC6 0x0b9f
+#define WCD9335_CDC_RX4_RX_PATH_SEC7 0x0ba0
+#define WCD9335_CDC_RX4_RX_PATH_MIX_SEC0 0x0ba1
+#define WCD9335_CDC_RX4_RX_PATH_MIX_SEC1 0x0ba2
+#define WCD9335_CDC_RX5_RX_PATH_CTL 0x0ba5
+#define WCD9335_CDC_RX5_RX_PATH_CFG0 0x0ba6
+#define WCD9335_CDC_RX5_RX_PATH_CFG1 0x0ba7
+#define WCD9335_CDC_RX5_RX_PATH_CFG2 0x0ba8
+#define WCD9335_CDC_RX5_RX_VOL_CTL 0x0ba9
+#define WCD9335_CDC_RX5_RX_PATH_MIX_CTL 0x0baa
+#define WCD9335_CDC_RX5_RX_PATH_MIX_CFG 0x0bab
+#define WCD9335_CDC_RX5_RX_VOL_MIX_CTL 0x0bac
+#define WCD9335_CDC_RX5_RX_PATH_SEC0 0x0bad
+#define WCD9335_CDC_RX5_RX_PATH_SEC1 0x0bae
+#define WCD9335_CDC_RX5_RX_PATH_SEC2 0x0baf
+#define WCD9335_CDC_RX5_RX_PATH_SEC3 0x0bb0
+#define WCD9335_CDC_RX5_RX_PATH_SEC5 0x0bb2
+#define WCD9335_CDC_RX5_RX_PATH_SEC6 0x0bb3
+#define WCD9335_CDC_RX5_RX_PATH_SEC7 0x0bb4
+#define WCD9335_CDC_RX5_RX_PATH_MIX_SEC0 0x0bb5
+#define WCD9335_CDC_RX5_RX_PATH_MIX_SEC1 0x0bb6
+#define WCD9335_CDC_RX6_RX_PATH_CTL 0x0bb9
+#define WCD9335_CDC_RX6_RX_PATH_CFG0 0x0bba
+#define WCD9335_CDC_RX6_RX_PATH_CFG1 0x0bbb
+#define WCD9335_CDC_RX6_RX_PATH_CFG2 0x0bbc
+#define WCD9335_CDC_RX6_RX_VOL_CTL 0x0bbd
+#define WCD9335_CDC_RX6_RX_PATH_MIX_CTL 0x0bbe
+#define WCD9335_CDC_RX6_RX_PATH_MIX_CFG 0x0bbf
+#define WCD9335_CDC_RX6_RX_VOL_MIX_CTL 0x0bc0
+#define WCD9335_CDC_RX6_RX_PATH_SEC0 0x0bc1
+#define WCD9335_CDC_RX6_RX_PATH_SEC1 0x0bc2
+#define WCD9335_CDC_RX6_RX_PATH_SEC2 0x0bc3
+#define WCD9335_CDC_RX6_RX_PATH_SEC3 0x0bc4
+#define WCD9335_CDC_RX6_RX_PATH_SEC5 0x0bc6
+#define WCD9335_CDC_RX6_RX_PATH_SEC6 0x0bc7
+#define WCD9335_CDC_RX6_RX_PATH_SEC7 0x0bc8
+#define WCD9335_CDC_RX6_RX_PATH_MIX_SEC0 0x0bc9
+#define WCD9335_CDC_RX6_RX_PATH_MIX_SEC1 0x0bca
+#define WCD9335_CDC_RX7_RX_PATH_CTL 0x0bcd
+#define WCD9335_CDC_RX7_RX_PATH_CFG0 0x0bce
+#define WCD9335_CDC_RX7_RX_PATH_CFG1 0x0bcf
+#define WCD9335_CDC_RX7_RX_PATH_CFG2 0x0bd0
+#define WCD9335_CDC_RX7_RX_VOL_CTL 0x0bd1
+#define WCD9335_CDC_RX7_RX_PATH_MIX_CTL 0x0bd2
+#define WCD9335_CDC_RX7_RX_PATH_MIX_CFG 0x0bd3
+#define WCD9335_CDC_RX7_RX_VOL_MIX_CTL 0x0bd4
+#define WCD9335_CDC_RX7_RX_PATH_SEC0 0x0bd5
+#define WCD9335_CDC_RX7_RX_PATH_SEC1 0x0bd6
+#define WCD9335_CDC_RX7_RX_PATH_SEC2 0x0bd7
+#define WCD9335_CDC_RX7_RX_PATH_SEC3 0x0bd8
+#define WCD9335_CDC_RX7_RX_PATH_SEC5 0x0bda
+#define WCD9335_CDC_RX7_RX_PATH_SEC6 0x0bdb
+#define WCD9335_CDC_RX7_RX_PATH_SEC7 0x0bdc
+#define WCD9335_CDC_RX7_RX_PATH_MIX_SEC0 0x0bdd
+#define WCD9335_CDC_RX7_RX_PATH_MIX_SEC1 0x0bde
+#define WCD9335_CDC_RX8_RX_PATH_CTL 0x0be1
+#define WCD9335_CDC_RX8_RX_PATH_CFG0 0x0be2
+#define WCD9335_CDC_RX8_RX_PATH_CFG1 0x0be3
+#define WCD9335_CDC_RX8_RX_PATH_CFG2 0x0be4
+#define WCD9335_CDC_RX8_RX_VOL_CTL 0x0be5
+#define WCD9335_CDC_RX8_RX_PATH_MIX_CTL 0x0be6
+#define WCD9335_CDC_RX8_RX_PATH_MIX_CFG 0x0be7
+#define WCD9335_CDC_RX8_RX_VOL_MIX_CTL 0x0be8
+#define WCD9335_CDC_RX8_RX_PATH_SEC0 0x0be9
+#define WCD9335_CDC_RX8_RX_PATH_SEC1 0x0bea
+#define WCD9335_CDC_RX8_RX_PATH_SEC2 0x0beb
+#define WCD9335_CDC_RX8_RX_PATH_SEC3 0x0bec
+#define WCD9335_CDC_RX8_RX_PATH_SEC5 0x0bee
+#define WCD9335_CDC_RX8_RX_PATH_SEC6 0x0bef
+#define WCD9335_CDC_RX8_RX_PATH_SEC7 0x0bf0
+#define WCD9335_CDC_RX8_RX_PATH_MIX_SEC0 0x0bf1
+#define WCD9335_CDC_RX8_RX_PATH_MIX_SEC1 0x0bf2
+
+/* Page-12 Registers */
+#define WCD9335_PAGE12_PAGE_REGISTER 0x0c00
+#define WCD9335_CDC_CLSH_CRC 0x0c01
+#define WCD9335_CDC_CLSH_DLY_CTRL 0x0c02
+#define WCD9335_CDC_CLSH_DECAY_CTRL 0x0c03
+#define WCD9335_CDC_CLSH_HPH_V_PA 0x0c04
+#define WCD9335_CDC_CLSH_EAR_V_PA 0x0c05
+#define WCD9335_CDC_CLSH_HPH_V_HD 0x0c06
+#define WCD9335_CDC_CLSH_EAR_V_HD 0x0c07
+#define WCD9335_CDC_CLSH_K1_MSB 0x0c08
+#define WCD9335_CDC_CLSH_K1_LSB 0x0c09
+#define WCD9335_CDC_CLSH_K2_MSB 0x0c0a
+#define WCD9335_CDC_CLSH_K2_LSB 0x0c0b
+#define WCD9335_CDC_CLSH_IDLE_CTRL 0x0c0c
+#define WCD9335_CDC_CLSH_IDLE_HPH 0x0c0d
+#define WCD9335_CDC_CLSH_IDLE_EAR 0x0c0e
+#define WCD9335_CDC_CLSH_TEST0 0x0c0f
+#define WCD9335_CDC_CLSH_TEST1 0x0c10
+#define WCD9335_CDC_CLSH_OVR_VREF 0x0c11
+#define WCD9335_CDC_BOOST0_BOOST_PATH_CTL 0x0c19
+#define WCD9335_CDC_BOOST0_BOOST_CTL 0x0c1a
+#define WCD9335_CDC_BOOST0_BOOST_CFG1 0x0c1b
+#define WCD9335_CDC_BOOST0_BOOST_CFG2 0x0c1c
+#define WCD9335_CDC_BOOST1_BOOST_PATH_CTL 0x0c21
+#define WCD9335_CDC_BOOST1_BOOST_CTL 0x0c22
+#define WCD9335_CDC_BOOST1_BOOST_CFG1 0x0c23
+#define WCD9335_CDC_BOOST1_BOOST_CFG2 0x0c24
+#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_0 0x0c29
+#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_1 0x0c2a
+#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_2 0x0c2b
+#define WCD9335_SWR_AHB_BRIDGE_WR_DATA_3 0x0c2c
+#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_0 0x0c2d
+#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_1 0x0c2e
+#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_2 0x0c2f
+#define WCD9335_SWR_AHB_BRIDGE_WR_ADDR_3 0x0c30
+#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_0 0x0c31
+#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_1 0x0c32
+#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_2 0x0c33
+#define WCD9335_SWR_AHB_BRIDGE_RD_ADDR_3 0x0c34
+#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_0 0x0c35
+#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_1 0x0c36
+#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_2 0x0c37
+#define WCD9335_SWR_AHB_BRIDGE_RD_DATA_3 0x0c38
+#define WCD9335_SWR_AHB_BRIDGE_ACCESS_CFG 0x0c39
+#define WCD9335_SWR_AHB_BRIDGE_ACCESS_STATUS 0x0c3a
+#define WCD9335_CDC_VBAT_VBAT_PATH_CTL 0x0c3d
+#define WCD9335_CDC_VBAT_VBAT_CFG 0x0c3e
+#define WCD9335_CDC_VBAT_VBAT_ADC_CAL1 0x0c3f
+#define WCD9335_CDC_VBAT_VBAT_ADC_CAL2 0x0c40
+#define WCD9335_CDC_VBAT_VBAT_ADC_CAL3 0x0c41
+#define WCD9335_CDC_VBAT_VBAT_PK_EST1 0x0c42
+#define WCD9335_CDC_VBAT_VBAT_PK_EST2 0x0c43
+#define WCD9335_CDC_VBAT_VBAT_PK_EST3 0x0c44
+#define WCD9335_CDC_VBAT_VBAT_RF_PROC1 0x0c45
+#define WCD9335_CDC_VBAT_VBAT_RF_PROC2 0x0c46
+#define WCD9335_CDC_VBAT_VBAT_TAC1 0x0c47
+#define WCD9335_CDC_VBAT_VBAT_TAC2 0x0c48
+#define WCD9335_CDC_VBAT_VBAT_TAC3 0x0c49
+#define WCD9335_CDC_VBAT_VBAT_TAC4 0x0c4a
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD1 0x0c4b
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD2 0x0c4c
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD3 0x0c4d
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD4 0x0c4e
+#define WCD9335_CDC_VBAT_VBAT_DEBUG1 0x0c4f
+#define WCD9335_CDC_VBAT_VBAT_GAIN_UPD_MON 0x0c50
+#define WCD9335_CDC_VBAT_VBAT_GAIN_MON_VAL 0x0c51
+#define WCD9335_SPLINE_SRC0_CLK_RST_CTL_0 0x0c55
+#define WCD9335_SPLINE_SRC0_STATUS 0x0c56
+#define WCD9335_SPLINE_SRC1_CLK_RST_CTL_0 0x0c6d
+#define WCD9335_SPLINE_SRC1_STATUS 0x0c6e
+#define WCD9335_SPLINE_SRC2_CLK_RST_CTL_0 0x0c85
+#define WCD9335_SPLINE_SRC2_STATUS 0x0c86
+#define WCD9335_SPLINE_SRC3_CLK_RST_CTL_0 0x0c9d
+#define WCD9335_SPLINE_SRC3_STATUS 0x0c9e
+#define WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CTL 0x0cb5
+#define WCD9335_CDC_SIDETONE_SRC0_ST_SRC_PATH_CFG1 0x0cb6
+#define WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CTL 0x0cb9
+#define WCD9335_CDC_SIDETONE_SRC1_ST_SRC_PATH_CFG1 0x0cba
+
+/* Page-13 Registers */
+#define WCD9335_PAGE13_PAGE_REGISTER 0x0d00
+#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG0 0x0d01
+#define WCD9335_CDC_RX_INP_MUX_RX_INT0_CFG1 0x0d02
+#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG0 0x0d03
+#define WCD9335_CDC_RX_INP_MUX_RX_INT1_CFG1 0x0d04
+#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG0 0x0d05
+#define WCD9335_CDC_RX_INP_MUX_RX_INT2_CFG1 0x0d06
+#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG0 0x0d07
+#define WCD9335_CDC_RX_INP_MUX_RX_INT3_CFG1 0x0d08
+#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG0 0x0d09
+#define WCD9335_CDC_RX_INP_MUX_RX_INT4_CFG1 0x0d0a
+#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG0 0x0d0b
+#define WCD9335_CDC_RX_INP_MUX_RX_INT5_CFG1 0x0d0c
+#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG0 0x0d0d
+#define WCD9335_CDC_RX_INP_MUX_RX_INT6_CFG1 0x0d0e
+#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG0 0x0d0f
+#define WCD9335_CDC_RX_INP_MUX_RX_INT7_CFG1 0x0d10
+#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG0 0x0d11
+#define WCD9335_CDC_RX_INP_MUX_RX_INT8_CFG1 0x0d12
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG0 0x0d13
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG1 0x0d14
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG2 0x0d15
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG3 0x0d16
+#define WCD9335_CDC_RX_INP_MUX_RX_MIX_CFG4 0x0d17
+#define WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG0 0x0d18
+#define WCD9335_CDC_RX_INP_MUX_SIDETONE_SRC_CFG1 0x0d19
+#define WCD9335_CDC_RX_INP_MUX_ANC_CFG0 0x0d1a
+#define WCD9335_CDC_RX_INP_MUX_SPLINE_SRC_CFG0 0x0d1b
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG0 0x0d1d
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX0_CFG1 0x0d1e
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG0 0x0d1f
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX1_CFG1 0x0d20
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG0 0x0d21
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX2_CFG1 0x0d22
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG0 0x0d23
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX3_CFG1 0x0d24
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX4_CFG0 0x0d25
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX5_CFG0 0x0d26
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX6_CFG0 0x0d27
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX7_CFG0 0x0d28
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX8_CFG0 0x0d29
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX10_CFG0 0x0d2b
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX11_CFG0 0x0d2c
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX12_CFG0 0x0d2d
+#define WCD9335_CDC_TX_INP_MUX_ADC_MUX13_CFG0 0x0d2e
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG0 0x0d31
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG1 0x0d32
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG2 0x0d33
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR0_MIX_CFG3 0x0d34
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG0 0x0d35
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG1 0x0d36
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG2 0x0d37
+#define WCD9335_CDC_SIDETONE_IIR_INP_MUX_IIR1_MIX_CFG3 0x0d38
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG0 0x0d3a
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG1 0x0d3b
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG2 0x0d3c
+#define WCD9335_CDC_IF_ROUTER_TX_MUX_CFG3 0x0d3d
+#define WCD9335_CDC_CLK_RST_CTRL_MCLK_CONTROL 0x0d41
+#define WCD9335_CDC_CLK_RST_CTRL_FS_CNT_CONTROL 0x0d42
+#define WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL 0x0d43
+#define WCD9335_CDC_PROX_DETECT_PROX_CTL 0x0d49
+#define WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD0 0x0d4a
+#define WCD9335_CDC_PROX_DETECT_PROX_POLL_PERIOD1 0x0d4b
+#define WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_LSB 0x0d4c
+#define WCD9335_CDC_PROX_DETECT_PROX_SIG_PATTERN_MSB 0x0d4d
+#define WCD9335_CDC_PROX_DETECT_PROX_STATUS 0x0d4e
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_CTRL 0x0d4f
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB 0x0d50
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB 0x0d51
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_LSB_RD 0x0d52
+#define WCD9335_CDC_PROX_DETECT_PROX_TEST_BUFF_MSB_RD 0x0d53
+#define WCD9335_CDC_PROX_DETECT_PROX_CTL_REPEAT_PAT 0x0d54
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_PATH_CTL 0x0d55
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B1_CTL 0x0d56
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B2_CTL 0x0d57
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B3_CTL 0x0d58
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B4_CTL 0x0d59
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B5_CTL 0x0d5a
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B6_CTL 0x0d5b
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B7_CTL 0x0d5c
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_B8_CTL 0x0d5d
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_CTL 0x0d5e
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_GAIN_TIMER_CTL 0x0d5f
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL 0x0d60
+#define WCD9335_CDC_SIDETONE_IIR0_IIR_COEF_B2_CTL 0x0d61
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_PATH_CTL 0x0d65
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B1_CTL 0x0d66
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B2_CTL 0x0d67
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B3_CTL 0x0d68
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL 0x0d69
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B5_CTL 0x0d6a
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B6_CTL 0x0d6b
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B7_CTL 0x0d6c
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_B8_CTL 0x0d6d
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_CTL 0x0d6e
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_GAIN_TIMER_CTL 0x0d6f
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B1_CTL 0x0d70
+#define WCD9335_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL 0x0d71
+#define WCD9335_CDC_TOP_TOP_CFG0 0x0d81
+#define WCD9335_CDC_TOP_TOP_CFG1 0x0d82
+#define WCD9335_CDC_TOP_TOP_CFG2 0x0d83
+#define WCD9335_CDC_TOP_TOP_CFG3 0x0d84
+#define WCD9335_CDC_TOP_TOP_CFG4 0x0d85
+#define WCD9335_CDC_TOP_TOP_CFG5 0x0d86
+#define WCD9335_CDC_TOP_TOP_CFG6 0x0d87
+#define WCD9335_CDC_TOP_TOP_CFG7 0x0d88
+#define WCD9335_CDC_TOP_HPHL_COMP_WR_LSB 0x0d89
+#define WCD9335_CDC_TOP_HPHL_COMP_WR_MSB 0x0d8a
+#define WCD9335_CDC_TOP_HPHL_COMP_LUT 0x0d8b
+#define WCD9335_CDC_TOP_HPHL_COMP_RD_LSB 0x0d8c
+#define WCD9335_CDC_TOP_HPHL_COMP_RD_MSB 0x0d8d
+#define WCD9335_CDC_TOP_HPHR_COMP_WR_LSB 0x0d8e
+#define WCD9335_CDC_TOP_HPHR_COMP_WR_MSB 0x0d8f
+#define WCD9335_CDC_TOP_HPHR_COMP_LUT 0x0d90
+#define WCD9335_CDC_TOP_HPHR_COMP_RD_LSB 0x0d91
+#define WCD9335_CDC_TOP_HPHR_COMP_RD_MSB 0x0d92
+#define WCD9335_CDC_TOP_DIFFL_COMP_WR_LSB 0x0d93
+#define WCD9335_CDC_TOP_DIFFL_COMP_WR_MSB 0x0d94
+#define WCD9335_CDC_TOP_DIFFL_COMP_LUT 0x0d95
+#define WCD9335_CDC_TOP_DIFFL_COMP_RD_LSB 0x0d96
+#define WCD9335_CDC_TOP_DIFFL_COMP_RD_MSB 0x0d97
+#define WCD9335_CDC_TOP_DIFFR_COMP_WR_LSB 0x0d98
+#define WCD9335_CDC_TOP_DIFFR_COMP_WR_MSB 0x0d99
+#define WCD9335_CDC_TOP_DIFFR_COMP_LUT 0x0d9a
+#define WCD9335_CDC_TOP_DIFFR_COMP_RD_LSB 0x0d9b
+#define WCD9335_CDC_TOP_DIFFR_COMP_RD_MSB 0x0d9c
+
+/* Page-0x80 Registers */
+#define WCD9335_PAGE80_PAGE_REGISTER 0x8000
+#define WCD9335_TLMM_BIST_MODE_PINCFG 0x8001
+#define WCD9335_TLMM_RF_PA_ON_PINCFG 0x8002
+#define WCD9335_TLMM_INTR1_PINCFG 0x8003
+#define WCD9335_TLMM_INTR2_PINCFG 0x8004
+#define WCD9335_TLMM_SWR_DATA_PINCFG 0x8005
+#define WCD9335_TLMM_SWR_CLK_PINCFG 0x8006
+#define WCD9335_TLMM_SLIMBUS_DATA2_PINCFG 0x8007
+#define WCD9335_TLMM_I2C_CLK_PINCFG 0x8008
+#define WCD9335_TLMM_I2C_DATA_PINCFG 0x8009
+#define WCD9335_TLMM_I2S_RX_SD0_PINCFG 0x800a
+#define WCD9335_TLMM_I2S_RX_SD1_PINCFG 0x800b
+#define WCD9335_TLMM_I2S_RX_SCK_PINCFG 0x800c
+#define WCD9335_TLMM_I2S_RX_WS_PINCFG 0x800d
+#define WCD9335_TLMM_I2S_TX_SD0_PINCFG 0x800e
+#define WCD9335_TLMM_I2S_TX_SD1_PINCFG 0x800f
+#define WCD9335_TLMM_I2S_TX_SCK_PINCFG 0x8010
+#define WCD9335_TLMM_I2S_TX_WS_PINCFG 0x8011
+#define WCD9335_TLMM_DMIC1_CLK_PINCFG 0x8012
+#define WCD9335_TLMM_DMIC1_DATA_PINCFG 0x8013
+#define WCD9335_TLMM_DMIC2_CLK_PINCFG 0x8014
+#define WCD9335_TLMM_DMIC2_DATA_PINCFG 0x8015
+#define WCD9335_TLMM_DMIC3_CLK_PINCFG 0x8016
+#define WCD9335_TLMM_DMIC3_DATA_PINCFG 0x8017
+#define WCD9335_TLMM_JTDI_PINCFG 0x8018
+#define WCD9335_TLMM_JTDO_PINCFG 0x8019
+#define WCD9335_TLMM_JTMS_PINCFG 0x801a
+#define WCD9335_TLMM_JTCK_PINCFG 0x801b
+#define WCD9335_TLMM_JTRST_PINCFG 0x801c
+#define WCD9335_TEST_DEBUG_PIN_CTL_OE_0 0x8031
+#define WCD9335_TEST_DEBUG_PIN_CTL_OE_1 0x8032
+#define WCD9335_TEST_DEBUG_PIN_CTL_OE_2 0x8033
+#define WCD9335_TEST_DEBUG_PIN_CTL_OE_3 0x8034
+#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_0 0x8035
+#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_1 0x8036
+#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_2 0x8037
+#define WCD9335_TEST_DEBUG_PIN_CTL_DATA_3 0x8038
+#define WCD9335_TEST_DEBUG_PAD_DRVCTL 0x8039
+#define WCD9335_TEST_DEBUG_PIN_STATUS 0x803a
+#define WCD9335_TEST_DEBUG_NPL_DLY_TEST_1 0x803b
+#define WCD9335_TEST_DEBUG_NPL_DLY_TEST_2 0x803c
+#define WCD9335_TEST_DEBUG_MEM_CTRL 0x803d
+#define WCD9335_TEST_DEBUG_DEBUG_BUS_SEL 0x8041
+#define WCD9335_TEST_DEBUG_DEBUG_JTAG 0x8042
+#define WCD9335_TEST_DEBUG_DEBUG_EN_1 0x8043
+#define WCD9335_TEST_DEBUG_DEBUG_EN_2 0x8044
+#define WCD9335_TEST_DEBUG_DEBUG_EN_3 0x8045
+#define WCD9335_MAX_REGISTER 0x80FF
+
+/* SLIMBUS Slave Registers */
+#define WCD9335_SLIM_PGD_PORT_INT_EN0 (0x30)
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_0 (0x34)
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS_RX_1 (0x35)
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_0 (0x36)
+#define WCD9335_SLIM_PGD_PORT_INT_STATUS_TX_1 (0x37)
+#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_0 (0x38)
+#define WCD9335_SLIM_PGD_PORT_INT_CLR_RX_1 (0x39)
+#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_0 (0x3A)
+#define WCD9335_SLIM_PGD_PORT_INT_CLR_TX_1 (0x3B)
+#define WCD9335_SLIM_PGD_PORT_INT_RX_SOURCE0 (0x60)
+#define WCD9335_SLIM_PGD_PORT_INT_TX_SOURCE0 (0x70)
+
+/* Macros for Packing Register Writes into a U32 */
+#define WCD9335_PACKED_REG_SIZE sizeof(u32)
+
+#define WCD9335_CODEC_PACK_ENTRY(reg, mask, val) ((val & 0xff)|\
+ ((mask & 0xff) << 8)|((reg & 0xffff) << 16))
+#define WCD9335_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \
+ do { \
+ ((reg) = ((packed >> 16) & (0xffff))); \
+ ((mask) = ((packed >> 8) & (0xff))); \
+ ((val) = ((packed) & (0xff))); \
+ } while (0)
+#endif
diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index 561cd429e6f2..eb634dd299bf 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -10,6 +10,82 @@
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#define SLIM_MAX_TX_PORTS 16
+#define SLIM_MAX_RX_PORTS 16
+
+static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret != 0 && ret != -ENOTSUPP) {
+ pr_err("%s: failed to get codec chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ } else if (ret == -ENOTSUPP) {
+ return 0;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ rx_ch_cnt, rx_ch);
+ if (ret != 0 && ret != -ENOTSUPP) {
+ pr_err("%s: failed to set cpu chan map, err:%d\n",
+ __func__, ret);
+ goto end;
+ }
+ } else {
+ /* TX not supported yet in wcd */
+ }
+end:
+ return ret;
+}
+
+static struct snd_soc_dapm_route wcd9335_audio_paths[] = {
+ {"MIC BIAS1", NULL, "MCLK"},
+ {"MIC BIAS2", NULL, "MCLK"},
+ {"MIC BIAS3", NULL, "MCLK"},
+ {"MIC BIAS4", NULL, "MCLK"},
+};
+
+
+static struct snd_soc_ops msm8996_be_ops = {
+ .hw_params = msm_snd_hw_params,
+};
+
+static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /* Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[16] = {144, 145, 146, 147, 148, 149, 150,
+ 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[16] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+ snd_soc_dapm_add_routes(dapm, wcd9335_audio_paths,
+ ARRAY_SIZE(wcd9335_audio_paths));
+ 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);
+
+ return 0;
+}
+
static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -100,6 +176,8 @@ static int apq8096_sbc_parse_of(struct snd_soc_card *card)
link->no_pcm = 1;
link->ignore_pmdown_time = 1;
link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
+ link->init = msm_audrx_init;
+ link->ops = &msm8996_be_ops;
} else {
link->platform_of_node = link->cpu_of_node;
link->codec_dai_name = "snd-soc-dummy-dai";
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index 593f66b8622f..ff81418de682 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -310,7 +310,7 @@ int q6routing_stream_open(int fedai_id, int perf_mode,
session->channels, topology, perf_mode,
session->bits_per_sample, 0, 0);
- if (!copp) {
+ if (IS_ERR(copp) || !copp) {
mutex_unlock(&routing_data->lock);
return -EINVAL;
}
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 4663de3cf495..14ac9a37c803 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2522,6 +2522,32 @@ int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
}
EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
+
+/**
+ * snd_soc_dai_get_channel_map - configure DAI audio channel map
+ * @dai: DAI
+ * @tx_num: how many TX channels
+ * @tx_slot: pointer to an array which imply the TX slot number channel
+ * 0~num-1 uses
+ * @rx_num: how many RX channels
+ * @rx_slot: pointer to an array which imply the RX slot number channel
+ * 0~num-1 uses
+ *
+ * configure the relationship between channel number and TDM slot number.
+ */
+int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
+ unsigned int *tx_num, unsigned int *tx_slot,
+ unsigned int *rx_num, unsigned int *rx_slot)
+{
+ if (dai->driver->ops->get_channel_map)
+ return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
+ rx_num, rx_slot);
+ else
+ return -ENOTSUPP;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
+
+
/**
* snd_soc_dai_set_tristate - configure DAI system or master clock.
* @dai: DAI