diff options
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, ®_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 |