Merge "msm: socinfo: Add support for socinfo v8"
diff --git a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt b/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
deleted file mode 100644
index 01301be..0000000
--- a/Documentation/devicetree/bindings/arm/msm/debug-pc-cntr.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-* MSM PC Debug Counters
-
-MSM PC debug counter reserves 16 registers in the IMEM memory space which
-maintains a count on the state of power collapse on each core. This count
-will be useful to debug the power collapse state on each core.
-
-The required nodes for MSM PC Debug Counters are:
-
-- compatible: "qcom,pc-cntr"
-- reg: physical IMEM address reserved for PC counters
-
-Example:
-
-qcom,pc-cntr@fe800000 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe800664 0x40>;
- };
-
diff --git a/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
new file mode 100644
index 0000000..e62b9ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/mpm_counter.txt
@@ -0,0 +1,17 @@
+* MSM Timetick counter (mpm-v2)
+
+The MPM provides a timetick that starts when the device is powered up and
+is not reset by any of the boot loaders or the HLOS. The MPM timetick counter
+driver provides an api to get this value.
+
+The required nodes for the MPM timetick counter driver are:
+
+- compatible: "qcom,mpm-counter"
+- reg: Specifies the physical address of the timetick count register.
+
+Example:
+ qcom,mpm-counter@fc4a3000 {
+ compatible = "qcom,mpm-counter";
+ reg = <0xfc4a3000 0x1000>;
+ };
+
diff --git a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
index b429072..a372912 100644
--- a/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
+++ b/Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
@@ -5,6 +5,9 @@
the kernel to be notified of idle and suspend states and when called, follows
through the set of instructions in putting the application cores to the lowest
power mode possible.
+The PC debug counter reserves 16 registers in the IMEM memory space which maintains
+a count on the state of power collapse on each core. This count will be useful to
+debug the power collapse state on each core.
The required properties for PM-8x60 are:
@@ -12,17 +15,22 @@
The optional properties are:
+- reg: physical IMEM address reserved for PC counters and the size
- qcom,use-sync-timer: Indicates whether the target uses the synchronized QTimer.
- qcom,pc-mode: Indicates the type of power collapse used by the target. The
- valid values for this are:
+ valid values for this are:
0 (Power collapse terminates in TZ; integrated L2 cache controller)
1, (Power collapse doesn't terminate in TZ; external L2 cache controller)
2 (Power collapse terminates in TZ; external L2 cache controller)
+- qcom,saw-turns-off-pll: Version of SAW2.1 or can turn off the HFPLL, when
+ doing power collapse and so the core need to switch to Global PLL before
+ PC.
Example:
-qcom,pm-8x60 {
+qcom,pm-8x60@fe800664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe800664 0x40>;
qcom,pc-mode = <0>;
qcom,use-sync-timer;
};
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 939f77b..4b912f3 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -1,25 +1,51 @@
Qualcomm Serial Peripheral Interface (SPI)
Required properties:
-- compatible : should be "qcom,spi-qup-v2".
-- reg : offset and length of the QUP register map.
-- interrupts : should contain the QUP core interrupt.
-- spi-max-frequency : specifies maximum SPI clock frequency, Units - Hz.
+- compatible : Should be "qcom,spi-qup-v2".
+- reg : Offset and length of the register regions for the device
+- reg-names : Register region names referenced in reg above.
+ Required register resource entries are:
+ "spi_physical" : Physical address of controller register blocks.
+- interrupts : Interrupt numbers used by this controller
+- interrupt-names : Interrupt resource names referenced in interrupts above.
+ Required interrupt resource entries are:
+ "spi_irq" : QUP-core interrupt.
+- spi-max-frequency : Specifies maximum SPI clock frequency, Units - Hz.
+
+Required alias:
+- The desired bus-number is specified via an alias with the following format
+ 'spi{n}' where n is the bus number.
Optional properties:
-- gpios : specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
+- gpios : Specifies the gpio pins to be used for SPI CLK, MISO, MOSI in
that order.
-- cs-gpios : specifies the gpio pins to be used for chipselects.
+- cs-gpios : Specifies the gpio pins to be used for chipselects.
+- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When
+ value is non-zero, the value is the number of words in maximum transfer
+ length.
-SPI slave nodes must be children of the SPI master node and contain
+Optional properties which are required for support of BAM-mode:
+- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
+ version support latest features (e.g. BAM) and then enable them. Should be
+ removed for legacy HW.
+- qcom,use-bam : Boolean. When present, enables BAM-mode.
+- qcom,bam-consumer-pipe-index : BAM consumer-pipe index.
+- qcom,bam-producer-pipe-index : BAM producer-pipe index.
+- reg-names : register region names referenced in reg.
+ Required register resource for BAM are:
+ "spi_bam_physical" : Physical address of BAM for this controller.
+- interrupt-names : interrupt resource names referenced in interrupts.
+ Required interrupt resource from BAM are:
+ "spi_bam_irq" : BAM interrupt used by the controller.
+
+Optional SPI slave nodes must be children of the SPI master node and contain
the following properties.
-- reg : (required) chip select address of device.
-- compatible : (required) name of SPI device following generic names
- recommended practice
+- reg: (required) chip-select address of the device.
+- compatible : (required) Name of SPI device following generic names.
- spi-max-frequency : (required) Maximum SPI clocking speed of device in Hz
-- interrupts : (recommended) should contain the SPI slave interrupt number
+- interrupts : (recommended) Should contain the SPI slave interrupt number
encoded depending on the type of the interrupt controller.
-- interrupt-parent : (recommended) the phandle for the interrupt controller
+- interrupt-parent : (recommended) The phandle for the interrupt controller
that services interrupts for this device.
- spi-cpol : (optional) Empty property indicating device requires inverse
clock polarity (CPOL) mode
@@ -29,18 +55,30 @@
chip select active high
Example:
- spi@f9924000 {
- compatible = "qcom,spi-qup-v2";
- reg = <0xf9924000 0x1000>;
- interrupts = <0 96 0>;
- spi-max-frequency = <24000000>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- device@0 {
- compatible = "spidev";
- reg = <0>;
- spi-max-frequency = <5000000>;
- };
+ aliases {
+ spi0 = &spi_0;
};
+ spi_0: spi@f9923000 {
+ compatible = "qcom,spi-qup-v2";
+
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0xf9923000 0x1000>,
+ <0xf9904000 0x10000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 95 0>, <0 238 0>;
+
+ spi-max-frequency = <19200000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 9 0>;
+
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,bam-consumer-pipe-index = <12>;
+ qcom,bam-producer-pipe-index = <13>;
+ qcom,ver-reg-exists;
+ };
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index 0e06ac5..ce4513b 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -16,6 +16,113 @@
interrupt-controller;
#interrupt-cells = <3>;
+ qcom,pm8226@0 {
+ spmi-slave-container;
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ pm8226_gpios: gpios {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8226-gpio";
+
+ gpio@c000 {
+ reg = <0xc000 0x100>;
+ qcom,pin-num = <1>;
+ };
+
+ gpio@c100 {
+ reg = <0xc100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ gpio@c200 {
+ reg = <0xc200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ gpio@c300 {
+ reg = <0xc300 0x100>;
+ qcom,pin-num = <4>;
+ };
+
+ gpio@c400 {
+ reg = <0xc400 0x100>;
+ qcom,pin-num = <5>;
+ };
+
+ gpio@c500 {
+ reg = <0xc500 0x100>;
+ qcom,pin-num = <6>;
+ };
+
+ gpio@c600 {
+ reg = <0xc600 0x100>;
+ qcom,pin-num = <7>;
+ };
+
+ gpio@c700 {
+ reg = <0xc700 0x100>;
+ qcom,pin-num = <8>;
+ };
+ };
+
+ pm8226_mpps: mpps {
+ spmi-dev-container;
+ compatible = "qcom,qpnp-pin";
+ gpio-controller;
+ #gpio-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ label = "pm8226-mpp";
+
+ mpp@a000 {
+ reg = <0xa000 0x100>;
+ qcom,pin-num = <1>;
+ };
+
+ mpp@a100 {
+ reg = <0xa100 0x100>;
+ qcom,pin-num = <2>;
+ };
+
+ mpp@a200 {
+ reg = <0xa200 0x100>;
+ qcom,pin-num = <3>;
+ };
+
+ mpp@a300 {
+ reg = <0xa300 0x100>;
+ qcom,pin-num = <4>;
+ };
+
+ mpp@a400 {
+ reg = <0xa400 0x100>;
+ qcom,pin-num = <5>;
+ };
+
+ mpp@a500 {
+ reg = <0xa500 0x100>;
+ qcom,pin-num = <6>;
+ };
+
+ mpp@a600 {
+ reg = <0xa600 0x100>;
+ qcom,pin-num = <7>;
+ };
+
+ mpp@a700 {
+ reg = <0xa700 0x100>;
+ qcom,pin-num = <8>;
+ };
+ };
+ };
+
qcom,pm8226@1 {
spmi-slave-container;
reg = <0x1>;
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index f2269d5..50d2dba 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -10,275 +10,300 @@
* GNU General Public License for more details.
*/
- /* Stub Regulators */
+/* Stub Regulators */
- / {
- pm8026_s1: regulator-s1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s1";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
-
+/ {
pm8026_s1_corner: regulator-s1-corner {
compatible = "qcom,stub-regulator";
- regulator-name = "8026_s1_corner";
+ regulator-name = "8226_s1_corner";
qcom,hpm-min-load = <100000>;
regulator-min-microvolt = <1>;
regulator-max-microvolt = <7>;
qcom,consumer-supplies = "vdd_dig", "";
};
+};
- pm8026_s2: regulator-s2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s2";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1050000>;
- regulator-max-microvolt = <1050000>;
- };
+/* QPNP controlled regulators: */
- pm8026_s3: regulator-s3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s3";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- };
+&spmi_bus {
- pm8026_s4: regulator-s4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s4";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <2100000>;
- regulator-max-microvolt = <2100000>;
- };
+ qcom,pm8226@1 {
- pm8026_s5: regulator-s5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_s5";
- qcom,hpm-min-load = <100000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
+ pm8226_s1: regulator@1400 {
+ status = "okay";
+ regulator-name = "8226_s1";
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ regulator-min-microvolt = <1287500>;
+ regulator-max-microvolt = <1287500>;
+ };
- pm8026_l1: regulator-l1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l1";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- };
+ pm8226_s2: regulator@1700 {
+ status = "okay";
+ regulator-name = "8226_s2";
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
- pm8026_l2: regulator-l2 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l2";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8226_s3: regulator@1a00 {
+ status = "okay";
+ regulator-name = "8226_s3";
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
- pm8026_l3: regulator-l3 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l3";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1150000>;
- regulator-max-microvolt = <1150000>;
- };
+ pm8226_s4: regulator@1d00 {
+ status = "okay";
+ regulator-name = "8226_s4";
+ qcom,enable-time = <500>;
+ qcom,system-load = <100000>;
+ regulator-always-on;
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ };
- pm8026_l4: regulator-l4 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l4";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8226_s5: regulator@2000 {
+ status = "okay";
+ regulator-name = "8226_s5";
+ qcom,enable-time = <500>;
+ regulator-min-microvolt = <1150000>;
+ regulator-max-microvolt = <1150000>;
+ };
- pm8026_l5: regulator-l5 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l5";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- };
+ pm8226_l1: regulator@4000 {
+ status = "okay";
+ regulator-name = "8226_l1";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
- pm8026_l6: regulator-l6 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l6";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8226_l2: regulator@4100 {
+ status = "okay";
+ regulator-name = "8226_l2";
+ parent-supply = <&pm8226_s3>;
+ regulator-always-on;
+ qcom,enable-time = <200>;
+ qcom,system-load = <10000>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
- pm8026_l7: regulator-l7 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l7";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1850000>;
- regulator-max-microvolt = <1850000>;
- };
+ pm8226_l3: regulator@4200 {
+ status = "okay";
+ regulator-name = "8226_l3";
+ parent-supply = <&pm8226_s3>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1287500>;
+ regulator-max-microvolt = <1287500>;
+ };
- pm8026_l8: regulator-l8 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l8";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- qcom,consumer-supplies = "vdd_sr2_pll", "";
- };
+ pm8226_l4: regulator@4300 {
+ status = "okay";
+ regulator-name = "8226_l4";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
- pm8026_l9: regulator-l9 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l9";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- };
+ pm8226_l5: regulator@4400 {
+ status = "okay";
+ regulator-name = "8226_l5";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ };
- pm8026_l10: regulator-l10 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l10";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8226_l6: regulator@4500 {
+ status = "okay";
+ regulator-name = "8226_l6";
+ parent-supply = <&pm8226_s4>;
+ qcom,system-load = <10000>;
+ regulator-always-on;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- pm8026_l12: regulator-l12 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l12";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
+ pm8226_l7: regulator@4600 {
+ status = "okay";
+ regulator-name = "8226_l7";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1850000>;
+ regulator-max-microvolt = <1850000>;
+ };
- pm8026_l14: regulator-l14 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l14";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <2750000>;
- regulator-max-microvolt = <2750000>;
- };
+ pm8226_l8: regulator@4700 {
+ status = "okay";
+ regulator-name = "8226_l8";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,consumer-supplies = "vdd_sr2_pll", "";
+ };
- pm8026_l15: regulator-l15 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l15";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
+ pm8226_l9: regulator@4800 {
+ status = "okay";
+ regulator-name = "8226_l9";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
- pm8026_l16: regulator-l16 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l16";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
+ pm8226_l10: regulator@4900 {
+ status = "okay";
+ regulator-name = "8226_l10";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ qcom,system-load = <5000>;
+ regulator-always-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- pm8026_l17: regulator-l17 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l17";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l12: regulator@4b00 {
+ status = "okay";
+ regulator-name = "8226_l12";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- pm8026_l18: regulator-l18 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l18";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2950000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l14: regulator@4d00 {
+ status = "okay";
+ regulator-name = "8226_l14";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2750000>;
+ regulator-max-microvolt = <2750000>;
+ };
- pm8026_l19: regulator-l19 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l19";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- };
+ pm8226_l15: regulator@4e00 {
+ status = "okay";
+ regulator-name = "8226_l15";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
- pm8026_l20: regulator-l20 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l20";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <3075000>;
- regulator-max-microvolt = <3075000>;
- };
+ pm8226_l16: regulator@4f00 {
+ status = "okay";
+ regulator-name = "8226_l16";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ };
- pm8026_l21: regulator-l21 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l21";
- qcom,hpm-min-load = <5000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l17: regulator@5000 {
+ status = "okay";
+ regulator-name = "8226_l17";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_l22: regulator-l22 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l22";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l18: regulator@5100 {
+ status = "okay";
+ regulator-name = "8226_l18";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2950000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_l23: regulator-l23 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l23";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l19: regulator@5200 {
+ status = "okay";
+ regulator-name = "8226_l19";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ };
- pm8026_l24: regulator-l24 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l24";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1300000>;
- regulator-max-microvolt = <1300000>;
- };
+ pm8226_l20: regulator@5300 {
+ status = "okay";
+ regulator-name = "8226_l20";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <3075000>;
+ regulator-max-microvolt = <3075000>;
+ };
- pm8026_l26: regulator-l26 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l26";
- parent-supply = <&pm8026_s3>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1225000>;
- regulator-max-microvolt = <1225000>;
- };
+ pm8226_l21: regulator@5400 {
+ status = "okay";
+ regulator-name = "8226_l21";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_l27: regulator-l27 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l27";
- parent-supply = <&pm8026_s4>;
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <2050000>;
- regulator-max-microvolt = <2050000>;
- };
+ pm8226_l22: regulator@5500 {
+ status = "okay";
+ regulator-name = "8226_l22";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_l28: regulator-l28 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_l28";
- qcom,hpm-min-load = <10000>;
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <2950000>;
- };
+ pm8226_l23: regulator@5600 {
+ status = "okay";
+ regulator-name = "8226_l23";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
- pm8026_lvs1: regulator-lvs1 {
- compatible = "qcom,stub-regulator";
- regulator-name = "8026_lvs1";
- parent-supply = <&pm8026_l6>;
+ pm8226_l24: regulator@5700 {
+ status = "okay";
+ regulator-name = "8226_l24";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ };
+
+ pm8226_l26: regulator@5900 {
+ status = "okay";
+ regulator-name = "8226_l26";
+ parent-supply = <&pm8226_s3>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1225000>;
+ regulator-max-microvolt = <1225000>;
+ };
+
+ pm8226_l27: regulator@5a00 {
+ status = "okay";
+ regulator-name = "8226_l27";
+ parent-supply = <&pm8226_s4>;
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <2050000>;
+ regulator-max-microvolt = <2050000>;
+ };
+
+ pm8226_l28: regulator@5b00 {
+ status = "okay";
+ regulator-name = "8226_l28";
+ qcom,enable-time = <200>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <2950000>;
+ };
+
+ pm8226_lvs1: regulator@8000 {
+ status = "okay";
+ regulator-name = "8226_lvs1";
+ parent-supply = <&pm8226_l6>;
+ qcom,enable-time = <200>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-sim.dts b/arch/arm/boot/dts/msm8226-sim.dts
index 9a0ec17..f9ab957 100644
--- a/arch/arm/boot/dts/msm8226-sim.dts
+++ b/arch/arm/boot/dts/msm8226-sim.dts
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -39,8 +39,8 @@
qcom,pad-drv-on = <0x7 0x4 0x4>; /* 16mA, 10mA, 10mA */
qcom,pad-drv-off = <0x0 0x0 0x0>; /* 2mA, 2mA, 2mA */
- vdd-supply = <&pm8026_l17>;
- vdd-io-supply = <&pm8026_l6>;
+ vdd-supply = <&pm8226_l17>;
+ vdd-io-supply = <&pm8226_l6>;
qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
qcom,sup-voltages = <2950 2950>;
@@ -50,8 +50,8 @@
};
&sdcc2 {
- vdd-supply = <&pm8026_l18>;
- vdd-io-supply = <&pm8026_l21>;
+ vdd-supply = <&pm8226_l18>;
+ vdd-io-supply = <&pm8226_l21>;
qcom,vdd-voltage-level = <2950000 2950000>;
qcom,vdd-current-level = <9000 800000>;
@@ -74,3 +74,57 @@
status = "ok";
};
+
+&pm8226_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+
+ gpio@c600 { /* GPIO 7 */
+ };
+
+ gpio@c700 { /* GPIO 8 */
+ };
+};
+
+&pm8226_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+
+ mpp@a600 { /* MPP 7 */
+ };
+
+ mpp@a700 { /* MPP 8 */
+ };
+};
+
+
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index 5227004..3ae69fd 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -81,9 +81,9 @@
reg = <0xf9a55000 0x400>;
interrupts = <0 134 0>, <0 140 0>;
interrupt-names = "core_irq", "async_irq";
- HSUSB_VDDCX-supply = <&pm8026_s1>;
- HSUSB_1p8-supply = <&pm8026_l10>;
- HSUSB_3p3-supply = <&pm8026_l20>;
+ HSUSB_VDDCX-supply = <&pm8226_s1>;
+ HSUSB_1p8-supply = <&pm8226_l10>;
+ HSUSB_3p3-supply = <&pm8226_l20>;
qcom,hsusb-otg-phy-type = <2>;
qcom,hsusb-otg-mode = <1>;
@@ -123,23 +123,23 @@
17 18 19 20 21 22 23 24 25 26 27 28>;
qcom,cdc-reset-gpio = <&msmgpio 72 0>;
- cdc-vdd-buck-supply = <&pm8026_s4>;
+ cdc-vdd-buck-supply = <&pm8226_s4>;
qcom,cdc-vdd-buck-voltage = <2100000 2100000>;
qcom,cdc-vdd-buck-current = <650000>;
- cdc-vdd-h-supply = <&pm8026_l6>;
+ cdc-vdd-h-supply = <&pm8226_l6>;
qcom,cdc-vdd-h-voltage = <1800000 1800000>;
qcom,cdc-vdd-h-current = <25000>;
- cdc-vdd-px-supply = <&pm8026_l6>;
+ cdc-vdd-px-supply = <&pm8226_l6>;
qcom,cdc-vdd-px-voltage = <1800000 1800000>;
qcom,cdc-vdd-px-current = <25000>;
- cdc-vdd-a-1p2v-supply = <&pm8026_l4>;
+ cdc-vdd-a-1p2v-supply = <&pm8226_l4>;
qcom,cdc-vdd-a-1p2v-voltage = <1200000 1200000>;
qcom,cdc-vdd-a-1p2v-current = <10000>;
- cdc-vdd-cx-supply = <&pm8026_l4>;
+ cdc-vdd-cx-supply = <&pm8226_l4>;
qcom,cdc-vdd-cx-voltage = <1200000 1200000>;
qcom,cdc-vdd-cx-current = <10000>;
@@ -466,8 +466,8 @@
compatible = "qcom,acpuclk-a7";
reg = <0xf9011050 0x8>;
reg-names = "rcg_base";
- a7_cpu-supply = <&pm8026_s2>;
- a7_mem-supply = <&pm8026_l3>;
+ a7_cpu-supply = <&pm8226_s2>;
+ a7_mem-supply = <&pm8226_l3>;
};
qcom,ocmem@fdd00000 {
@@ -510,7 +510,7 @@
<0xfd485300 0xc>;
reg-names = "pmu_base", "clk_base", "halt_base";
interrupts = <0 149 1>;
- vdd_pronto_pll-supply = <&pm8026_l8>;
+ vdd_pronto_pll-supply = <&pm8226_l8>;
qcom,firmware-name = "wcnss";
};
@@ -566,5 +566,5 @@
status = "ok";
};
-/include/ "msm8226-regulator.dtsi"
/include/ "msm-pm8226.dtsi"
+/include/ "msm8226-regulator.dtsi"
diff --git a/arch/arm/boot/dts/msm8974-cdp.dtsi b/arch/arm/boot/dts/msm8974-cdp.dtsi
index 12804fb..16883ef 100644
--- a/arch/arm/boot/dts/msm8974-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8974-cdp.dtsi
@@ -534,3 +534,11 @@
mpp@a300 { /* MPP 4 */
};
};
+
+&slim_msm {
+ taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-fluid.dtsi b/arch/arm/boot/dts/msm8974-fluid.dtsi
index 7cc10e2..11c835f 100644
--- a/arch/arm/boot/dts/msm8974-fluid.dtsi
+++ b/arch/arm/boot/dts/msm8974-fluid.dtsi
@@ -207,7 +207,10 @@
&slim_msm {
taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
};
};
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index 76b23a1..e97678a 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -585,6 +585,7 @@
&slim_msm {
taiko_codec {
qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias3-ext-cap;
};
};
diff --git a/arch/arm/boot/dts/msm8974-mtp.dtsi b/arch/arm/boot/dts/msm8974-mtp.dtsi
index ea57389..e21610b 100644
--- a/arch/arm/boot/dts/msm8974-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974-mtp.dtsi
@@ -512,7 +512,9 @@
&slim_msm {
taiko_codec {
+ qcom,cdc-micbias1-ext-cap;
qcom,cdc-micbias2-ext-cap;
+ qcom,cdc-micbias4-ext-cap;
};
};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index f9b9e33..2de5fad 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -419,13 +419,9 @@
<40 95>;
};
- qcom,pc-cntr@fe805664 {
- compatible = "qcom,pc-cntr";
- reg = <0xfe805664 0x40>;
- };
-
- qcom,pm-8x60 {
+ qcom,pm-8x60@fe805664 {
compatible = "qcom,pm-8x60";
+ reg = <0xfe805664 0x40>;
qcom,pc-mode = <0>; /*MSM_PC_TZ_L2_INT */
qcom,use-sync-timer;
};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 3be174f..e6376d4 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -25,6 +25,11 @@
compatible = "qcom,msm8974";
interrupt-parent = <&intc>;
+ aliases {
+ spi0 = &spi_0;
+ spi7 = &spi_7;
+ };
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -60,6 +65,11 @@
clock-frequency = <19200000>;
};
+ qcom,mpm-counter@fc4a3000 {
+ compatible = "qcom,mpm-counter";
+ reg = <0xfc4a3000 0x1000>;
+ };
+
qcom,vidc@fdc00000 {
compatible = "qcom,msm-vidc";
reg = <0xfdc00000 0xff000>;
@@ -376,9 +386,8 @@
qcom,bam-dma-res-pipes = <6>;
};
- spi_epm: spi@f9966000 {
+ spi_7: spi_epm: spi@f9966000 {
compatible = "qcom,spi-qup-v2";
- cell-index = <7>;
reg = <0xf9966000 0x1000>;
interrupts = <0 104 0>;
spi-max-frequency = <19200000>;
@@ -567,8 +576,7 @@
qcom,i2c-src-freq = <19200000>;
};
- spi@f9923000 {
- cell-index = <0>;
+ spi_0: spi@f9923000 {
compatible = "qcom,spi-qup-v2";
reg = <0xf9923000 0x1000>;
interrupts = <0 95 0>;
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 793d27b..a735609 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -189,8 +189,38 @@
qcom,gic-parent = <&intc>;
qcom,gic-map = <47 172>, /* usb2_hsic_async_wakeup_irq */
- <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
- <0xff 208>; /* summary_irq_kpss */
+ <41 180>, /* usb_async_wakeup_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 57>, /* mss_to_apps_irq(0) */
+ <0xff 58>, /* mss_to_apps_irq(1) */
+ <0xff 59>, /* mss_to_apps_irq(2) */
+ <0xff 60>, /* mss_to_apps_irq(3) */
+ <0xff 173>, /* o_wcss_apss_smd_hi */
+ <0xff 174>, /* o_wcss_apss_smd_med */
+ <0xff 175>, /* o_wcss_apss_smd_lo */
+ <0xff 176>, /* o_wcss_apss_smsm_irq */
+ <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */
+ <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */
+ <0xff 179>, /* o_wcss_apss_asic_intr */
+ <0xff 188>, /* q6ss_irq_out(4) */
+ <0xff 189>, /* q6ss_irq_out(5) */
+ <0xff 190>, /* q6ss_irq_out(6) */
+ <0xff 191>, /* q6ss_irq_out(7) */
+ <0xff 192>, /* audio_out0_irq */
+ <0xff 193>, /* midi_arm_irq */
+ <0xff 194>, /* q6ss_wdog_exp_irq */
+ <0xff 195>, /* slimbus_core_ee1_irq */
+ <0xff 196>, /* bam_irq(1) */
+ <0xff 197>, /* qdss_irq_out(7) */
+ <0xff 200>, /* rpm_ipc(4) */
+ <0xff 201>, /* rpm_ipc(5) */
+ <0xff 202>, /* rpm_ipc(6) */
+ <0xff 203>, /* rpm_ipc(7) */
+ <0xff 204>, /* rpm_ipc(24) */
+ <0xff 205>, /* rpm_ipc(25) */
+ <0xff 206>, /* rpm_ipc(26) */
+ <0xff 207>, /* rpm_ipc(27) */
+ <0xff 240>; /* summary_irq_kpss */
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <4 1>,
diff --git a/arch/arm/boot/dts/msm9625-v2-1-cdp.dts b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
new file mode 100644
index 0000000..8702184
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-cdp.dts
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+ model = "Qualcomm MSM 9625V2.1 CDP";
+ compatible = "qcom,msm9625-cdp", "qcom,msm9625";
+ qcom,msm-id = <134 1 0x20001>, <152 1 0x20001>, <149 1 0x20001>,
+ <150 1 0x20001>, <151 1 0x20001>, <148 1 0x20001>,
+ <173 1 0x20001>, <174 1 0x20001>, <175 1 0x20001>;
+
+ i2c@f9925000 {
+ charger@57 {
+ compatible = "summit,smb137c";
+ reg = <0x57>;
+ summit,chg-current-ma = <1500>;
+ summit,term-current-ma = <50>;
+ summit,pre-chg-current-ma = <100>;
+ summit,float-voltage-mv = <4200>;
+ summit,thresh-voltage-mv = <3000>;
+ summit,recharge-thresh-mv = <75>;
+ summit,system-voltage-mv = <4250>;
+ summit,charging-timeout = <382>;
+ summit,pre-charge-timeout = <48>;
+ summit,therm-current-ua = <10>;
+ summit,temperature-min = <4>; /* 0 C */
+ summit,temperature-max = <3>; /* 45 C */
+ };
+ };
+
+ wlan0: qca,wlan {
+ cell-index = <0>;
+ compatible = "qca,ar6004-sdio";
+ qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+ qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+ qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+ };
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ /* ext_2p95v regulator enable config */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,invert = <0>; /* Output low */
+ qcom,out-strength = <1>; /* Low */
+ qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+};
+
+&pm8019_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1-mtp.dts b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
new file mode 100644
index 0000000..2dc040c
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1-mtp.dts
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "msm9625-v2-1.dtsi"
+
+/ {
+ model = "Qualcomm MSM 9625V2.1 MTP";
+ compatible = "qcom,msm9625-mtp", "qcom,msm9625";
+ qcom,msm-id = <134 7 0x20001>, <152 7 0x20001>, <149 7 0x20001>,
+ <150 7 0x20001>, <151 7 0x20001>, <148 7 0x20001>,
+ <173 7 0x20001>, <174 7 0x20001>, <175 7 0x20001>;
+
+ i2c@f9925000 {
+ charger@57 {
+ compatible = "summit,smb137c";
+ reg = <0x57>;
+ summit,chg-current-ma = <1500>;
+ summit,term-current-ma = <50>;
+ summit,pre-chg-current-ma = <100>;
+ summit,float-voltage-mv = <4200>;
+ summit,thresh-voltage-mv = <3000>;
+ summit,recharge-thresh-mv = <75>;
+ summit,system-voltage-mv = <4250>;
+ summit,charging-timeout = <382>;
+ summit,pre-charge-timeout = <48>;
+ summit,therm-current-ua = <10>;
+ summit,temperature-min = <4>; /* 0 C */
+ summit,temperature-max = <3>; /* 45 C */
+ };
+ };
+
+ wlan0: qca,wlan {
+ cell-index = <0>;
+ compatible = "qca,ar6004-sdio";
+ qca,chip-pwd-l-gpios = <&msmgpio 62 0>;
+ qca,pm-enable-gpios = <&pm8019_gpios 3 0x0>;
+ qca,ar6004-vdd-io-supply = <&pm8019_l11>;
+ };
+};
+
+/* PM8019 GPIO and MPP configuration */
+&pm8019_gpios {
+ gpio@c000 { /* GPIO 1 */
+ };
+
+ gpio@c100 { /* GPIO 2 */
+ };
+
+ gpio@c200 { /* GPIO 3 */
+ };
+
+ gpio@c300 { /* GPIO 4 */
+ /* ext_2p95v regulator enable config */
+ qcom,mode = <1>; /* Digital output */
+ qcom,output-type = <0>; /* CMOS */
+ qcom,invert = <0>; /* Output low */
+ qcom,out-strength = <1>; /* Low */
+ qcom,vin-sel = <2>; /* PM8019 L11 - 1.8V */
+ qcom,src-sel = <0>; /* Constant */
+ qcom,master-en = <1>; /* Enable GPIO */
+ };
+
+ gpio@c400 { /* GPIO 5 */
+ };
+
+ gpio@c500 { /* GPIO 6 */
+ };
+};
+
+&pm8019_mpps {
+ mpp@a000 { /* MPP 1 */
+ };
+
+ mpp@a100 { /* MPP 2 */
+ };
+
+ mpp@a200 { /* MPP 3 */
+ };
+
+ mpp@a300 { /* MPP 4 */
+ };
+
+ mpp@a400 { /* MPP 5 */
+ };
+
+ mpp@a500 { /* MPP 6 */
+ };
+};
diff --git a/arch/arm/boot/dts/msm9625-v2-1.dtsi b/arch/arm/boot/dts/msm9625-v2-1.dtsi
new file mode 100644
index 0000000..c3c2c49
--- /dev/null
+++ b/arch/arm/boot/dts/msm9625-v2-1.dtsi
@@ -0,0 +1,36 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * 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.
+ */
+
+/*
+ * As a general rule, only version-specific property overrides should be placed
+ * inside this file. However, device definitions should be placed inside the
+ * msm9625.dtsi file.
+ */
+
+/include/ "msm9625.dtsi"
+
+/ {
+ qcom,msm-imem@fe807800 {
+ compatible = "qcom,msm-imem";
+ reg = <0xfe807800 0x1000>; /* Address and size of IMEM */
+ };
+
+ android_usb@fe8078c8 {
+ compatible = "qcom,android-usb";
+ reg = <0xfe8078c8 0xc8>;
+ qcom,android-usb-swfi-latency = <100>;
+ };
+};
+
+&ipa_hw {
+ qcom,ipa-hw-ver = <2>; /* IPA h-w revision */
+};
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index d5a33ee..922616c 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -21,6 +21,10 @@
compatible = "qcom,msm9625";
interrupt-parent = <&intc>;
+ aliases {
+ spi0 = &spi_0;
+ };
+
intc: interrupt-controller@F9000000 {
compatible = "qcom,msm-qgic2";
interrupt-controller;
@@ -186,8 +190,7 @@
interrupt-names = "bam_irq";
};
- spi@f9924000 {
- cell-index = <0>;
+ spi_0: spi@f9924000 {
compatible = "qcom,spi-qup-v2";
reg = <0xf9924000 0x1000>;
interrupts = <0 96 0>;
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 1623d45..2bf4630 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -139,6 +139,7 @@
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
CONFIG_WCD9306_CODEC=y
+CONFIG_GPIO_QPNP_PIN=y
# CONFIG_HWMON is not set
CONFIG_REGULATOR=y
CONFIG_REGULATOR_STUB=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index ecea32b..cb5e712 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -411,3 +411,5 @@
obj-$(CONFIG_MSM_SMCMOD) += smcmod.o
obj-$(CONFIG_MSM_CPU_PWRCTL) += msm_cpu_pwrctl.o
+
+obj-$(CONFIG_ARCH_MSM8974) += msm_mpmctr.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index b451d08..202b8dd 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -68,6 +68,8 @@
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v1-rumi.dtb
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-cdp.dtb
dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM9625) += msm9625-v2-1-cdp.dtb
# MSM8226
zreladdr-$(CONFIG_ARCH_MSM8226) := 0x00008000
diff --git a/arch/arm/mach-msm/bms-batterydata-desay.c b/arch/arm/mach-msm/bms-batterydata-desay.c
index 5b72a3f..dd3f346 100644
--- a/arch/arm/mach-msm/bms-batterydata-desay.c
+++ b/arch/arm/mach-msm/bms-batterydata-desay.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -83,4 +83,5 @@
.pc_temp_ocv_lut = &desay_5200_pc_temp_ocv,
.pc_sf_lut = &desay_5200_pc_sf,
.default_rbatt_mohm = 156,
+ .rbatt_capacitive_mohm = 50,
};
diff --git a/arch/arm/mach-msm/bms-batterydata.c b/arch/arm/mach-msm/bms-batterydata.c
index 824cf6b..0c39df6 100644
--- a/arch/arm/mach-msm/bms-batterydata.c
+++ b/arch/arm/mach-msm/bms-batterydata.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -105,4 +105,5 @@
.pc_temp_ocv_lut = &pc_temp_ocv,
.rbatt_sf_lut = &rbatt_sf,
.default_rbatt_mohm = 236,
+ .rbatt_capacitive_mohm = 50,
};
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index a89ea61..beb064b 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2723,7 +2723,6 @@
&apq8064_device_uart_gsbi1,
&apq8064_device_uart_gsbi4,
&msm_device_sps_apq8064,
- &msm8064_pc_cntr,
};
static struct platform_device *common_i2s_devices[] __initdata = {
@@ -2888,7 +2887,6 @@
#ifdef CONFIG_MSM_ROTATOR
&msm_rotator_device,
#endif
- &msm8064_pc_cntr,
};
static struct platform_device
@@ -3861,11 +3859,13 @@
if (cpu_is_apq8064ab())
apq8064ab_update_krait_spm();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8064_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
apq8064ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+ platform_device_register(&msm8064_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index a8e117f..25ba1aa 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2473,7 +2473,6 @@
&msm8930_iommu_domain_device,
&msm_tsens_device,
&msm8930_cache_dump_device,
- &msm8930_pc_cntr,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -2955,11 +2954,14 @@
msm8930_i2c_init();
msm8930_init_gpu();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8930_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
msm8930ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+
+ platform_device_register(&msm8930_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
msm8930_init_buses();
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 6524832..95f618a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2955,7 +2955,6 @@
&msm8960_cache_dump_device,
&msm8960_iommu_domain_device,
&msm_tsens_device,
- &msm8960_pc_cntr,
};
static struct platform_device *cdp_devices[] __initdata = {
@@ -3488,11 +3487,13 @@
if (cpu_is_msm8960ab())
msm8960ab_update_krait_spm();
if (cpu_is_krait_v3()) {
- msm_pm_set_tz_retention_flag(0);
+ struct msm_pm_init_data_type *pdata =
+ msm8960_pm_8x60.dev.platform_data;
+ pdata->retention_calls_tz = false;
msm8960ab_update_retention_spm();
- } else {
- msm_pm_set_tz_retention_flag(1);
}
+ platform_device_register(&msm8960_pm_8x60);
+
msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
msm_spm_l2_init(msm_spm_l2_data);
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index eb99073..b3cc9b7 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -258,12 +258,6 @@
.dir = GPIOMUX_OUT_HIGH,
};
-static struct gpiomux_setting mhl_active_2_cfg = {
- .func = GPIOMUX_FUNC_1,
- .drv = GPIOMUX_DRV_2MA,
- .pull = GPIOMUX_PULL_UP,
-};
-
static struct gpiomux_setting hdmi_suspend_cfg = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -299,14 +293,6 @@
[GPIOMUX_ACTIVE] = &mhl_active_1_cfg,
},
},
- {
- /* mhl-sii8334 reset */
- .gpio = 8,
- .settings = {
- [GPIOMUX_SUSPENDED] = &mhl_suspend_config,
- [GPIOMUX_ACTIVE] = &mhl_active_2_cfg,
- },
- },
};
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index c45cf11..02a753a 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -5299,6 +5299,7 @@
&msm_device_tz_log,
&msm_rtb_device,
&msm8660_iommu_domain_device,
+ &msm8660_pm_8x60,
};
#ifdef CONFIG_ION_MSM
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index c3e1e3e..d26b4b2 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -526,7 +526,6 @@
#define mm_gnd_source_val 6
#define gpll1_hsic_source_val 4
#define cxo_lpass_source_val 0
-#define lpapll0_lpass_source_val 1
#define gpll0_lpass_source_val 5
#define edppll_270_mm_source_val 4
#define edppll_350_mm_source_val 4
@@ -742,21 +741,6 @@
},
};
-static struct pll_vote_clk lpapll0_clk_src = {
- .en_reg = (void __iomem *)LPASS_LPA_PLL_VOTE_APPS_REG,
- .en_mask = BIT(0),
- .status_reg = (void __iomem *)LPAPLL_STATUS_REG,
- .status_mask = BIT(17),
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &cxo_clk_src.c,
- .rate = 491520000,
- .dbg_name = "lpapll0_clk_src",
- .ops = &clk_ops_pll_vote,
- CLK_INIT(lpapll0_clk_src.c),
- },
-};
-
static struct pll_vote_clk mmpll0_clk_src = {
.en_reg = (void __iomem *)MMSS_PLL_VOTE_APCS_REG,
.en_mask = BIT(0),
@@ -4350,411 +4334,6 @@
},
};
-static struct clk_freq_tbl ftbl_audio_core_slimbus_core_clock[] = {
- F_LPASS(24576000, lpapll0, 4, 1, 5),
- F_END
-};
-
-static struct rcg_clk audio_core_slimbus_core_clk_src = {
- .cmd_rcgr_reg = SLIMBUS_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_slimbus_core_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_slimbus_core_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 70000000, NOMINAL, 140000000),
- CLK_INIT(audio_core_slimbus_core_clk_src.c),
- },
-};
-
-static struct branch_clk audio_core_slimbus_core_clk = {
- .cbcr_reg = AUDIO_CORE_SLIMBUS_CORE_CBCR,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_slimbus_core_clk_src.c,
- .dbg_name = "audio_core_slimbus_core_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_slimbus_core_clk.c),
- },
-};
-
-static struct branch_clk audio_core_slimbus_lfabif_clk = {
- .cbcr_reg = AUDIO_CORE_SLIMBUS_LFABIF_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_slimbus_lfabif_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_slimbus_lfabif_clk.c),
- },
-};
-
-static struct clk_freq_tbl ftbl_audio_core_lpaif_clock[] = {
- F_LPASS( 512000, lpapll0, 16, 1, 60),
- F_LPASS( 768000, lpapll0, 16, 1, 40),
- F_LPASS( 1024000, lpapll0, 16, 1, 30),
- F_LPASS( 1536000, lpapll0, 16, 1, 20),
- F_LPASS( 2048000, lpapll0, 16, 1, 15),
- F_LPASS( 3072000, lpapll0, 16, 1, 10),
- F_LPASS( 4096000, lpapll0, 15, 1, 8),
- F_LPASS( 6144000, lpapll0, 10, 1, 8),
- F_LPASS( 8192000, lpapll0, 15, 1, 4),
- F_LPASS(12288000, lpapll0, 10, 1, 4),
- F_END
-};
-
-static struct rcg_clk audio_core_lpaif_codec_spkr_clk_src = {
- .cmd_rcgr_reg = LPAIF_SPKR_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_codec_spkr_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_pri_clk_src = {
- .cmd_rcgr_reg = LPAIF_PRI_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pri_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_pri_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_sec_clk_src = {
- .cmd_rcgr_reg = LPAIF_SEC_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_sec_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_sec_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_ter_clk_src = {
- .cmd_rcgr_reg = LPAIF_TER_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_ter_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_ter_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_quad_clk_src = {
- .cmd_rcgr_reg = LPAIF_QUAD_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_quad_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_quad_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_pcm0_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCM0_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm0_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_pcm0_clk_src.c),
- },
-};
-
-static struct rcg_clk audio_core_lpaif_pcm1_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCM1_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm1_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP2(LOW, 12000000, NOMINAL, 25000000),
- CLK_INIT(audio_core_lpaif_pcm1_clk_src.c),
- },
-};
-
-struct rcg_clk audio_core_lpaif_pcmoe_clk_src = {
- .cmd_rcgr_reg = LPAIF_PCMOE_CMD_RCGR,
- .set_rate = set_rate_mnd,
- .freq_tbl = ftbl_audio_core_lpaif_clock,
- .current_freq = &rcg_dummy_freq,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcmoe_clk_src",
- .ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP1(LOW, 12290000),
- CLK_INIT(audio_core_lpaif_pcmoe_clk_src.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_codec_spkr_clk_src.c,
- .dbg_name = "audio_core_lpaif_codec_spkr_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_codec_spkr_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_codec_spkr_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_CODEC_SPKR_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_codec_spkr_clk_src.c,
- .dbg_name = "audio_core_lpaif_codec_spkr_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_codec_spkr_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pri_clk_src.c,
- .dbg_name = "audio_core_lpaif_pri_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pri_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pri_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PRI_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pri_clk_src.c,
- .dbg_name = "audio_core_lpaif_pri_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pri_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_sec_clk_src.c,
- .dbg_name = "audio_core_lpaif_sec_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_sec_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_sec_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_SEC_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_sec_clk_src.c,
- .dbg_name = "audio_core_lpaif_sec_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_sec_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_ter_clk_src.c,
- .dbg_name = "audio_core_lpaif_ter_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_ter_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_ter_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_TER_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_ter_clk_src.c,
- .dbg_name = "audio_core_lpaif_ter_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_ter_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_osr_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_OSR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_quad_clk_src.c,
- .dbg_name = "audio_core_lpaif_quad_osr_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_osr_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_quad_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_quad_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_QUAD_IBIT_CBCR,
- .has_sibling = 1,
- .max_div = 15,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_quad_clk_src.c,
- .dbg_name = "audio_core_lpaif_quad_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_quad_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_lpaif_pcm0_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm0_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm0_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM0_IBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pcm0_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm0_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm0_ibit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ebit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_EBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pcm1_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm1_ebit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm1_ebit_clk.c),
- },
-};
-
-static struct branch_clk audio_core_lpaif_pcm1_ibit_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM1_IBIT_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pcm1_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcm1_ibit_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcm1_ibit_clk.c),
- },
-};
-
-struct branch_clk audio_core_lpaif_pcmoe_clk = {
- .cbcr_reg = AUDIO_CORE_LPAIF_PCM_DATA_OE_CBCR,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .parent = &audio_core_lpaif_pcmoe_clk_src.c,
- .dbg_name = "audio_core_lpaif_pcmoe_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_lpaif_pcmoe_clk.c),
- },
-};
-
static struct branch_clk q6ss_ahb_lfabif_clk = {
.cbcr_reg = LPASS_Q6SS_AHB_LFABIF_CBCR,
.has_sibling = 1,
@@ -4766,16 +4345,6 @@
},
};
-static struct branch_clk audio_core_ixfabric_clk = {
- .cbcr_reg = AUDIO_CORE_IXFABRIC_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_core_ixfabric_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_core_ixfabric_clk.c),
- },
-};
static struct branch_clk gcc_lpass_q6_axi_clk = {
.cbcr_reg = LPASS_Q6_AXI_CBCR,
@@ -4811,17 +4380,6 @@
},
};
-static struct branch_clk audio_wrapper_br_clk = {
- .cbcr_reg = AUDIO_WRAPPER_BR_CBCR,
- .has_sibling = 1,
- .base = &virt_bases[LPASS_BASE],
- .c = {
- .dbg_name = "audio_wrapper_br_clk",
- .ops = &clk_ops_branch,
- CLK_INIT(audio_wrapper_br_clk.c),
- },
-};
-
static DEFINE_CLK_MEASURE(l2_m_clk);
static DEFINE_CLK_MEASURE(krait0_m_clk);
static DEFINE_CLK_MEASURE(krait1_m_clk);
@@ -5004,20 +4562,9 @@
{&mdss_hdmi_ahb_clk.c, MMSS_BASE, 0x0023},
{&mdss_pclk0_clk.c, MMSS_BASE, 0x0016},
{&mdss_pclk1_clk.c, MMSS_BASE, 0x0017},
- {&audio_core_lpaif_pri_clk_src.c, LPASS_BASE, 0x0017},
- {&audio_core_lpaif_sec_clk_src.c, LPASS_BASE, 0x0016},
- {&audio_core_lpaif_ter_clk_src.c, LPASS_BASE, 0x0015},
- {&audio_core_lpaif_quad_clk_src.c, LPASS_BASE, 0x0014},
- {&audio_core_lpaif_pcm0_clk_src.c, LPASS_BASE, 0x0013},
- {&audio_core_lpaif_pcm1_clk_src.c, LPASS_BASE, 0x0012},
- {&audio_core_lpaif_pcmoe_clk_src.c, LPASS_BASE, 0x000f},
- {&audio_core_slimbus_core_clk.c, LPASS_BASE, 0x003d},
- {&audio_core_slimbus_lfabif_clk.c, LPASS_BASE, 0x003e},
{&q6ss_xo_clk.c, LPASS_BASE, 0x002b},
{&q6ss_ahb_lfabif_clk.c, LPASS_BASE, 0x001e},
{&q6ss_ahbm_clk.c, LPASS_BASE, 0x001d},
- {&audio_core_ixfabric_clk.c, LPASS_BASE, 0x0059},
- {&audio_wrapper_br_clk.c, LPASS_BASE, 0x0022},
{&krait0_m_clk, APCS_BASE, M_ACPU0},
{&krait1_m_clk, APCS_BASE, M_ACPU1},
@@ -5639,57 +5186,6 @@
/* LPASS clocks */
- CLK_LOOKUP("bus_clk", audio_core_ixfabric_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_slimbus_core_clk.c, "fe12f000.slim"),
- CLK_LOOKUP("iface_clk", audio_core_slimbus_lfabif_clk.c,
- "fe12f000.slim"),
- CLK_LOOKUP("core_clk", audio_core_lpaif_codec_spkr_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_codec_spkr_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_codec_spkr_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_codec_spkr_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pri_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_pri_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pri_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pri_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_sec_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_sec_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_sec_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_sec_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_ter_clk_src.c, ""),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_ter_osr_clk.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_ter_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_ter_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_quad_clk_src.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("osr_clk", audio_core_lpaif_quad_osr_clk.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_quad_ebit_clk.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_quad_ibit_clk.c,
- "msm-dai-q6-mi2s.3"),
- CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm0_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c, ""),
- CLK_LOOKUP("core_clk", audio_core_lpaif_pcm1_clk_src.c, ""),
- CLK_LOOKUP("ebit_clk", audio_core_lpaif_pcm1_ebit_clk.c, ""),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm1_ibit_clk.c, ""),
- CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
- "msm-dai-q6.4106"),
- CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
- "msm-dai-q6.4107"),
- CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
-
CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("iface_clk", gcc_mss_cfg_ahb_clk.c, "fc880000.qcom,mss"),
CLK_LOOKUP("mem_clk", gcc_boot_rom_ahb_clk.c, "fc880000.qcom,mss"),
@@ -5880,32 +5376,6 @@
.main_output_mask = BIT(0),
};
-static struct pll_config_regs lpapll0_regs __initdata = {
- .l_reg = (void __iomem *)LPAPLL_L_REG,
- .m_reg = (void __iomem *)LPAPLL_M_REG,
- .n_reg = (void __iomem *)LPAPLL_N_REG,
- .config_reg = (void __iomem *)LPAPLL_USER_CTL_REG,
- .mode_reg = (void __iomem *)LPAPLL_MODE_REG,
- .base = &virt_bases[LPASS_BASE],
-};
-
-/* LPAPLL0 at 491.52 MHz, main output enabled. */
-static struct pll_config lpapll0_config __initdata = {
- .l = 0x33,
- .m = 0x1,
- .n = 0x5,
- .vco_val = 0x0,
- .vco_mask = BM(21, 20),
- .pre_div_val = BVAL(14, 12, 0x1),
- .pre_div_mask = BM(14, 12),
- .post_div_val = 0x0,
- .post_div_mask = BM(9, 8),
- .mn_ena_val = BIT(24),
- .mn_ena_mask = BIT(24),
- .main_output_val = BIT(0),
- .main_output_mask = BIT(0),
-};
-
#define PWR_ON_MASK BIT(31)
#define EN_REST_WAIT_MASK (0xF << 20)
#define EN_FEW_WAIT_MASK (0xF << 16)
@@ -5922,8 +5392,7 @@
static void __init reg_init(void)
{
- u32 regval, status;
- int ret;
+ u32 regval;
configure_sr_hpm_lp_pll(&mmpll0_config, &mmpll0_regs, 1);
@@ -5934,7 +5403,6 @@
configure_sr_hpm_lp_pll(&mmpll1_config, &mmpll1_regs, 1);
configure_sr_hpm_lp_pll(&mmpll3_config, &mmpll3_regs, 0);
}
- configure_sr_hpm_lp_pll(&lpapll0_config, &lpapll0_regs, 1);
/* Vote for GPLL0 to turn on. Needed by acpuclock. */
regval = readl_relaxed(GCC_REG_BASE(APCS_GPLL_ENA_VOTE_REG));
@@ -5957,31 +5425,6 @@
* register.
*/
writel_relaxed(0x0, GCC_REG_BASE(APCS_CLOCK_SLEEP_ENA_VOTE));
-
- /*
- * TODO: The following sequence enables the LPASS audio core GDSC.
- * Remove when this becomes unnecessary.
- */
-
- /*
- * Disable HW trigger: collapse/restore occur based on registers writes.
- * Disable SW override: Use hardware state-machine for sequencing.
- */
- regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
- regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);
-
- /* Configure wait time between states. */
- regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
- regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
- writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
- regval = readl_relaxed(LPASS_REG_BASE(AUDIO_CORE_GDSCR));
- regval &= ~BIT(0);
- writel_relaxed(regval, LPASS_REG_BASE(AUDIO_CORE_GDSCR));
-
- ret = readl_poll_timeout(LPASS_REG_BASE(AUDIO_CORE_GDSCR), status,
- status & PWR_ON_MASK, 50, GDSC_TIMEOUT_US);
- WARN(ret, "LPASS Audio Core GDSC did not power on.\n");
}
static void __init mdss_clock_setup(void)
@@ -6021,11 +5464,6 @@
*/
clk_prepare_enable(&cxo_a_clk_src.c);
- /* TODO: Temporarily enable a clock to allow access to LPASS core
- * registers.
- */
- clk_prepare_enable(&audio_core_ixfabric_clk.c);
-
/*
* TODO: Temporarily enable NOC configuration AHB clocks. Remove when
* the bus driver is ready.
@@ -6060,8 +5498,6 @@
clk_set_rate(&esc1_clk_src.c, esc1_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&hdmi_clk_src.c, hdmi_clk_src.freq_tbl[0].freq_hz);
clk_set_rate(&vsync_clk_src.c, vsync_clk_src.freq_tbl[0].freq_hz);
- clk_set_rate(&audio_core_slimbus_core_clk_src.c,
- audio_core_slimbus_core_clk_src.freq_tbl[0].freq_hz);
}
#define GCC_CC_PHYS 0xFC400000
diff --git a/arch/arm/mach-msm/clock-rpm.c b/arch/arm/mach-msm/clock-rpm.c
index c1cc27b..ee91a34 100644
--- a/arch/arm/mach-msm/clock-rpm.c
+++ b/arch/arm/mach-msm/clock-rpm.c
@@ -245,6 +245,14 @@
return rc;
}
+static int rpm_branch_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (rate == clk->rate)
+ return 0;
+
+ return -EPERM;
+}
+
static unsigned long rpm_clk_get_rate(struct clk *clk)
{
struct rpm_clk *r = to_rpm_clk(clk);
@@ -335,6 +343,7 @@
struct clk_ops clk_ops_rpm_branch = {
.prepare = rpm_clk_prepare,
.unprepare = rpm_clk_unprepare,
+ .set_rate = rpm_branch_clk_set_rate,
.is_local = rpm_clk_is_local,
.handoff = rpm_clk_handoff,
};
diff --git a/arch/arm/mach-msm/cpuidle.c b/arch/arm/mach-msm/cpuidle.c
index 77c91b8..e87c7b5 100644
--- a/arch/arm/mach-msm/cpuidle.c
+++ b/arch/arm/mach-msm/cpuidle.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -72,18 +72,19 @@
struct cpuidle_device *dev, struct cpuidle_driver *drv, int index)
{
int ret = 0;
- int i = 0;
+ int i;
enum msm_pm_sleep_mode pm_mode;
- struct cpuidle_state_usage *st_usage = NULL;
cpu_pm_enter();
- pm_mode = msm_pm_idle_prepare(dev, drv, index);
- dev->last_residency = msm_pm_idle_enter(pm_mode);
+ pm_mode = msm_pm_idle_enter(dev, drv, index);
+
for (i = 0; i < dev->state_count; i++) {
- st_usage = &dev->states_usage[i];
- if ((enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage)
- == pm_mode) {
+ struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
+ enum msm_pm_sleep_mode last_mode =
+ (enum msm_pm_sleep_mode)cpuidle_get_statedata(st_usage);
+
+ if (last_mode == pm_mode) {
ret = i;
break;
}
@@ -95,7 +96,7 @@
return ret;
}
-static void __init msm_cpuidle_set_states(void)
+static void __devinit msm_cpuidle_set_states(void)
{
int i = 0;
int state_count = 0;
@@ -151,7 +152,7 @@
dev->state_count = state_count; /* Per cpu state count */
}
-int __init msm_cpuidle_init(void)
+int __devinit msm_cpuidle_init(void)
{
unsigned int cpu = 0;
int ret = 0;
diff --git a/arch/arm/mach-msm/devices-8064.c b/arch/arm/mach-msm/devices-8064.c
index f87c540..10ee1e3 100644
--- a/arch/arm/mach-msm/devices-8064.c
+++ b/arch/arm/mach-msm/devices-8064.c
@@ -49,6 +49,7 @@
#include <mach/mpm.h>
#include <mach/iommu_domains.h>
#include <mach/msm_cache_dump.h>
+#include "pm.h"
/* Address of GSBI blocks */
#define MSM_GSBI1_PHYS 0x12440000
@@ -120,11 +121,24 @@
},
};
-struct platform_device msm8064_pc_cntr = {
- .name = "pc-cntr",
+static uint32_t msm_pm_cp15_regs[] = {0x4501, 0x5501, 0x6501, 0x7501, 0x0500};
+
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+ .cp15_data.save_cp15 = true,
+ .cp15_data.qsb_pc_vdd = 0x98,
+ .cp15_data.reg_data = &msm_pm_cp15_regs[0],
+ .cp15_data.reg_saved_state_size = ARRAY_SIZE(msm_pm_cp15_regs),
+};
+
+struct platform_device msm8064_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8064_resources_pccntr),
.resource = msm8064_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
static struct msm_watchdog_pdata msm_watchdog_pdata = {
diff --git a/arch/arm/mach-msm/devices-8930.c b/arch/arm/mach-msm/devices-8930.c
index aad512e..6fe8ccb 100644
--- a/arch/arm/mach-msm/devices-8930.c
+++ b/arch/arm/mach-msm/devices-8930.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,7 @@
#include "rpm_rbcpr_stats.h"
#include "footswitch.h"
#include "acpuclock-krait.h"
+#include "pm.h"
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -48,11 +49,18 @@
},
};
-struct platform_device msm8930_pc_cntr = {
- .name = "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+};
+
+struct platform_device msm8930_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8930_resources_pccntr),
.resource = msm8930_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
struct msm_rpm_platform_data msm8930_rpm_data __initdata = {
diff --git a/arch/arm/mach-msm/devices-8960.c b/arch/arm/mach-msm/devices-8960.c
index c3748fa..6a344be 100644
--- a/arch/arm/mach-msm/devices-8960.c
+++ b/arch/arm/mach-msm/devices-8960.c
@@ -53,6 +53,7 @@
#include <mach/msm_dcvs.h>
#include <mach/iommu_domains.h>
#include <mach/socinfo.h>
+#include "pm.h"
#ifdef CONFIG_MSM_MPM
#include <mach/mpm.h>
@@ -116,11 +117,18 @@
},
};
-struct platform_device msm8960_pc_cntr = {
- .name = "pc-cntr",
+static struct msm_pm_init_data_type msm_pm_data = {
+ .retention_calls_tz = true,
+};
+
+struct platform_device msm8960_pm_8x60 = {
+ .name = "pm-8x60",
.id = -1,
.num_resources = ARRAY_SIZE(msm8960_resources_pccntr),
.resource = msm8960_resources_pccntr,
+ .dev = {
+ .platform_data = &msm_pm_data,
+ },
};
static struct resource resources_otg[] = {
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index 58416c7..cfa9281 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -3181,3 +3181,9 @@
.platform_data = &msm8660_iommu_domain_pdata,
}
};
+
+struct platform_device msm8660_pm_8x60 = {
+ .name = "pm-8x60",
+ .id = -1,
+};
+
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index d3810a2..53eca3e 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -1,7 +1,7 @@
/* linux/arch/arm/mach-msm/devices.h
*
* Copyright (C) 2008 Google, Inc.
- * Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -113,11 +113,11 @@
extern struct platform_device msm_device_sdc3;
extern struct platform_device msm_device_sdc4;
+extern struct platform_device msm8960_pm_8x60;
+extern struct platform_device msm8064_pm_8x60;
+extern struct platform_device msm8930_pm_8x60;
extern struct platform_device msm9615_pm_8x60;
-
-extern struct platform_device msm8960_pc_cntr;
-extern struct platform_device msm8064_pc_cntr;
-extern struct platform_device msm8930_pc_cntr;
+extern struct platform_device msm8660_pm_8x60;
extern struct platform_device msm_device_gadget_peripheral;
extern struct platform_device msm_device_hsusb_host;
diff --git a/arch/arm/mach-msm/include/mach/msm_mpmctr.h b/arch/arm/mach-msm/include/mach/msm_mpmctr.h
new file mode 100644
index 0000000..d3d853f
--- /dev/null
+++ b/arch/arm/mach-msm/include/mach/msm_mpmctr.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MSM_MPMCTR_H__
+#define __MSM_MPMCTR_H__
+
+/*
+ * returns the count value of the mpm timetick.
+ */
+uint32_t msm_mpm_get_count(void);
+
+#endif
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 52aa43a..0c1e279 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -291,6 +291,11 @@
int krait_power_mdd_enable(int cpu_num, bool on)
{
+ /*
+ * Expected to be called when the cpu goes to retention mode as a part
+ * of idle power collapse. IT is guaranteed that cpu won't be put in
+ * retention while being hotplugged out
+ */
struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu_num);
if (!on && kvreg->mode == LDO_MODE) {
@@ -298,7 +303,7 @@
return -EINVAL;
}
- if ((on && kvreg->mode == LDO_MODE) || (!on && kvreg->mode == HS_MODE))
+ if (on && kvreg->mode == LDO_MODE)
return 0;
__krait_power_mdd_enable(kvreg, on);
@@ -801,6 +806,8 @@
int rc;
mutex_lock(&pvreg->krait_power_vregs_lock);
+ if (kvreg->mode == LDO_MODE)
+ __krait_power_mdd_enable(kvreg, true);
kvreg->online = true;
rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load_uA);
if (rc < 0)
@@ -830,6 +837,8 @@
goto dis_err;
rc = _set_voltage(rdev, kvreg->uV, kvreg->uV);
+ if (kvreg->mode == LDO_MODE)
+ __krait_power_mdd_enable(kvreg, false);
dis_err:
mutex_unlock(&pvreg->krait_power_vregs_lock);
return rc;
diff --git a/arch/arm/mach-msm/lpm_levels.c b/arch/arm/mach-msm/lpm_levels.c
index dec62f0..539a4fe 100644
--- a/arch/arm/mach-msm/lpm_levels.c
+++ b/arch/arm/mach-msm/lpm_levels.c
@@ -66,18 +66,12 @@
atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
MSM_LPM_STATE_ENTER, &sleep_data);
- ret = msm_rpm_enter_sleep();
- if (ret) {
- pr_warn("%s(): RPM failed to enter sleep err:%d\n",
- __func__, ret);
- goto bail;
- }
if (from_idle)
debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_IDLE_LIMITS;
+ MSM_LPM_LVL_DBG_IDLE_LIMITS;
else
debug_mask = msm_lpm_lvl_dbg_msk &
- MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
+ MSM_LPM_LVL_DBG_SUSPEND_LIMITS;
if (debug_mask)
pr_info("%s(): pxo:%d l2:%d mem:0x%x(0x%x) dig:0x%x(0x%x)\n",
@@ -88,6 +82,19 @@
l->vdd_dig_upper_bound);
ret = msm_lpmrs_enter_sleep(sclk_count, l, from_idle, notify_rpm);
+ if (ret) {
+ pr_warn("%s() LPM resources failed to enter sleep\n",
+ __func__);
+ goto bail;
+ }
+ if (notify_rpm) {
+ ret = msm_rpm_enter_sleep(debug_mask);
+ if (ret) {
+ pr_warn("%s(): RPM failed to enter sleep err:%d\n",
+ __func__, ret);
+ goto bail;
+ }
+ }
bail:
return ret;
}
@@ -95,9 +102,11 @@
static void msm_lpm_exit_sleep(void *limits, bool from_idle,
bool notify_rpm, bool collapsed)
{
- msm_rpm_exit_sleep();
+
msm_lpmrs_exit_sleep((struct msm_rpmrs_limits *)limits,
from_idle, notify_rpm, collapsed);
+ if (notify_rpm)
+ msm_rpm_exit_sleep();
atomic_notifier_call_chain(&__get_cpu_var(lpm_notify_head),
MSM_LPM_STATE_EXIT, NULL);
}
diff --git a/arch/arm/mach-msm/lpm_resources.c b/arch/arm/mach-msm/lpm_resources.c
index 5d7fc94..a62ee92 100644
--- a/arch/arm/mach-msm/lpm_resources.c
+++ b/arch/arm/mach-msm/lpm_resources.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -668,7 +668,8 @@
}
msm_lpm_get_rpm_notif = true;
- msm_mpm_enter_sleep(sclk_count, from_idle);
+ if (notify_rpm)
+ msm_mpm_enter_sleep(sclk_count, from_idle);
return ret;
}
diff --git a/arch/arm/mach-msm/msm_mpmctr.c b/arch/arm/mach-msm/msm_mpmctr.c
new file mode 100644
index 0000000..4ab82ab
--- /dev/null
+++ b/arch/arm/mach-msm/msm_mpmctr.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/smp.h>
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <mach/msm_mpmctr.h>
+
+static void __iomem *mpm_timer_base;
+
+uint32_t msm_mpm_get_count(void)
+{
+ uint32_t count;
+ if (!mpm_timer_base)
+ return 0;
+
+ count = __raw_readl_no_log(mpm_timer_base);
+ pr_debug("mpm sclk sync:(%u)", count);
+ return count;
+}
+EXPORT_SYMBOL(msm_mpm_get_count);
+
+static inline void msm_mpmctr_show_count(void)
+{
+ unsigned long long t;
+ unsigned long nsec_rem;
+
+ t = sched_clock();
+
+ nsec_rem = do_div(t, 1000000000)/1000;
+
+ printk(KERN_INFO "mpm_counter: [%5lu.%06lu]:(%u)\n",
+ (unsigned long)t, nsec_rem,
+ msm_mpm_get_count());
+
+}
+
+static struct of_device_id msm_mpmctr_of_match[] = {
+ {.compatible = "qcom,mpm-counter"},
+ {}
+};
+
+static struct platform_driver msm_mpmctr_driver = {
+ .driver = {
+ .name = "msm_mpctr",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_mpmctr_of_match,
+ },
+};
+
+static int __init mpmctr_set_register(struct device_node *np)
+{
+ if (of_get_address(np, 0, NULL, NULL)) {
+ mpm_timer_base = of_iomap(np, 0);
+ if (!mpm_timer_base) {
+ pr_err("%s: cannot map timer base\n", __func__);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static int __init msm_mpmctr_probe(struct platform_device *pdev)
+{
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ if (mpmctr_set_register(pdev->dev.of_node))
+ return -ENODEV;
+
+ msm_mpmctr_show_count();
+
+ return 0;
+}
+
+static int __init mpmctr_init(void)
+{
+ return platform_driver_probe(&msm_mpmctr_driver, msm_mpmctr_probe);
+}
+
+module_init(mpmctr_init)
diff --git a/arch/arm/mach-msm/no-pm.c b/arch/arm/mach-msm/no-pm.c
index 0db6e68..a8d4fdb 100644
--- a/arch/arm/mach-msm/no-pm.c
+++ b/arch/arm/mach-msm/no-pm.c
@@ -37,15 +37,11 @@
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls) {}
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index)
{
return -ENOSYS;
}
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
-{
- return -ENOSYS;
-}
-
void msm_pm_enable_retention(bool enable) {}
+
diff --git a/arch/arm/mach-msm/pil-q6v5.c b/arch/arm/mach-msm/pil-q6v5.c
index 7f8d3b9..0263faf 100644
--- a/arch/arm/mach-msm/pil-q6v5.c
+++ b/arch/arm/mach-msm/pil-q6v5.c
@@ -167,7 +167,7 @@
/* Assert Q6 resets */
val = readl_relaxed(drv->reg_base + QDSP6SS_RESET);
- val = (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
+ val |= (Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENA);
writel_relaxed(val, drv->reg_base + QDSP6SS_RESET);
/* Kill power at block headswitch */
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 0b08238..b52d284 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -40,7 +41,6 @@
#ifdef CONFIG_VFP
#include <asm/vfp.h>
#endif
-
#include "acpuclock.h"
#include "clock.h"
#include "avs.h"
@@ -54,9 +54,27 @@
#include <mach/event_timer.h>
#define CREATE_TRACE_POINTS
#include "trace_msm_low_power.h"
-/******************************************************************************
- * Debug Definitions
- *****************************************************************************/
+
+#define SCM_L2_RETENTION (0x2)
+#define SCM_CMD_TERMINATE_PC (0x2)
+
+#define GET_CPU_OF_ATTR(attr) \
+ (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
+
+#define SCLK_HZ (32768)
+#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
+
+#define NUM_OF_COUNTERS 3
+#define MAX_BUF_SIZE 512
+
+static int msm_pm_debug_mask = 1;
+module_param_named(
+ debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
+);
+
+static int msm_pm_sleep_time_override;
+module_param_named(sleep_time_override,
+ msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
enum {
MSM_PM_DEBUG_SUSPEND = BIT(0),
@@ -70,24 +88,12 @@
MSM_PM_DEBUG_HOTPLUG = BIT(8),
};
-static int msm_pm_debug_mask = 1;
-module_param_named(
- debug_mask, msm_pm_debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP
-);
-static int msm_pm_retention_tz_call;
-
-/******************************************************************************
- * Sleep Modes and Parameters
- *****************************************************************************/
enum {
MSM_PM_MODE_ATTR_SUSPEND,
MSM_PM_MODE_ATTR_IDLE,
MSM_PM_MODE_ATTR_NR,
};
-#define SCM_L2_RETENTION (0x2)
-#define SCM_CMD_TERMINATE_PC (0x2)
-
static char *msm_pm_mode_attr_labels[MSM_PM_MODE_ATTR_NR] = {
[MSM_PM_MODE_ATTR_SUSPEND] = "suspend_enabled",
[MSM_PM_MODE_ATTR_IDLE] = "idle_enabled",
@@ -98,9 +104,6 @@
struct kobj_attribute ka;
};
-#define GET_CPU_OF_ATTR(attr) \
- (container_of(attr, struct msm_pm_kobj_attribute, ka)->cpu)
-
struct msm_pm_sysfs_sleep_mode {
struct kobject *kobj;
struct attribute_group attr_group;
@@ -116,10 +119,15 @@
"standalone_power_collapse",
};
-static struct msm_pm_init_data_type msm_pm_init_data;
static struct hrtimer pm_hrtimer;
static struct msm_pm_sleep_ops pm_sleep_ops;
static bool msm_pm_ldo_retention_enabled = true;
+static bool msm_pm_use_sync_timer;
+static struct msm_pm_cp15_save_data cp15_data;
+static bool msm_pm_retention_calls_tz;
+static uint32_t msm_pm_max_sleep_time;
+static bool msm_no_ramp_down_pc;
+
/*
* Write out the attribute.
*/
@@ -166,9 +174,6 @@
return ret;
}
-/*
- * Read in the new attribute value.
- */
static ssize_t msm_pm_mode_attr_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count)
{
@@ -205,10 +210,7 @@
return ret ? ret : count;
}
-/*
- * Add sysfs entries for one cpu.
- */
-static int __init msm_pm_mode_sysfs_add_cpu(
+static int __devinit msm_pm_mode_sysfs_add_cpu(
unsigned int cpu, struct kobject *modes_kobj)
{
char cpu_name[8];
@@ -291,10 +293,7 @@
return ret;
}
-/*
- * Add sysfs entries for the sleep modes.
- */
-static int __init msm_pm_mode_sysfs_add(void)
+int __devinit msm_pm_mode_sysfs_add(void)
{
struct kobject *module_kobj;
struct kobject *modes_kobj;
@@ -328,10 +327,6 @@
return ret;
}
-/******************************************************************************
- * Configure Hardware before/after Low Power Mode
- *****************************************************************************/
-
/*
* Configure hardware registers in preparation for Apps power down.
*/
@@ -374,22 +369,6 @@
return;
}
-
-/******************************************************************************
- * Suspend Max Sleep Time
- *****************************************************************************/
-
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
-static int msm_pm_sleep_time_override;
-module_param_named(sleep_time_override,
- msm_pm_sleep_time_override, int, S_IRUGO | S_IWUSR | S_IWGRP);
-#endif
-
-#define SCLK_HZ (32768)
-#define MSM_PM_SLEEP_TICK_LIMIT (0x6DDD000)
-
-static uint32_t msm_pm_max_sleep_time;
-
/*
* Convert time from nanoseconds to slow clock ticks, then cap it to the
* specified limit
@@ -408,36 +387,21 @@
if (max_sleep_time_ns == 0) {
msm_pm_max_sleep_time = 0;
} else {
- msm_pm_max_sleep_time = (uint32_t)msm_pm_convert_and_cap_time(
+ msm_pm_max_sleep_time =
+ (uint32_t)msm_pm_convert_and_cap_time(
max_sleep_time_ns, MSM_PM_SLEEP_TICK_LIMIT);
if (msm_pm_max_sleep_time == 0)
msm_pm_max_sleep_time = 1;
}
- if (msm_pm_debug_mask & MSM_PM_DEBUG_SUSPEND)
+ if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: Requested %lld ns Giving %u sclk ticks\n",
- __func__, max_sleep_time_ns, msm_pm_max_sleep_time);
+ __func__, max_sleep_time_ns,
+ msm_pm_max_sleep_time);
}
EXPORT_SYMBOL(msm_pm_set_max_sleep_time);
-struct reg_data {
- uint32_t reg;
- uint32_t val;
-};
-
-static struct reg_data reg_saved_state[] = {
- { .reg = 0x4501, },
- { .reg = 0x5501, },
- { .reg = 0x6501, },
- { .reg = 0x7501, },
- { .reg = 0x0500, },
-};
-
-static unsigned int active_vdd;
-static bool msm_pm_save_cp15;
-static const unsigned int pc_vdd = 0x98;
-
static void msm_pm_save_cpu_reg(void)
{
int i;
@@ -455,11 +419,12 @@
* rate. Then restore the active vdd before switching the acpuclk rate.
*/
if (msm_pm_get_l2_flush_flag() == 1) {
- active_vdd = msm_spm_get_vdd(0);
- for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
- reg_saved_state[i].val =
- get_l2_indirect_reg(reg_saved_state[i].reg);
- msm_spm_set_vdd(0, pc_vdd);
+ cp15_data.active_vdd = msm_spm_get_vdd(0);
+ for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+ cp15_data.reg_val[i] =
+ get_l2_indirect_reg(
+ cp15_data.reg_data[i]);
+ msm_spm_set_vdd(0, cp15_data.qsb_pc_vdd);
}
}
@@ -472,22 +437,20 @@
return;
if (msm_pm_get_l2_flush_flag() == 1) {
- for (i = 0; i < ARRAY_SIZE(reg_saved_state); i++)
- set_l2_indirect_reg(reg_saved_state[i].reg,
- reg_saved_state[i].val);
- msm_spm_set_vdd(0, active_vdd);
+ for (i = 0; i < cp15_data.reg_saved_state_size; i++)
+ set_l2_indirect_reg(
+ cp15_data.reg_data[i],
+ cp15_data.reg_val[i]);
+ msm_spm_set_vdd(0, cp15_data.active_vdd);
}
}
-static void *msm_pm_idle_rs_limits;
-
static void msm_pm_swfi(void)
{
msm_pm_config_hw_before_swfi();
msm_arch_idle();
}
-
static void msm_pm_retention(void)
{
int ret = 0;
@@ -496,7 +459,7 @@
ret = msm_spm_set_low_power_mode(MSM_SPM_MODE_POWER_RETENTION, false);
WARN_ON(ret);
- if (msm_pm_retention_tz_call)
+ if (msm_pm_retention_calls_tz)
scm_call_atomic1(SCM_SVC_BOOT, SCM_CMD_TERMINATE_PC,
SCM_L2_RETENTION);
else
@@ -567,7 +530,7 @@
static bool msm_pm_power_collapse(bool from_idle)
{
unsigned int cpu = smp_processor_id();
- unsigned long saved_acpuclk_rate;
+ unsigned long saved_acpuclk_rate = 0;
unsigned int avsdscr;
unsigned int avscsr;
bool collapsed;
@@ -584,28 +547,28 @@
avscsr = avs_get_avscsr();
avs_set_avscsr(0); /* Disable AVS */
- if (cpu_online(cpu))
+ if (cpu_online(cpu) && !msm_no_ramp_down_pc)
saved_acpuclk_rate = acpuclk_power_collapse();
- else
- saved_acpuclk_rate = 0;
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: change clock rate (old rate = %lu)\n",
cpu, __func__, saved_acpuclk_rate);
- if (msm_pm_save_cp15)
+ if (cp15_data.save_cp15)
msm_pm_save_cpu_reg();
collapsed = msm_pm_spm_power_collapse(cpu, from_idle, true);
- if (msm_pm_save_cp15)
+ if (cp15_data.save_cp15)
msm_pm_restore_cpu_reg();
if (cpu_online(cpu)) {
if (MSM_PM_DEBUG_CLOCK & msm_pm_debug_mask)
pr_info("CPU%u: %s: restore clock rate to %lu\n",
cpu, __func__, saved_acpuclk_rate);
- if (acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC) < 0)
+ if (!msm_no_ramp_down_pc &&
+ acpuclk_set_rate(cpu, saved_acpuclk_rate, SETRATE_PC)
+ < 0)
pr_err("CPU%u: %s: failed to restore clock rate(%lu)\n",
cpu, __func__, saved_acpuclk_rate);
} else {
@@ -635,15 +598,9 @@
return collapsed;
}
-static void msm_pm_target_init(void)
-{
- if (cpu_is_apq8064())
- msm_pm_save_cp15 = true;
-}
-
static int64_t msm_pm_timer_enter_idle(void)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(tick_nohz_get_sleep_length());
return msm_timer_enter_idle();
@@ -651,7 +608,7 @@
static void msm_pm_timer_exit_idle(bool timer_halted)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return;
msm_timer_exit_idle((int) timer_halted);
@@ -661,7 +618,7 @@
{
int64_t time = 0;
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(ktime_get());
time = msm_timer_get_sclk_time(period);
@@ -673,7 +630,7 @@
static int64_t msm_pm_timer_exit_suspend(int64_t time, int64_t period)
{
- if (msm_pm_init_data.use_sync_timer)
+ if (msm_pm_use_sync_timer)
return ktime_to_ns(ktime_get()) - time;
if (time != 0) {
@@ -765,8 +722,9 @@
}
}
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
+static int msm_pm_idle_prepare(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index,
+ void **msm_pm_idle_rs_limits)
{
int i;
unsigned int power_usage = -1;
@@ -793,9 +751,9 @@
struct cpuidle_state_usage *st_usage = &dev->states_usage[i];
enum msm_pm_sleep_mode mode;
bool allow;
- void *rs_limits = NULL;
uint32_t power;
int idx;
+ void *rs_limits = NULL;
mode = (enum msm_pm_sleep_mode) cpuidle_get_statedata(st_usage);
idx = MSM_PM_MODE(dev->cpu, mode);
@@ -805,11 +763,9 @@
switch (mode) {
case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
- if (num_online_cpus() > 1) {
+ if (num_online_cpus() > 1)
allow = false;
- break;
- }
- /* fall through */
+ break;
case MSM_PM_SLEEP_MODE_RETENTION:
/*
* The Krait BHS regulator doesn't have enough head
@@ -817,62 +773,41 @@
* has disabled retention
*/
if (!msm_pm_ldo_retention_enabled)
- break;
-
- if (!allow)
- break;
-
- if (msm_pm_retention_tz_call &&
- num_online_cpus() > 1) {
allow = false;
- break;
- }
- /* fall through */
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
- if (!allow)
- break;
- /* fall through */
-
- case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
- if (!allow)
- break;
- /* fall through */
-
- if (pm_sleep_ops.lowest_limits)
- rs_limits = pm_sleep_ops.lowest_limits(true,
- mode, &time_param, &power);
-
- if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: %s, latency %uus, "
- "sleep %uus, limit %p\n",
- dev->cpu, __func__, state->desc,
- time_param.latency_us,
- time_param.sleep_us, rs_limits);
-
- if (!rs_limits)
+ if (msm_pm_retention_calls_tz && num_online_cpus() > 1)
allow = false;
break;
-
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE_STANDALONE:
+ case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
+ break;
default:
allow = false;
break;
}
+ if (!allow)
+ continue;
+
+ if (pm_sleep_ops.lowest_limits)
+ rs_limits = pm_sleep_ops.lowest_limits(true,
+ mode, &time_param, &power);
+
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
- pr_info("CPU%u: %s: allow %s: %d\n",
- dev->cpu, __func__, state->desc, (int)allow);
+ pr_info("CPU%u:%s:%s, latency %uus, slp %uus, lim %p\n",
+ dev->cpu, __func__, state->desc,
+ time_param.latency_us,
+ time_param.sleep_us, rs_limits);
+ if (!rs_limits)
+ continue;
- if (allow) {
- if (power < power_usage) {
- power_usage = power;
- modified_time_us = time_param.modified_time_us;
- ret = mode;
- }
-
- if (MSM_PM_SLEEP_MODE_POWER_COLLAPSE == mode)
- msm_pm_idle_rs_limits = rs_limits;
+ if (power < power_usage) {
+ power_usage = power;
+ modified_time_us = time_param.modified_time_us;
+ ret = mode;
+ *msm_pm_idle_rs_limits = rs_limits;
}
+
}
if (modified_time_us && !dev->cpu)
@@ -885,11 +820,27 @@
return ret;
}
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode)
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
{
int64_t time;
- int exit_stat;
bool collapsed = 1;
+ int exit_stat = -1;
+ enum msm_pm_sleep_mode sleep_mode;
+ void *msm_pm_idle_rs_limits = NULL;
+ int sleep_delay = 1;
+ int ret = -ENODEV;
+ int64_t timer_expiration = 0;
+ int notify_rpm = false;
+ bool timer_halted = false;
+
+ sleep_mode = msm_pm_idle_prepare(dev, drv, index,
+ &msm_pm_idle_rs_limits);
+
+ if (!msm_pm_idle_rs_limits) {
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+ goto cpuidle_enter_bail;
+ }
if (MSM_PM_DEBUG_IDLE & msm_pm_debug_mask)
pr_info("CPU%u: %s: mode %d\n",
@@ -897,6 +848,22 @@
time = ktime_to_ns(ktime_get());
+ if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE) {
+ notify_rpm = true;
+ timer_expiration = msm_pm_timer_enter_idle();
+
+ sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
+ timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
+ if (sleep_delay == 0) /* 0 would mean infinite time */
+ sleep_delay = 1;
+ }
+
+ if (pm_sleep_ops.enter_sleep)
+ ret = pm_sleep_ops.enter_sleep(sleep_delay,
+ msm_pm_idle_rs_limits, true, notify_rpm);
+ if (ret)
+ goto cpuidle_enter_bail;
+
switch (sleep_mode) {
case MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT:
msm_pm_swfi();
@@ -913,39 +880,16 @@
exit_stat = MSM_PM_STAT_IDLE_STANDALONE_POWER_COLLAPSE;
break;
- case MSM_PM_SLEEP_MODE_POWER_COLLAPSE: {
- int64_t timer_expiration = 0;
- bool timer_halted = false;
- uint32_t sleep_delay;
- int ret = -ENODEV;
- int notify_rpm =
- (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE);
- timer_expiration = msm_pm_timer_enter_idle();
-
- sleep_delay = (uint32_t) msm_pm_convert_and_cap_time(
- timer_expiration, MSM_PM_SLEEP_TICK_LIMIT);
- if (sleep_delay == 0) /* 0 would mean infinite time */
- sleep_delay = 1;
-
+ case MSM_PM_SLEEP_MODE_POWER_COLLAPSE:
if (MSM_PM_DEBUG_IDLE_CLK & msm_pm_debug_mask)
clock_debug_print_enabled();
- if (pm_sleep_ops.enter_sleep)
- ret = pm_sleep_ops.enter_sleep(sleep_delay,
- msm_pm_idle_rs_limits,
- true, notify_rpm);
- if (!ret) {
- collapsed = msm_pm_power_collapse(true);
- timer_halted = true;
+ collapsed = msm_pm_power_collapse(true);
+ timer_halted = true;
- if (pm_sleep_ops.exit_sleep)
- pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits,
- true, notify_rpm, collapsed);
- }
- msm_pm_timer_exit_idle(timer_halted);
exit_stat = MSM_PM_STAT_IDLE_POWER_COLLAPSE;
+ msm_pm_timer_exit_idle(timer_halted);
break;
- }
case MSM_PM_SLEEP_MODE_NOT_SELECTED:
goto cpuidle_enter_bail;
@@ -957,16 +901,24 @@
break;
}
- time = ktime_to_ns(ktime_get()) - time;
- msm_pm_add_stat(exit_stat, time);
- msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode,
- collapsed);
+ if (pm_sleep_ops.exit_sleep)
+ pm_sleep_ops.exit_sleep(msm_pm_idle_rs_limits, true,
+ notify_rpm, collapsed);
+ time = ktime_to_ns(ktime_get()) - time;
+ msm_pm_ftrace_lpm_exit(smp_processor_id(), sleep_mode, collapsed);
+ if (exit_stat >= 0)
+ msm_pm_add_stat(exit_stat, time);
do_div(time, 1000);
- return (int) time;
+ dev->last_residency = (int) time;
+ return sleep_mode;
cpuidle_enter_bail:
- return 0;
+ dev->last_residency = 0;
+ if (sleep_mode == MSM_PM_SLEEP_MODE_POWER_COLLAPSE)
+ msm_pm_timer_exit_idle(timer_halted);
+ sleep_mode = MSM_PM_SLEEP_MODE_NOT_SELECTED;
+ return sleep_mode;
}
void msm_pm_cpu_enter_lowpower(unsigned int cpu)
@@ -1060,17 +1012,16 @@
clock_debug_print_enabled();
-#ifdef CONFIG_MSM_SLEEP_TIME_OVERRIDE
if (msm_pm_sleep_time_override > 0) {
int64_t ns = NSEC_PER_SEC *
(int64_t) msm_pm_sleep_time_override;
msm_pm_set_max_sleep_time(ns);
msm_pm_sleep_time_override = 0;
}
-#endif /* CONFIG_MSM_SLEEP_TIME_OVERRIDE */
+
if (pm_sleep_ops.lowest_limits)
rs_limits = pm_sleep_ops.lowest_limits(false,
- MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
+ MSM_PM_SLEEP_MODE_POWER_COLLAPSE, &time_param, &power);
if (rs_limits) {
if (pm_sleep_ops.enter_sleep)
@@ -1104,7 +1055,6 @@
msm_pm_swfi();
}
-
enter_exit:
if (MSM_PM_DEBUG_SUSPEND & msm_pm_debug_mask)
pr_info("%s: return\n", __func__);
@@ -1112,66 +1062,18 @@
return 0;
}
-static struct platform_suspend_ops msm_pm_ops = {
- .enter = msm_pm_enter,
- .valid = suspend_valid_only_mem,
-};
-
-/******************************************************************************
- * Initialization routine
- *****************************************************************************/
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops)
{
if (ops)
pm_sleep_ops = *ops;
}
-void __init msm_pm_set_tz_retention_flag(unsigned int flag)
-{
- msm_pm_retention_tz_call = flag;
-}
-
-static int __devinit msm_pc_debug_probe(struct platform_device *pdev)
-{
- struct resource *res = NULL;
- int i ;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- goto fail;
-
- msm_pc_debug_counters_phys = res->start;
- WARN_ON(resource_size(res) < SZ_64);
- msm_pc_debug_counters = devm_ioremap_nocache(&pdev->dev, res->start,
- resource_size(res));
-
- if (!msm_pc_debug_counters)
- goto fail;
-
- for (i = 0; i < resource_size(res)/4; i++)
- __raw_writel(0, msm_pc_debug_counters + i * 4);
- return 0;
-fail:
- msm_pc_debug_counters = 0;
- msm_pc_debug_counters_phys = 0;
- return -EFAULT;
-}
-
-static struct of_device_id msm_pc_debug_table[] = {
- {.compatible = "qcom,pc-cntr"},
- {},
+static const struct platform_suspend_ops msm_pm_ops = {
+ .enter = msm_pm_enter,
+ .valid = suspend_valid_only_mem,
};
-static struct platform_driver msm_pc_counter_driver = {
- .probe = msm_pc_debug_probe,
- .driver = {
- .name = "pc-cntr",
- .owner = THIS_MODULE,
- .of_match_table = msm_pc_debug_table,
- },
-};
-
-static int __init msm_pm_init(void)
+static int __devinit msm_pm_init(void)
{
pgd_t *pc_pgd;
pmd_t *pmd;
@@ -1186,7 +1088,6 @@
unsigned long exit_phys;
/* Page table for cores to come back up safely. */
-
pc_pgd = pgd_alloc(&init_mm);
if (!pc_pgd)
return -ENOMEM;
@@ -1225,18 +1126,13 @@
msm_pm_mode_sysfs_add();
msm_pm_add_stats(enable_stats, ARRAY_SIZE(enable_stats));
-
suspend_set_ops(&msm_pm_ops);
- msm_pm_target_init();
hrtimer_init(&pm_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
msm_cpuidle_init();
- platform_driver_register(&msm_pc_counter_driver);
return 0;
}
-late_initcall(msm_pm_init);
-
static void __devinit msm_pm_set_flush_fn(uint32_t pc_mode)
{
msm_pm_disable_l2_fn = NULL;
@@ -1249,41 +1145,203 @@
}
}
+struct msm_pc_debug_counters_buffer {
+ void __iomem *reg;
+ u32 len;
+ char buf[MAX_BUF_SIZE];
+};
+
+static inline u32 msm_pc_debug_counters_read_register(
+ void __iomem *reg, int index , int offset)
+{
+ return readl_relaxed(reg + (index * 4 + offset) * 4);
+}
+
+static char *counter_name[] = {
+ "PC Entry Counter",
+ "Warmboot Entry Counter",
+ "PC Bailout Counter"
+};
+
+static int msm_pc_debug_counters_copy(
+ struct msm_pc_debug_counters_buffer *data)
+{
+ int j;
+ u32 stat;
+ unsigned int cpu;
+
+ for_each_possible_cpu(cpu) {
+ data->len += scnprintf(data->buf + data->len,
+ sizeof(data->buf)-data->len,
+ "CPU%d\n", cpu);
+
+ for (j = 0; j < NUM_OF_COUNTERS; j++) {
+ stat = msm_pc_debug_counters_read_register(
+ data->reg, cpu, j);
+ data->len += scnprintf(data->buf + data->len,
+ sizeof(data->buf)-data->len,
+ "\t%s : %d\n", counter_name[j],
+ stat);
+ }
+
+ }
+
+ return data->len;
+}
+
+static int msm_pc_debug_counters_file_read(struct file *file,
+ char __user *bufu, size_t count, loff_t *ppos)
+{
+ struct msm_pc_debug_counters_buffer *data;
+
+ data = file->private_data;
+
+ if (!data)
+ return -EINVAL;
+
+ if (!bufu || count < 0)
+ return -EINVAL;
+
+ if (!access_ok(VERIFY_WRITE, bufu, count))
+ return -EFAULT;
+
+ if (*ppos >= data->len && data->len == 0)
+ data->len = msm_pc_debug_counters_copy(data);
+
+ return simple_read_from_buffer(bufu, count, ppos,
+ data->buf, data->len);
+}
+
+static int msm_pc_debug_counters_file_open(struct inode *inode,
+ struct file *file)
+{
+ struct msm_pc_debug_counters_buffer *buf;
+ void __iomem *msm_pc_debug_counters_reg;
+
+ msm_pc_debug_counters_reg = inode->i_private;
+
+ if (!msm_pc_debug_counters_reg)
+ return -EINVAL;
+
+ file->private_data = kzalloc(
+ sizeof(struct msm_pc_debug_counters_buffer), GFP_KERNEL);
+
+ if (!file->private_data) {
+ pr_err("%s: ERROR kmalloc failed to allocate %d bytes\n",
+ __func__, sizeof(struct msm_pc_debug_counters_buffer));
+
+ return -ENOMEM;
+ }
+
+ buf = file->private_data;
+ buf->reg = msm_pc_debug_counters_reg;
+
+ return 0;
+}
+
+static int msm_pc_debug_counters_file_close(struct inode *inode,
+ struct file *file)
+{
+ kfree(file->private_data);
+ return 0;
+}
+
+static const struct file_operations msm_pc_debug_counters_fops = {
+ .open = msm_pc_debug_counters_file_open,
+ .read = msm_pc_debug_counters_file_read,
+ .release = msm_pc_debug_counters_file_close,
+ .llseek = no_llseek,
+};
+
static int __devinit msm_pm_8x60_probe(struct platform_device *pdev)
{
char *key = NULL;
+ struct dentry *dent = NULL;
uint32_t val = 0;
+ struct resource *res = NULL;
+ int i ;
+ struct msm_pm_init_data_type pdata_local;
int ret = 0;
+ memset(&pdata_local, 0, sizeof(struct msm_pm_init_data_type));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res) {
+ msm_pc_debug_counters_phys = res->start;
+ WARN_ON(resource_size(res) < SZ_64);
+ msm_pc_debug_counters = devm_ioremap(&pdev->dev, res->start,
+ resource_size(res));
+ if (msm_pc_debug_counters)
+ for (i = 0; i < resource_size(res)/4; i++)
+ __raw_writel(0, msm_pc_debug_counters + i * 4);
+
+ }
+
+ if (!msm_pc_debug_counters) {
+ msm_pc_debug_counters = 0;
+ msm_pc_debug_counters_phys = 0;
+ } else {
+ dent = debugfs_create_file("pc_debug_counter", S_IRUGO, NULL,
+ msm_pc_debug_counters,
+ &msm_pc_debug_counters_fops);
+ if (!dent)
+ pr_err("%s: ERROR debugfs_create_file failed\n",
+ __func__);
+ }
+
if (!pdev->dev.of_node) {
struct msm_pm_init_data_type *d = pdev->dev.platform_data;
if (!d)
goto pm_8x60_probe_done;
- msm_pm_init_data.pc_mode = d->pc_mode;
- msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
- msm_pm_init_data.use_sync_timer = d->use_sync_timer;
+ memcpy(&pdata_local, d, sizeof(struct msm_pm_init_data_type));
+
} else {
key = "qcom,pc-mode";
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
-
if (ret) {
pr_debug("%s: Cannot read %s,defaulting to 0",
__func__, key);
val = MSM_PM_PC_TZ_L2_INT;
ret = 0;
}
-
- msm_pm_init_data.pc_mode = val;
- msm_pm_set_flush_fn(msm_pm_init_data.pc_mode);
+ pdata_local.pc_mode = val;
key = "qcom,use-sync-timer";
- msm_pm_init_data.use_sync_timer =
+ pdata_local.use_sync_timer =
of_property_read_bool(pdev->dev.of_node, key);
+
+ key = "qcom,saw-turns-off-pll";
+ msm_no_ramp_down_pc = of_property_read_bool(pdev->dev.of_node,
+ key);
}
+ if (pdata_local.cp15_data.reg_data &&
+ pdata_local.cp15_data.reg_saved_state_size > 0) {
+ cp15_data.reg_data = kzalloc(sizeof(uint32_t) *
+ pdata_local.cp15_data.reg_saved_state_size,
+ GFP_KERNEL);
+ if (!cp15_data.reg_data)
+ return -ENOMEM;
+
+ cp15_data.reg_val = kzalloc(sizeof(uint32_t) *
+ pdata_local.cp15_data.reg_saved_state_size,
+ GFP_KERNEL);
+ if (cp15_data.reg_val)
+ return -ENOMEM;
+
+ memcpy(cp15_data.reg_data, pdata_local.cp15_data.reg_data,
+ pdata_local.cp15_data.reg_saved_state_size *
+ sizeof(uint32_t));
+ }
+
+ msm_pm_set_flush_fn(pdata_local.pc_mode);
+ msm_pm_use_sync_timer = pdata_local.use_sync_timer;
+ msm_pm_retention_calls_tz = pdata_local.retention_calls_tz;
+
pm_8x60_probe_done:
+ msm_pm_init();
return ret;
}
@@ -1305,4 +1363,4 @@
{
return platform_driver_register(&msm_pm_8x60_driver);
}
-module_init(msm_pm_8x60_init);
+device_initcall(msm_pm_8x60_init);
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 399194a..af0744c 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -97,8 +97,19 @@
external L2 cache controller */
};
+struct msm_pm_cp15_save_data {
+ bool save_cp15;
+ uint32_t active_vdd;
+ uint32_t qsb_pc_vdd;
+ uint32_t reg_saved_state_size;
+ uint32_t *reg_data;
+ uint32_t *reg_val;
+};
+
struct msm_pm_init_data_type {
enum msm_pm_pc_mode_type pc_mode;
+ bool retention_calls_tz;
+ struct msm_pm_cp15_save_data cp15_data;
bool use_sync_timer;
};
@@ -108,10 +119,9 @@
};
void msm_pm_set_platform_data(struct msm_pm_platform_data *data, int count);
-int msm_pm_idle_prepare(struct cpuidle_device *dev,
+enum msm_pm_sleep_mode msm_pm_idle_enter(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
void msm_pm_set_irq_extns(struct msm_pm_irq_calls *irq_calls);
-int msm_pm_idle_enter(enum msm_pm_sleep_mode sleep_mode);
void msm_pm_cpu_enter_lowpower(unsigned int cpu);
void __init msm_pm_set_tz_retention_flag(unsigned int flag);
void msm_pm_enable_retention(bool enable);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
index 654f547..e6b9549 100644
--- a/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils_aio.c
@@ -897,6 +897,11 @@
struct audio_client *ac;
struct audio_aio_write_param param;
+ if (!audio || !buf_node) {
+ pr_err("%s NULL pointer audio=[0x%p], buf_node=[0x%p]\n",
+ __func__, audio, buf_node);
+ return;
+ }
pr_debug("%s[%p]: Send write buff %p phy %lx len %d meta_enable = %d\n",
__func__, audio, buf_node, buf_node->paddr,
buf_node->buf.data_len,
@@ -922,8 +927,7 @@
if (!audio->buf_cfg.meta_info_enable)
param.flags = 0xFF00;
- if ((buf_node != NULL) &&
- (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET))
+ if (buf_node->meta_info.meta_in.nflags & AUDIO_DEC_EOF_SET)
param.flags |= AUDIO_DEC_EOF_SET;
param.uid = param.paddr;
diff --git a/arch/arm/mach-msm/rpm-notifier.h b/arch/arm/mach-msm/rpm-notifier.h
index b9815a5..16de77e 100644
--- a/arch/arm/mach-msm/rpm-notifier.h
+++ b/arch/arm/mach-msm/rpm-notifier.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -40,8 +40,12 @@
/**
* msm_rpm_enter_sleep - Notify RPM driver to prepare for entering sleep
+ *
+ * @bool - flag to enable print contents of sleep buffer.
+ *
+ * return 0 on success errno on failure.
*/
-int msm_rpm_enter_sleep(void);
+int msm_rpm_enter_sleep(bool print);
/**
* msm_rpm_exit_sleep - Notify RPM driver about resuming from power collapse
diff --git a/arch/arm/mach-msm/rpm-smd.c b/arch/arm/mach-msm/rpm-smd.c
index 4295fd4..b84ade9 100644
--- a/arch/arm/mach-msm/rpm-smd.c
+++ b/arch/arm/mach-msm/rpm-smd.c
@@ -32,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/rbtree.h>
#include <mach/socinfo.h>
#include <mach/msm_smd.h>
#include <mach/rpm-smd.h>
@@ -62,6 +63,9 @@
};
#define DEFAULT_BUFFER_SIZE 256
+#define DEBUG_PRINT_BUFFER_SIZE 512
+#define MAX_SLEEP_BUFFER 128
+
#define GFP_FLAG(noirq) (noirq ? GFP_ATOMIC : GFP_KERNEL)
#define INV_RSC "resource does not exist"
#define ERR "err\0"
@@ -106,6 +110,11 @@
uint32_t data_len;
};
+struct kvp {
+ unsigned int k;
+ unsigned int s;
+};
+
struct msm_rpm_kvp_data {
uint32_t key;
uint32_t nbytes; /* number of bytes */
@@ -113,6 +122,301 @@
bool valid;
};
+struct slp_buf {
+ struct rb_node node;
+ char ubuf[MAX_SLEEP_BUFFER];
+ char *buf;
+ bool valid;
+};
+static struct rb_root tr_root = RB_ROOT;
+
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq);
+static uint32_t msm_rpm_get_next_msg_id(void);
+
+static inline unsigned int get_rsc_type(char *buf)
+{
+ struct rpm_message_header *h;
+ h = (struct rpm_message_header *)
+ (buf + sizeof(struct rpm_request_header));
+ return h->resource_type;
+}
+
+static inline unsigned int get_rsc_id(char *buf)
+{
+ struct rpm_message_header *h;
+ h = (struct rpm_message_header *)
+ (buf + sizeof(struct rpm_request_header));
+ return h->resource_id;
+}
+
+#define get_data_len(buf) \
+ (((struct rpm_message_header *) \
+ (buf + sizeof(struct rpm_request_header)))->data_len)
+
+#define get_req_len(buf) \
+ (((struct rpm_request_header *)(buf))->request_len)
+
+#define get_msg_id(buf) \
+ (((struct rpm_message_header *) \
+ (buf + sizeof(struct rpm_request_header)))->msg_id)
+
+
+static inline int get_buf_len(char *buf)
+{
+ return get_req_len(buf) + sizeof(struct rpm_request_header);
+}
+
+static inline struct kvp *get_first_kvp(char *buf)
+{
+ return (struct kvp *)(buf + sizeof(struct rpm_request_header)
+ + sizeof(struct rpm_message_header));
+}
+
+static inline struct kvp *get_next_kvp(struct kvp *k)
+{
+ return (struct kvp *)((void *)k + sizeof(*k) + k->s);
+}
+
+static inline void *get_data(struct kvp *k)
+{
+ return (void *)k + sizeof(*k);
+}
+
+
+static void delete_kvp(char *msg, struct kvp *d)
+{
+ struct kvp *n;
+ int dec, size;
+
+ n = get_next_kvp(d);
+ dec = (void *)n - (void *)d;
+ size = get_data_len(msg) - ((void *)n - (void *)get_first_kvp(msg));
+
+ memcpy((void *)d, (void *)n, size);
+
+ get_data_len(msg) -= dec;
+ get_req_len(msg) -= dec;
+}
+
+static inline void update_kvp_data(struct kvp *dest, struct kvp *src)
+{
+ memcpy(get_data(dest), get_data(src), src->s);
+}
+
+static void add_kvp(char *buf, struct kvp *n)
+{
+ int inc = sizeof(*n) + n->s;
+ BUG_ON((get_req_len(buf) + inc) > MAX_SLEEP_BUFFER);
+
+ memcpy(buf + get_buf_len(buf), n, inc);
+
+ get_data_len(buf) += inc;
+ get_req_len(buf) += inc;
+}
+
+static struct slp_buf *tr_search(struct rb_root *root, char *slp)
+{
+ unsigned int type = get_rsc_type(slp);
+ unsigned int id = get_rsc_id(slp);
+
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct slp_buf *cur = rb_entry(node, struct slp_buf, node);
+ unsigned int ctype = get_rsc_type(cur->buf);
+ unsigned int cid = get_rsc_id(cur->buf);
+
+ if (type < ctype)
+ node = node->rb_left;
+ else if (type > ctype)
+ node = node->rb_right;
+ else if (id < cid)
+ node = node->rb_left;
+ else if (id > cid)
+ node = node->rb_right;
+ else
+ return cur;
+ }
+ return NULL;
+}
+
+static int tr_insert(struct rb_root *root, struct slp_buf *slp)
+{
+ unsigned int type = get_rsc_type(slp->buf);
+ unsigned int id = get_rsc_id(slp->buf);
+
+ struct rb_node **node = &(root->rb_node), *parent = NULL;
+
+ while (*node) {
+ struct slp_buf *curr = rb_entry(*node, struct slp_buf, node);
+ unsigned int ctype = get_rsc_type(curr->buf);
+ unsigned int cid = get_rsc_id(curr->buf);
+
+ parent = *node;
+
+ if (type < ctype)
+ node = &((*node)->rb_left);
+ else if (type > ctype)
+ node = &((*node)->rb_right);
+ else if (id < cid)
+ node = &((*node)->rb_left);
+ else if (id > cid)
+ node = &((*node)->rb_right);
+ else
+ return -EINVAL;
+ }
+
+ rb_link_node(&slp->node, parent, node);
+ rb_insert_color(&slp->node, root);
+ slp->valid = true;
+ return 0;
+}
+
+#define for_each_kvp(buf, k) \
+ for (k = (struct kvp *)get_first_kvp(buf); \
+ ((void *)k - (void *)get_first_kvp(buf)) < get_data_len(buf);\
+ k = get_next_kvp(k))
+
+
+static void tr_update(struct slp_buf *s, char *buf)
+{
+ struct kvp *e, *n;
+
+ for_each_kvp(buf, n) {
+ for_each_kvp(s->buf, e) {
+ if (n->k == e->k) {
+ if (n->s == e->s) {
+ void *e_data = get_data(e);
+ void *n_data = get_data(n);
+ if (memcmp(e_data, n_data, n->s)) {
+ update_kvp_data(e, n);
+ s->valid = true;
+ }
+ } else {
+ delete_kvp(s->buf, e);
+ add_kvp(s->buf, n);
+ s->valid = true;
+ }
+ break;
+ }
+ }
+ }
+}
+
+int msm_rpm_smd_buffer_request(char *buf, int size, gfp_t flag)
+{
+ struct slp_buf *slp;
+ static DEFINE_SPINLOCK(slp_buffer_lock);
+ unsigned long flags;
+
+ if (size > MAX_SLEEP_BUFFER)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&slp_buffer_lock, flags);
+ slp = tr_search(&tr_root, buf);
+
+ if (!slp) {
+ slp = kzalloc(sizeof(struct slp_buf), GFP_ATOMIC);
+ if (!slp) {
+ spin_unlock_irqrestore(&slp_buffer_lock, flags);
+ return -ENOMEM;
+ }
+ slp->buf = PTR_ALIGN(&slp->ubuf[0], sizeof(u32));
+ memcpy(slp->buf, buf, size);
+ if (tr_insert(&tr_root, slp))
+ pr_err("%s(): Error updating sleep request\n",
+ __func__);
+ } else {
+ /* handle unsent requests */
+ tr_update(slp, buf);
+ }
+
+ spin_unlock_irqrestore(&slp_buffer_lock, flags);
+
+ return 0;
+}
+static void msm_rpm_print_sleep_buffer(struct slp_buf *s)
+{
+ char buf[DEBUG_PRINT_BUFFER_SIZE] = {0};
+ int pos;
+ int buflen = DEBUG_PRINT_BUFFER_SIZE;
+ char ch[5] = {0};
+ u32 type;
+ struct kvp *e;
+
+ if (!s)
+ return;
+
+ if (!s->valid)
+ return;
+
+ type = get_rsc_type(s->buf);
+ memcpy(ch, &type, sizeof(u32));
+
+ pos = scnprintf(buf, buflen,
+ "Sleep request type = 0x%08x(%s)",
+ get_rsc_type(s->buf), ch);
+ pos += scnprintf(buf + pos, buflen - pos, " id = 0%x",
+ get_rsc_id(s->buf));
+ for_each_kvp(s->buf, e) {
+ int i;
+ char *data = get_data(e);
+
+ memcpy(ch, &e->k, sizeof(u32));
+
+ pos += scnprintf(buf + pos, buflen - pos,
+ "\n\t\tkey = 0x%08x(%s)",
+ e->k, ch);
+ pos += scnprintf(buf + pos, buflen - pos,
+ " sz= %d data =", e->s);
+
+ for (i = 0; i < e->s; i++)
+ pos += scnprintf(buf + pos, buflen - pos,
+ " 0x%02X", data[i]);
+ }
+ pos += scnprintf(buf + pos, buflen - pos, "\n");
+ printk(buf);
+}
+
+static int msm_rpm_flush_requests(bool print)
+{
+ struct rb_node *t;
+ int ret;
+
+ for (t = rb_first(&tr_root); t; t = rb_next(t)) {
+
+ struct slp_buf *s = rb_entry(t, struct slp_buf, node);
+
+ if (!s->valid)
+ continue;
+
+ if (print)
+ msm_rpm_print_sleep_buffer(s);
+
+ get_msg_id(s->buf) = msm_rpm_get_next_msg_id();
+ ret = msm_rpm_send_smd_buffer(s->buf,
+ get_buf_len(s->buf), true);
+ /* By not adding the message to a wait list we can reduce
+ * latency involved in waiting for a ACK from RPM. The ACK
+ * messages will be processed when we wakeup from sleep but
+ * processing should be minimal
+ * msm_rpm_wait_for_ack_noirq(get_msg_id(s->buf));
+ */
+
+ WARN_ON(ret != get_buf_len(s->buf));
+
+ trace_rpm_send_message(true, MSM_RPM_CTX_SLEEP_SET,
+ get_rsc_type(s->buf),
+ get_rsc_id(s->buf),
+ get_msg_id(s->buf));
+
+ s->valid = false;
+ }
+ return 0;
+
+}
+
+
static atomic_t msm_rpm_msg_id = ATOMIC_INIT(0);
static struct msm_rpm_driver_data msm_rpm_data;
@@ -450,7 +754,12 @@
}
elem = NULL;
}
- WARN_ON(!elem);
+ /* Special case where the sleep driver doesn't
+ * wait for ACKs. This would decrease the latency involved with
+ * entering RPM assisted power collapse.
+ */
+ if (!elem)
+ trace_rpm_ack_recd(0, msg_id);
spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
}
@@ -544,8 +853,6 @@
}
}
-#define DEBUG_PRINT_BUFFER_SIZE 512
-
static void msm_rpm_log_request(struct msm_rpm_request *cdata)
{
char buf[DEBUG_PRINT_BUFFER_SIZE];
@@ -677,13 +984,42 @@
pos += scnprintf(buf + pos, buflen - pos, "\n");
printk(buf);
}
+static int msm_rpm_send_smd_buffer(char *buf, int size, bool noirq)
+{
+ unsigned long flags;
+ int ret;
+ spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+ ret = smd_write_avail(msm_rpm_data.ch_info);
+
+ while ((ret = smd_write_avail(msm_rpm_data.ch_info)) < size) {
+ if (ret < 0)
+ break;
+ if (!noirq) {
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
+ flags);
+ cpu_relax();
+ spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
+ } else
+ udelay(5);
+ }
+
+ if (ret < 0) {
+ pr_err("%s(): SMD not initialized\n", __func__);
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ return ret;
+ }
+
+ ret = smd_write(msm_rpm_data.ch_info, buf, size);
+ spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ return ret;
+
+}
static int msm_rpm_send_data(struct msm_rpm_request *cdata,
int msg_type, bool noirq)
{
uint8_t *tmpbuff;
int i, ret, msg_size;
- unsigned long flags;
int req_hdr_sz, msg_hdr_sz;
@@ -695,8 +1031,6 @@
cdata->req_hdr.service_type = msm_rpm_request_service[msg_type];
- cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
-
cdata->req_hdr.request_len = cdata->msg_hdr.data_len + msg_hdr_sz;
msg_size = cdata->req_hdr.request_len + req_hdr_sz;
@@ -714,8 +1048,6 @@
tmpbuff = cdata->buf;
- memcpy(tmpbuff, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
-
tmpbuff += req_hdr_sz + msg_hdr_sz;
for (i = 0; (i < cdata->write_idx); i++) {
@@ -740,6 +1072,17 @@
}
+ memcpy(cdata->buf, &cdata->req_hdr, req_hdr_sz + msg_hdr_sz);
+
+ if ((cdata->msg_hdr.set == MSM_RPM_CTX_SLEEP_SET) &&
+ !msm_rpm_smd_buffer_request(cdata->buf, msg_size,
+ GFP_FLAG(noirq)))
+ return 1;
+
+ cdata->msg_hdr.msg_id = msm_rpm_get_next_msg_id();
+
+ memcpy(cdata->buf + req_hdr_sz, &cdata->msg_hdr, msg_hdr_sz);
+
if (msm_rpm_debug_mask
& (MSM_RPM_LOG_REQUEST_PRETTY | MSM_RPM_LOG_REQUEST_RAW))
msm_rpm_log_request(cdata);
@@ -755,29 +1098,7 @@
msm_rpm_add_wait_list(cdata->msg_hdr.msg_id);
- spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
-
- ret = smd_write_avail(msm_rpm_data.ch_info);
-
- if (ret < 0) {
- pr_err("%s(): SMD not initialized\n", __func__);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
- return 0;
- }
-
- while ((ret < msg_size)) {
- if (!noirq) {
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write,
- flags);
- cpu_relax();
- spin_lock_irqsave(&msm_rpm_data.smd_lock_write, flags);
- } else
- udelay(5);
- ret = smd_write_avail(msm_rpm_data.ch_info);
- }
-
- ret = smd_write(msm_rpm_data.ch_info, &cdata->buf[0], msg_size);
- spin_unlock_irqrestore(&msm_rpm_data.smd_lock_write, flags);
+ ret = msm_rpm_send_smd_buffer(&cdata->buf[0], msg_size, noirq);
if (ret == msg_size) {
trace_rpm_send_message(noirq, cdata->msg_hdr.set,
@@ -958,11 +1279,13 @@
* During power collapse, the rpm driver disables the SMD interrupts to make
* sure that the interrupt doesn't wakes us from sleep.
*/
-int msm_rpm_enter_sleep(void)
+int msm_rpm_enter_sleep(bool print)
{
if (standalone)
return 0;
+ msm_rpm_flush_requests(print);
+
return smd_mask_receive_interrupt(msm_rpm_data.ch_info, true);
}
EXPORT_SYMBOL(msm_rpm_enter_sleep);
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 2945b7b..89335f3 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1001,7 +1001,7 @@
}
/* Set the CPU latency to 501usec to allow low latency PC modes */
- pwr->pm_qos_latency = 3;
+ pwr->pm_qos_latency = 501;
pm_runtime_enable(device->parentdev);
register_early_suspend(&device->display_off);
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 717f763..eaf3519 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -128,6 +128,7 @@
};
#define QUP_MAX_CLK_STATE_RETRIES 300
+#define DEFAULT_CLK_RATE (19200000)
static char const * const i2c_rsrcs[] = {"i2c_clk", "i2c_sda"};
@@ -1235,18 +1236,26 @@
dev->clk_ctl = 0;
dev->pos = 0;
+ if (dev->pdata->src_clk_rate <= 0) {
+ dev_info(&pdev->dev,
+ "No src_clk_rate specified in platfrom data or "
+ "qcom,i2c-src-freq in DT\n");
+ dev_info(&pdev->dev, "Using default clock rate %dHz\n",
+ DEFAULT_CLK_RATE);
+ dev->pdata->src_clk_rate = DEFAULT_CLK_RATE;
+ }
+
+ ret = clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
+ if (ret)
+ dev_info(&pdev->dev, "clk_set_rate(core_clk, %dHz):%d\n",
+ dev->pdata->src_clk_rate, ret);
+
+ clk_prepare_enable(dev->clk);
+ clk_prepare_enable(dev->pclk);
/*
* If bootloaders leave a pending interrupt on certain GSBI's,
* then we reset the core before registering for interrupts.
*/
-
- if (dev->pdata->src_clk_rate > 0)
- clk_set_rate(dev->clk, dev->pdata->src_clk_rate);
- else
- dev->pdata->src_clk_rate = 19200000;
-
- clk_prepare_enable(dev->clk);
- clk_prepare_enable(dev->pclk);
writel_relaxed(1, dev->base + QUP_SW_RESET);
if (qup_i2c_poll_state(dev, 0, true) != 0)
goto err_reset_failed;
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index c447231..abb5bbc 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -1529,7 +1529,7 @@
static ssize_t fwu_sysfs_config_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- unsigned char config_id[8];
+ unsigned char config_id[4];
/* device config id */
fwu->fn_ptr->read(fwu->rmi4_data,
fwu->f34_fd.ctrl_base_addr,
diff --git a/drivers/leds/leds-qpnp.c b/drivers/leds/leds-qpnp.c
index bea6842..fb1882c 100644
--- a/drivers/leds/leds-qpnp.c
+++ b/drivers/leds/leds-qpnp.c
@@ -27,6 +27,7 @@
#define WLED_MOD_EN_REG(base, n) (base + 0x60 + n*0x10)
#define WLED_IDAC_DLY_REG(base, n) (WLED_MOD_EN_REG(base, n) + 0x01)
#define WLED_FULL_SCALE_REG(base, n) (WLED_IDAC_DLY_REG(base, n) + 0x01)
+#define WLED_MOD_SRC_SEL_REG(base, n) (WLED_FULL_SCALE_REG(base, n) + 0x01)
/* wled control registers */
#define WLED_BRIGHTNESS_CNTL_LSB(base, n) (base + 0x40 + 2*n)
@@ -83,7 +84,7 @@
#define FLASH_LED_1_CURR(base) (base + 0x43)
#define FLASH_CLAMP_CURR(base) (base + 0x44)
#define FLASH_LED_TMR_CTRL(base) (base + 0x48)
-#define FLASH_HEADROOM(base) (base + 0x49)
+#define FLASH_HEADROOM(base) (base + 0x4A)
#define FLASH_STARTUP_DELAY(base) (base + 0x4B)
#define FLASH_MASK_ENABLE(base) (base + 0x4C)
#define FLASH_VREG_OK_FORCE(base) (base + 0x4F)
@@ -111,7 +112,7 @@
#define FLASH_ENABLE_MODULE 0x80
#define FLASH_ENABLE_MODULE_MASK 0x80
#define FLASH_DISABLE_ALL 0x00
-#define FLASH_ENABLE_MASK 0x60
+#define FLASH_ENABLE_MASK 0xE0
#define FLASH_ENABLE_LED_0 0x40
#define FLASH_ENABLE_LED_1 0x20
#define FLASH_INIT_MASK 0xE0
@@ -454,6 +455,14 @@
/* Set led current */
if (val > 0) {
+ rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
+ FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Enable reg write failed(%d)\n", rc);
+ return rc;
+ }
+
rc = qpnp_led_masked_write(led, led->flash_cfg->current_addr,
FLASH_CURRENT_MASK, led->flash_cfg->current_prgm);
if (rc) {
@@ -487,6 +496,13 @@
"LED %d flash write failed(%d)\n", led->id, rc);
return rc;
}
+ rc = qpnp_led_masked_write(led, FLASH_VREG_OK_FORCE(led->base),
+ FLASH_VREG_MASK, FLASH_HW_VREG_OK);
+ if (rc) {
+ dev_err(&led->spmi_dev->dev,
+ "Vreg OK reg write failed(%d)\n", rc);
+ return rc;
+ }
} else {
rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
FLASH_ENABLE_MASK,
@@ -755,7 +771,7 @@
if (led->wled_cfg->dig_mod_gen_en) {
rc = qpnp_led_masked_write(led,
- WLED_MOD_EN_REG(led->base, i),
+ WLED_MOD_SRC_SEL_REG(led->base, i),
WLED_NO_MASK, WLED_USE_EXT_GEN_MOD_SRC);
if (rc) {
dev_err(&led->spmi_dev->dev,
@@ -883,7 +899,7 @@
}
rc = qpnp_led_masked_write(led, FLASH_ENABLE_CONTROL(led->base),
- FLASH_ENABLE_MODULE_MASK, FLASH_ENABLE_MODULE);
+ FLASH_ENABLE_MODULE_MASK, FLASH_DISABLE_ALL);
if (rc) {
dev_err(&led->spmi_dev->dev,
"Enable reg write failed(%d)\n", rc);
diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c
index 8e2aa30..125c699 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.c
+++ b/drivers/media/platform/msm/vidc/msm_smem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,7 +26,7 @@
unsigned long align, unsigned long *iova,
unsigned long *buffer_size, int flags)
{
- int rc;
+ int rc = 0;
if (!iova || !buffer_size || !hndl || !clnt) {
dprintk(VIDC_ERR, "Invalid params: %p, %p, %p, %p\n",
clnt, hndl, iova, buffer_size);
@@ -71,6 +71,7 @@
struct ion_handle *hndl;
unsigned long iova = 0;
unsigned long buffer_size = 0;
+ unsigned long ionflags = 0;
int rc = 0;
int align = SZ_4K;
hndl = ion_import_dma_buf(client->clnt, fd);
@@ -84,7 +85,20 @@
mem->domain = domain;
mem->partition_num = partition;
mem->flags = flags;
-
+ rc = ion_handle_get_flags(client->clnt, hndl, &ionflags);
+ if (rc) {
+ dprintk(VIDC_ERR, "Failed to get ion flags: %d\n", rc);
+ goto fail_map;
+ }
+ if (ION_IS_CACHED(ionflags)) {
+ mem->kvaddr = ion_map_kernel(client->clnt, hndl);
+ if (!mem->kvaddr) {
+ dprintk(VIDC_ERR,
+ "Failed to map shared mem in kernel\n");
+ rc = -EIO;
+ goto fail_map;
+ }
+ }
if (flags & SMEM_SECURE)
align = ALIGN(align, SZ_1M);
@@ -103,7 +117,9 @@
mem->device_addr, mem->size);
return rc;
fail_device_address:
- ion_unmap_kernel(client->clnt, hndl);
+ if (mem->kvaddr)
+ ion_unmap_kernel(client->clnt, hndl);
+fail_map:
ion_free(client->clnt, hndl);
fail_import_fd:
return rc;
@@ -243,31 +259,79 @@
return mem;
}
-static int ion_mem_clean_invalidate(struct smem_client *clt,
- struct msm_smem *mem)
+static int ion_cache_operations(struct smem_client *client,
+ struct msm_smem *mem, enum smem_cache_ops cache_op)
{
- /*
- * Note: We're always mapping into iommu as uncached
- * as a result we don't need to flush/clean anything
- */
- return 0;
+ unsigned long ionflag = 0;
+ int rc = 0;
+ int msm_cache_ops = 0;
+ if (!mem || !client) {
+ dprintk(VIDC_ERR, "Invalid params: %p, %p\n",
+ mem, client);
+ return -EINVAL;
+ }
+ rc = ion_handle_get_flags(client->clnt, mem->smem_priv,
+ &ionflag);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "ion_handle_get_flags failed: %d\n", rc);
+ goto cache_op_failed;
+ }
+ if (ION_IS_CACHED(ionflag)) {
+ switch (cache_op) {
+ case SMEM_CACHE_CLEAN:
+ msm_cache_ops = ION_IOC_CLEAN_CACHES;
+ break;
+ case SMEM_CACHE_INVALIDATE:
+ msm_cache_ops = ION_IOC_INV_CACHES;
+ break;
+ case SMEM_CACHE_CLEAN_INVALIDATE:
+ msm_cache_ops = ION_IOC_CLEAN_INV_CACHES;
+ break;
+ default:
+ dprintk(VIDC_ERR, "cache operation not supported\n");
+ rc = -EINVAL;
+ goto cache_op_failed;
+ }
+ if (mem->kvaddr) {
+ rc = msm_ion_do_cache_op(client->clnt,
+ (struct ion_handle *)mem->smem_priv,
+ (unsigned long *) mem->kvaddr,
+ (unsigned long)mem->size,
+ msm_cache_ops);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "cache operation failed %d\n", rc);
+ goto cache_op_failed;
+ }
+ } else {
+ dprintk(VIDC_WARN,
+ "cache operation failed as no kernel mapping\n");
+ }
+ }
+cache_op_failed:
+ return rc;
}
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem)
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+ enum smem_cache_ops cache_op)
{
struct smem_client *client = clt;
- int rc;
- if (!client || !mem) {
- dprintk(VIDC_ERR, "Invalid client/handle passed\n");
+ int rc = 0;
+ if (!client) {
+ dprintk(VIDC_ERR, "Invalid params: %p\n",
+ client);
return -EINVAL;
}
switch (client->mem_type) {
case SMEM_ION:
- rc = ion_mem_clean_invalidate(client, mem);
+ rc = ion_cache_operations(client, mem, cache_op);
+ if (rc)
+ dprintk(VIDC_ERR,
+ "Failed cache operations: %d\n", rc);
break;
default:
dprintk(VIDC_ERR, "Mem type not supported\n");
- rc = -EINVAL;
break;
}
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h
index 6e40bef..d1c8293 100644
--- a/drivers/media/platform/msm/vidc/msm_smem.h
+++ b/drivers/media/platform/msm/vidc/msm_smem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -37,6 +37,13 @@
void *smem_priv;
};
+enum smem_cache_ops {
+ SMEM_CACHE_CLEAN,
+ SMEM_CACHE_INVALIDATE,
+ SMEM_CACHE_CLEAN_INVALIDATE,
+};
+
+
void *msm_smem_new_client(enum smem_type mtype);
struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags,
int domain, int partition, int map_kernel);
@@ -44,5 +51,6 @@
void msm_smem_delete_client(void *clt);
struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, int
domain, int partition, int flags);
-int msm_smem_clean_invalidate(void *clt, struct msm_smem *mem);
+int msm_smem_cache_operations(void *clt, struct msm_smem *mem,
+ enum smem_cache_ops);
#endif
diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
index 6480bf5..54047eb 100644
--- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
+++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c
@@ -181,10 +181,12 @@
err_invalid_input:
return ret;
}
-static u32 device_to_uvaddr(struct list_head *list, u32 device_addr)
+
+static struct buffer_info *device_to_uvaddr(
+ struct list_head *list, u32 device_addr)
{
- struct buffer_info *temp;
- u32 uvaddr = 0;
+ struct buffer_info *temp = NULL;
+ int found = 0;
int i;
if (!list || !device_addr) {
dprintk(VIDC_ERR, "Invalid input\n");
@@ -198,16 +200,16 @@
== device_addr) {
dprintk(VIDC_INFO,
"Found same fd buffer\n");
- uvaddr = temp->uvaddr[i];
+ found = 1;
break;
}
}
- if (uvaddr)
+ if (found)
break;
}
}
err_invalid_input:
- return uvaddr;
+ return temp;
}
static int msm_v4l2_open(struct file *filp)
@@ -544,9 +546,10 @@
b->m.planes[i].m.userptr = binfo->device_addr[i];
dprintk(VIDC_DBG, "Queueing device address = 0x%x\n",
binfo->device_addr[i]);
- if (binfo->handle[i]) {
- rc = msm_smem_clean_invalidate(v4l2_inst->mem_client,
- binfo->handle[i]);
+ if (binfo->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) {
+ rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+ binfo->handle[i], SMEM_CACHE_CLEAN);
if (rc) {
dprintk(VIDC_ERR,
"Failed to clean caches: %d\n", rc);
@@ -566,6 +569,7 @@
int i;
struct msm_v4l2_vid_inst *v4l2_inst;
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
+ struct buffer_info *buffer_info;
if (b->length > VIDEO_MAX_PLANES) {
dprintk(VIDC_ERR, "num planes exceed maximum: %d\n",
b->length);
@@ -585,9 +589,10 @@
!b->m.planes[i].m.userptr) {
continue;
}
- b->m.planes[i].m.userptr = device_to_uvaddr(
+ buffer_info = device_to_uvaddr(
&v4l2_inst->registered_bufs,
b->m.planes[i].m.userptr);
+ b->m.planes[i].m.userptr = buffer_info->uvaddr[i];
if (!b->m.planes[i].m.userptr) {
dprintk(VIDC_ERR,
"Failed to find user virtual address, 0x%lx, %d, %d\n",
@@ -595,6 +600,16 @@
rc = -EINVAL;
goto fail_dq_buf;
}
+ if (buffer_info->handle[i] &&
+ (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
+ rc = msm_smem_cache_operations(v4l2_inst->mem_client,
+ buffer_info->handle[i], SMEM_CACHE_INVALIDATE);
+ if (rc) {
+ dprintk(VIDC_ERR,
+ "Failed to clean caches: %d\n", rc);
+ goto fail_dq_buf;
+ }
+ }
}
fail_dq_buf:
return rc;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index 9f5f5af..6a83334 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -362,9 +362,7 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
struct v4l2_event dqevent;
- struct v4l2_control control = {0};
struct msm_vidc_cb_event *event_notify;
- int rc = 0;
if (response) {
inst = (struct msm_vidc_inst *)response->session_id;
dqevent.id = 0;
@@ -372,16 +370,7 @@
switch (event_notify->hal_event_type) {
case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES:
dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT;
- control.id =
- V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER;
- rc = v4l2_g_ctrl(&inst->ctrl_handler, &control);
- if (rc)
- dprintk(VIDC_WARN,
- "Failed to get Smooth streamng flag\n");
- if (!rc && control.value == true)
- dqevent.type =
- V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
+ V4L2_EVENT_SEQ_CHANGED_SUFFICIENT;
break;
case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES:
dqevent.type =
@@ -1929,6 +1918,12 @@
rc = -ENOMEM;
goto err_no_mem;
}
+ rc = msm_smem_cache_operations(inst->mem_client,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache may cause undefined behavior\n");
+ }
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
dprintk(VIDC_ERR, "Out of memory\n");
@@ -2014,6 +2009,12 @@
rc = -ENOMEM;
goto err_no_mem;
}
+ rc = msm_smem_cache_operations(inst->mem_client,
+ handle, SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN,
+ "Failed to clean cache may cause undefined behavior\n");
+ }
binfo = kzalloc(sizeof(*binfo), GFP_KERNEL);
if (!binfo) {
dprintk(VIDC_ERR, "Out of memory\n");
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 80fc832..da44ec1 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -353,20 +353,19 @@
rc = -ENOMEM;
goto fail_smem_alloc;
}
- rc = msm_smem_clean_invalidate(clnt, alloc);
- if (rc) {
- dprintk(VIDC_ERR, "NOTE: Failed to clean caches\n");
- goto fail_clean_cache;
- }
dprintk(VIDC_DBG, "venus_hfi_alloc:ptr=%p,size=%d",
alloc->kvaddr, size);
+ rc = msm_smem_cache_operations(clnt, alloc,
+ SMEM_CACHE_CLEAN);
+ if (rc) {
+ dprintk(VIDC_WARN, "Failed to clean cache\n");
+ dprintk(VIDC_WARN, "This may result in undefined behavior\n");
+ }
vmem->mem_size = alloc->size;
vmem->mem_data = alloc;
vmem->align_virtual_addr = (u8 *) alloc->kvaddr;
vmem->align_device_addr = (u8 *)alloc->device_addr;
return rc;
-fail_clean_cache:
- msm_smem_free(clnt, alloc);
fail_smem_alloc:
return rc;
}
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 82d58ef..13e23e8 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -136,6 +136,7 @@
int amux_2_trim_delta;
uint16_t prev_last_good_ocv_raw;
int rconn_mohm;
+ int rbatt_capacitive_mohm;
struct mutex last_ocv_uv_mutex;
int last_ocv_uv;
int last_ocv_temp_decidegc;
@@ -847,8 +848,8 @@
{
int ibat_ua, vbat_uv, ocv_est_uv;
int rc;
-
- int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
+ int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm
+ + chip->rbatt_capacitive_mohm;
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
@@ -917,7 +918,10 @@
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
&vbat_uv);
-
+ /*
+ * don't include rbatt and rbatt_capacitve since we expect this to
+ * be used with a fake battery which does not have internal resistnaces
+ */
ocv_est_uv = vbat_uv + (ibat_ua * the_chip->rconn_mohm) / 1000;
pr_debug("forcing ocv to be %d due to bms reset mode\n", ocv_est_uv);
the_chip->last_ocv_uv = ocv_est_uv;
@@ -1072,6 +1076,10 @@
pr_debug("adding rconn_mohm = %d rbatt = %d\n",
the_chip->rconn_mohm, rbatt);
+ rbatt += the_chip->rbatt_capacitive_mohm;
+ pr_debug("adding rbatt_capacitive_mohm = %d rbatt = %d\n",
+ the_chip->rbatt_capacitive_mohm, rbatt);
+
if (is_between(20, 10, soc_rbatt))
rbatt = rbatt
+ ((20 - soc_rbatt) * chip->delta_rbatt_mohm) / 10;
@@ -1583,6 +1591,8 @@
}
EXPORT_SYMBOL(pm8921_bms_get_simultaneous_battery_voltage_and_current);
+#define SIGN(x) ((x) < 0 ? -1 : 1)
+
static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
int batt_temp,
int chargecycles,
@@ -1597,7 +1607,6 @@
int pc, new_pc;
int batt_temp_degc = batt_temp / 10;
int ocv;
- int count = 0;
rc = (s64)shutdown_soc * (fcc_uah - uuc_uah);
rc = div_s64(rc, 100) + cc_uah + uuc_uah;
@@ -1611,17 +1620,55 @@
new_pc = interpolate_pc(chip->pc_temp_ocv_lut, batt_temp_degc, ocv);
pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
- /* try 10 times to get a close enough pc */
- while (abs(new_pc - pc) > 1 && count++ < 10) {
+ if (abs(new_pc - pc) > 0) {
+ /* Maximum spins to make in while-loop when searching in
+ * full resolution.
+ */
+ const unsigned int max_spin_count =
+ chip->max_voltage_uv / 1000 - chip->v_cutoff + 1;
+ unsigned int count = 0;
int delta_mv = 5;
+ int diff = abs(new_pc - pc);
+ char sign = SIGN(new_pc - pc);
+ char old_sign;
+ int old_diff;
+ int old_ocv;
- if (new_pc > pc)
- delta_mv = -1 * delta_mv;
+ do {
+ count++;
+ old_ocv = ocv;
+ old_diff = diff;
+ old_sign = sign;
- ocv = ocv + delta_mv;
- new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
- batt_temp_degc, ocv);
- pr_debug("test revlookup pc = %d for ocv = %d\n", new_pc, ocv);
+ if (new_pc > pc)
+ ocv -= delta_mv;
+ else
+ ocv += delta_mv;
+
+ new_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+ batt_temp_degc, ocv);
+ pr_debug("test revlookup pc = %d for ocv = %d\n",
+ new_pc, ocv);
+ diff = abs(new_pc - pc);
+ sign = SIGN(new_pc - pc);
+
+ if (sign != old_sign) {
+ if (delta_mv == 5) {
+ /*
+ * we crossed our desired PC probably
+ * becuase we were overcorrecting
+ */
+ delta_mv = 1;
+ } else {
+ /* we crossed our desired PC even with
+ * 1mV steps, choose the best of two */
+ if (diff > old_diff)
+ ocv = old_ocv;
+
+ break;
+ }
+ }
+ } while (count <= max_spin_count && diff > 0);
}
*ocv_uv = ocv * 1000;
@@ -2869,6 +2916,8 @@
chip->default_rbatt_mohm
= palladium_1500_data.default_rbatt_mohm;
chip->delta_rbatt_mohm = palladium_1500_data.delta_rbatt_mohm;
+ chip->rbatt_capacitive_mohm
+ = palladium_1500_data.rbatt_capacitive_mohm;
return 0;
desay:
chip->fcc = desay_5200_data.fcc;
@@ -2878,6 +2927,8 @@
chip->rbatt_sf_lut = desay_5200_data.rbatt_sf_lut;
chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm;
chip->delta_rbatt_mohm = desay_5200_data.delta_rbatt_mohm;
+ chip->rbatt_capacitive_mohm
+ = desay_5200_data.rbatt_capacitive_mohm;
return 0;
}
@@ -3008,9 +3059,9 @@
int ret = 0;
struct pm8921_soc_params raw;
- mutex_lock(&the_chip->bms_output_lock);
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
read_soc_params_raw(the_chip, &raw, 300);
- mutex_unlock(&the_chip->bms_output_lock);
+ mutex_lock(&the_chip->last_ocv_uv_mutex);
*val = 0;
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 6135e71..7f60128 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -2375,7 +2375,7 @@
of_property_read_u32(node, "spi-max-frequency",
&pdata->max_clock_speed);
- of_property_read_u32(node, "infinite_mode",
+ of_property_read_u32(node, "qcom,infinite-mode",
&pdata->infinite_mode);
pdata->ver_reg_exists = of_property_read_bool(node
@@ -2485,13 +2485,12 @@
goto err_probe_exit;
}
- rc = of_property_read_u32(pdev->dev.of_node,
- "cell-index", &pdev->id);
- if (rc)
+ rc = of_alias_get_id(pdev->dev.of_node, "spi");
+ if (rc < 0)
dev_warn(&pdev->dev,
"using default bus_num %d\n", pdev->id);
else
- master->bus_num = pdev->id;
+ master->bus_num = pdev->id = rc;
for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 24f3cb1..a09b1ab 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -842,7 +842,7 @@
u32 __iomem *status_reg = &ehci->regs->port_status[
(wIndex & 0xff) - 1];
u32 __iomem *hostpc_reg = NULL;
- u32 temp, temp1, status, cmd = 0;
+ u32 temp, temp1, status;
unsigned long flags;
int retval = 0;
unsigned selector;
@@ -1221,31 +1221,13 @@
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (50);
}
-
- if (ehci->reset_sof_bug && (temp & PORT_RESET)) {
- cmd = ehci_readl(ehci, &ehci->regs->command);
- cmd &= ~CMD_RUN;
- ehci_writel(ehci, cmd, &ehci->regs->command);
- if (handshake(ehci, &ehci->regs->status,
- STS_HALT, STS_HALT, 16 * 125))
- ehci_info(ehci,
- "controller halt failed\n");
- }
- ehci_writel(ehci, temp, status_reg);
- if (ehci->reset_sof_bug && (temp & PORT_RESET)
- && hcd->driver->enable_ulpi_control) {
- hcd->driver->enable_ulpi_control(hcd,
- PORT_RESET);
+ if (ehci->reset_sof_bug && (temp & PORT_RESET) &&
+ hcd->driver->reset_sof_bug_handler) {
spin_unlock_irqrestore(&ehci->lock, flags);
- usleep_range(50000, 55000);
- if (handshake(ehci, status_reg,
- PORT_RESET, 0, 10 * 1000))
- ehci_info(ehci,
- "failed to clear reset\n");
+ hcd->driver->reset_sof_bug_handler(hcd, temp);
spin_lock_irqsave(&ehci->lock, flags);
- hcd->driver->disable_ulpi_control(hcd);
- cmd |= CMD_RUN;
- ehci_writel(ehci, cmd, &ehci->regs->command);
+ } else {
+ ehci_writel(ehci, temp, status_reg);
}
break;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 3ec158b..a559ccf 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -101,6 +101,8 @@
struct completion rt_completion;
int resume_status;
int resume_again;
+ int bus_reset;
+ int reset_again;
struct pm_qos_request pm_qos_req_dma;
};
@@ -430,7 +432,7 @@
}
-static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
+static int __maybe_unused ulpi_read(struct msm_hsic_hcd *mehci, u32 reg)
{
struct usb_hcd *hcd = hsic_to_hcd(mehci);
int cnt = 0;
@@ -501,37 +503,6 @@
return 0;
}
-#define HSIC_DBG1 0X38
-#define ULPI_MANUAL_ENABLE BIT(4)
-#define ULPI_LINESTATE_DATA BIT(5)
-#define ULPI_LINESTATE_STROBE BIT(6)
-static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate)
-{
- struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
- int val;
-
- switch (linestate) {
- case PORT_RESET:
- val = ulpi_read(mehci, HSIC_DBG1);
- val |= ULPI_MANUAL_ENABLE;
- val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE);
- ulpi_write(mehci, val, HSIC_DBG1);
- break;
- default:
- pr_info("%s: Unknown linestate:%0x\n", __func__, linestate);
- }
-}
-
-static void ehci_msm_disable_ulpi_control(struct usb_hcd *hcd)
-{
- struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
- int val;
-
- val = ulpi_read(mehci, HSIC_DBG1);
- val &= ~ULPI_MANUAL_ENABLE;
- ulpi_write(mehci, val, HSIC_DBG1);
-}
-
static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en)
{
int rc = 0;
@@ -955,6 +926,26 @@
__func__, ret);
}
+static int msm_hsic_reset_done(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ u32 __iomem *status_reg = &ehci->regs->port_status[0];
+ int ret;
+
+ ehci_writel(ehci, ehci_readl(ehci, status_reg) & ~(PORT_RWC_BITS |
+ PORT_RESET), status_reg);
+
+ ret = handshake(ehci, status_reg, PORT_RESET, 0, 1 * 1000);
+
+ if (ret)
+ pr_err("reset handshake failed in %s\n", __func__);
+ else
+ ehci_writel(ehci, ehci_readl(ehci, &ehci->regs->command) |
+ CMD_RUN, &ehci->regs->command);
+
+ return ret;
+}
+
#define STS_GPTIMER0_INTERRUPT BIT(24)
static irqreturn_t msm_hsic_irq(struct usb_hcd *hcd)
{
@@ -982,16 +973,28 @@
if (status & STS_GPTIMER0_INTERRUPT) {
int timeleft;
- dbg_log_event(NULL, "FPR: gpt0_isr", 0);
+ dbg_log_event(NULL, "FPR: gpt0_isr", mehci->bus_reset);
timeleft = GPT_CNT(ehci_readl(ehci,
&mehci->timer->gptimer1_ctrl));
if (timeleft) {
- ehci_writel(ehci, ehci_readl(ehci,
- &ehci->regs->command) | CMD_RUN,
- &ehci->regs->command);
- } else
- mehci->resume_again = 1;
+ if (mehci->bus_reset) {
+ ret = msm_hsic_reset_done(hcd);
+ if (ret) {
+ mehci->reset_again = 1;
+ dbg_log_event(NULL, "RESET: fail", 0);
+ }
+ } else {
+ ehci_writel(ehci, ehci_readl(ehci,
+ &ehci->regs->command) | CMD_RUN,
+ &ehci->regs->command);
+ }
+ } else {
+ if (mehci->bus_reset)
+ mehci->reset_again = 1;
+ else
+ mehci->resume_again = 1;
+ }
dbg_log_event(NULL, "FPR: timeleft", timeleft);
@@ -1047,6 +1050,83 @@
#ifdef CONFIG_PM
+#define RESET_RETRY_LIMIT 3
+#define RESET_SIGNAL_TIME_SOF_USEC (50 * 1000)
+#define RESET_SIGNAL_TIME_USEC (20 * 1000)
+static void ehci_hsic_reset_sof_bug_handler(struct usb_hcd *hcd, u32 val)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+ u32 __iomem *status_reg = &ehci->regs->port_status[0];
+ unsigned long flags;
+ int retries = 0, ret, cnt = RESET_SIGNAL_TIME_USEC;
+
+ if (pdata && pdata->swfi_latency)
+ pm_qos_update_request(&mehci->pm_qos_req_dma,
+ pdata->swfi_latency + 1);
+
+ mehci->bus_reset = 1;
+retry:
+ retries++;
+ dbg_log_event(NULL, "RESET: start", retries);
+ pr_debug("reset begin %d\n", retries);
+ mehci->reset_again = 0;
+ spin_lock_irqsave(&ehci->lock, flags);
+ ehci_writel(ehci, val, status_reg);
+ ehci_writel(ehci, GPT_LD(RESET_SIGNAL_TIME_USEC - 1),
+ &mehci->timer->gptimer0_ld);
+ ehci_writel(ehci, GPT_RESET | GPT_RUN,
+ &mehci->timer->gptimer0_ctrl);
+ ehci_writel(ehci, INTR_MASK | STS_GPTIMER0_INTERRUPT,
+ &ehci->regs->intr_enable);
+
+ ehci_writel(ehci, GPT_LD(RESET_SIGNAL_TIME_SOF_USEC - 1),
+ &mehci->timer->gptimer1_ld);
+ ehci_writel(ehci, GPT_RESET | GPT_RUN,
+ &mehci->timer->gptimer1_ctrl);
+
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ wait_for_completion(&mehci->gpt0_completion);
+
+ if (!mehci->reset_again)
+ goto done;
+
+ if (handshake(ehci, status_reg, PORT_RESET, 0, 10 * 1000)) {
+ pr_err("reset handshake fatal error\n");
+ dbg_log_event(NULL, "RESET: fatal", retries);
+ goto fail;
+ }
+
+ if (retries < RESET_RETRY_LIMIT)
+ goto retry;
+
+ /* complete reset in tight loop */
+ pr_info("RESET in tight loop\n");
+ dbg_log_event(NULL, "RESET: tight", 0);
+
+ spin_lock_irqsave(&ehci->lock, flags);
+ ehci_writel(ehci, val, status_reg);
+ while (cnt--)
+ udelay(1);
+ ret = msm_hsic_reset_done(hcd);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ if (ret) {
+ pr_err("RESET in tight loop failed\n");
+ dbg_log_event(NULL, "RESET: tight failed", 0);
+ goto fail;
+ }
+
+done:
+ dbg_log_event(NULL, "RESET: done", retries);
+ pr_debug("reset completed\n");
+fail:
+ mehci->bus_reset = 0;
+ if (pdata && pdata->swfi_latency)
+ pm_qos_update_request(&mehci->pm_qos_req_dma,
+ PM_QOS_DEFAULT_VALUE);
+}
+
static int ehci_hsic_bus_suspend(struct usb_hcd *hcd)
{
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
@@ -1321,10 +1401,8 @@
.log_urb = dbg_log_event,
.dump_regs = dump_hsic_regs,
- .enable_ulpi_control = ehci_msm_enable_ulpi_control,
- .disable_ulpi_control = ehci_msm_disable_ulpi_control,
-
.set_autosuspend_delay = ehci_msm_set_autosuspend_delay,
+ .reset_sof_bug_handler = ehci_hsic_reset_sof_bug_handler,
};
static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index e1e82fd..5c89938 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -417,9 +417,6 @@
mfd->op_enable);
if (ret)
pr_warn("can't turn on display!\n");
-
- if (mfd->vsync_pending)
- mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
}
mfd->is_power_setting = false;
complete_all(&mfd->power_set_comp);
@@ -1043,16 +1040,23 @@
void mdss_fb_wait_for_fence(struct msm_fb_data_type *mfd)
{
- int i, ret;
+ int i, ret = 0;
/* buf sync */
for (i = 0; i < mfd->acq_fen_cnt; i++) {
ret = sync_fence_wait(mfd->acq_fen[i], WAIT_FENCE_TIMEOUT);
- sync_fence_put(mfd->acq_fen[i]);
if (ret < 0) {
pr_err("%s: sync_fence_wait failed! ret = %x\n",
__func__, ret);
break;
}
+ sync_fence_put(mfd->acq_fen[i]);
+ }
+
+ if (ret < 0) {
+ while (i < mfd->acq_fen_cnt) {
+ sync_fence_put(mfd->acq_fen[i]);
+ i++;
+ }
}
mfd->acq_fen_cnt = 0;
}
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 455f725..5158974 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -32,8 +32,6 @@
#define MAX_MIXER_HEIGHT 2400
#define MAX_IMG_WIDTH 0x3FFF
#define MAX_IMG_HEIGHT 0x3FFF
-#define MIN_DST_W 10
-#define MIN_DST_H 10
#define MAX_DST_W MAX_MIXER_WIDTH
#define MAX_DST_H MAX_MIXER_HEIGHT
#define MAX_PLANES 4
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index a8764cb..0c891f9 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -57,10 +57,19 @@
struct mdss_mdp_format_params *fmt)
{
u32 xres, yres;
+ u32 min_src_size, min_dst_size;
xres = mfd->fbi->var.xres;
yres = mfd->fbi->var.yres;
+ if (mfd->mdata->mdp_rev >= MDSS_MDP_HW_REV_102) {
+ min_src_size = fmt->is_yuv ? 2 : 1;
+ min_dst_size = 1;
+ } else {
+ min_src_size = fmt->is_yuv ? 10 : 5;
+ min_dst_size = 2;
+ }
+
if (req->z_order >= MDSS_MDP_MAX_STAGE) {
pr_err("zorder %d out of range\n", req->z_order);
return -ERANGE;
@@ -68,7 +77,7 @@
if (req->src.width > MAX_IMG_WIDTH ||
req->src.height > MAX_IMG_HEIGHT ||
- req->src_rect.w == 0 || req->src_rect.h == 0 ||
+ req->src_rect.w < min_src_size || req->src_rect.h < min_src_size ||
CHECK_BOUNDS(req->src_rect.x, req->src_rect.w, req->src.width) ||
CHECK_BOUNDS(req->src_rect.y, req->src_rect.h, req->src.height)) {
pr_err("invalid source image img wh=%dx%d rect=%d,%d,%d,%d\n",
@@ -78,7 +87,7 @@
return -EOVERFLOW;
}
- if (req->dst_rect.w < MIN_DST_W || req->dst_rect.h < MIN_DST_H ||
+ if (req->dst_rect.w < min_dst_size || req->dst_rect.h < min_dst_size ||
req->dst_rect.w > MAX_DST_W || req->dst_rect.h > MAX_DST_H) {
pr_err("invalid destination resolution (%dx%d)",
req->dst_rect.w, req->dst_rect.h);
@@ -151,10 +160,6 @@
pr_err("invalid odd src resolution or coordinates\n");
return -EINVAL;
}
- if ((req->dst_rect.w & 0x1) || (req->dst_rect.h & 0x1)) {
- pr_err("invalid odd dst resolution\n");
- return -EINVAL;
- }
}
return 0;
@@ -265,14 +270,16 @@
pipe->params_changed = true;
}
- if (req->id == MSMFB_NEW_REQUEST) {
- mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
- if (!mixer) {
- pr_err("unable to get mixer\n");
- return -ENODEV;
- }
+ mixer = mdss_mdp_mixer_get(mfd->ctl, mixer_mux);
+ if (!mixer) {
+ pr_err("unable to get mixer\n");
+ return -ENODEV;
+ }
- if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
+ if (req->id == MSMFB_NEW_REQUEST) {
+ if (req->flags & MDP_OV_PIPE_FORCE_DMA)
+ pipe_type = MDSS_MDP_PIPE_TYPE_DMA;
+ else if (fmt->is_yuv || (req->flags & MDP_OV_PIPE_SHARE))
pipe_type = MDSS_MDP_PIPE_TYPE_VIG;
else
pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
@@ -308,6 +315,21 @@
pr_err("invalid pipe ndx=%x\n", req->id);
return pipe ? PTR_ERR(pipe) : -ENODEV;
}
+
+ if (pipe->mixer != mixer) {
+ if (!mixer->ctl || (mixer->ctl->mfd != mfd)) {
+ pr_err("Can't switch mixer %d->%d pnum %d!\n",
+ pipe->mixer->num, mixer->num,
+ pipe->num);
+ mdss_mdp_pipe_unmap(pipe);
+ return -EINVAL;
+ }
+ pr_debug("switching pipe mixer %d->%d pnum %d\n",
+ pipe->mixer->num, mixer->num,
+ pipe->num);
+ mdss_mdp_mixer_pipe_unstage(pipe);
+ pipe->mixer = mixer;
+ }
}
pipe->flags = req->flags;
@@ -415,25 +437,28 @@
int num_planes,
u32 flags)
{
- int i;
+ int i, rc = 0;
+
+ if ((num_planes <= 0) || (num_planes > MAX_PLANES))
+ return -EINVAL;
memset(data, 0, sizeof(*data));
for (i = 0; i < num_planes; i++) {
data->p[i].flags = flags;
- mdss_mdp_get_img(&planes[i], &data->p[i]);
- if (data->p[0].len == 0)
+ rc = mdss_mdp_get_img(&planes[i], &data->p[i]);
+ if (rc) {
+ pr_err("failed to map buf p=%d flags=%x\n", i, flags);
+ while (i > 0) {
+ i--;
+ mdss_mdp_put_img(&data->p[i]);
+ }
break;
+ }
}
- if (i != num_planes) {
- for (; i >= 0; i--)
- mdss_mdp_put_img(&data->p[i]);
- return -ENOMEM;
- }
+ data->num_planes = i;
- data->num_planes = num_planes;
-
- return 0;
+ return rc;
}
static inline int mdss_mdp_overlay_free_buf(struct mdss_mdp_data *data)
@@ -645,26 +670,24 @@
ret = mdss_mdp_overlay_get_buf(mfd, &src_data, &req->data, 1, flgs);
if (ret) {
pr_err("src_data pmem error\n");
- goto rotate_done;
+ return ret;
}
ret = mdss_mdp_overlay_get_buf(mfd, &dst_data, &req->dst_data, 1, flgs);
if (ret) {
pr_err("dst_data pmem error\n");
- goto rotate_done;
+ goto dst_buf_fail;
}
ret = mdss_mdp_rotator_queue(rot, &src_data, &dst_data);
- if (ret) {
+ if (ret)
pr_err("rotator queue error session id=%x\n", req->id);
- goto rotate_done;
- }
-rotate_done:
mdss_mdp_overlay_free_buf(&dst_data);
+dst_buf_fail:
mdss_mdp_overlay_free_buf(&src_data);
- return 0;
+ return ret;
}
static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd,
@@ -1307,6 +1330,11 @@
rc = mdss_mdp_ctl_start(mfd->ctl);
if (rc == 0) {
atomic_inc(&ov_active_panels);
+
+ if (mfd->vsync_pending) {
+ mfd->vsync_pending = 0;
+ mdss_mdp_overlay_vsync_ctrl(mfd, mfd->vsync_pending);
+ }
} else {
mdss_mdp_ctl_destroy(mfd->ctl);
mfd->ctl = NULL;
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index 5ff1cfb..f27ceca 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -89,6 +89,8 @@
* readings from bms are not available.
* @delta_rbatt_mohm: the resistance to be added towards lower soc to
* compensate for battery capacitance.
+ * @rbatt_capacitve_mohm: the resistance to be added to compensate for
+ * battery capacitance
*/
struct bms_battery_data {
@@ -100,6 +102,7 @@
struct sf_lut *rbatt_sf_lut;
int default_rbatt_mohm;
int delta_rbatt_mohm;
+ int rbatt_capacitive_mohm;
};
#if defined(CONFIG_PM8921_BMS) || \
diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h
index 3ec966b..32f71a1 100644
--- a/include/linux/msm_mdp.h
+++ b/include/linux/msm_mdp.h
@@ -166,6 +166,7 @@
#define MDP_BACKEND_COMPOSITION 0x00040000
#define MDP_BORDERFILL_SUPPORTED 0x00010000
#define MDP_SECURE_OVERLAY_SESSION 0x00008000
+#define MDP_OV_PIPE_FORCE_DMA 0x00004000
#define MDP_MEMORY_ID_TYPE_FB 0x00001000
#define MDP_TRANSP_NOP 0xffffffff
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 268aa48..4fb20f6 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -349,9 +349,8 @@
/* to log submission/completion events*/
void (*log_urb)(struct urb *urb, char *event, unsigned extra);
void (*dump_regs)(struct usb_hcd *);
- void (*enable_ulpi_control)(struct usb_hcd *hcd, u32 linestate);
- void (*disable_ulpi_control)(struct usb_hcd *hcd);
void (*set_autosuspend_delay)(struct usb_device *);
+ void (*reset_sof_bug_handler)(struct usb_hcd *hcd, u32 val);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 28be822..1746502 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -2169,45 +2169,44 @@
{
struct snd_soc_codec *codec = w->codec;
struct taiko_priv *taiko = snd_soc_codec_get_drvdata(codec);
- u16 micb_int_reg;
+ u16 micb_int_reg = 0, micb_ctl_reg = 0;
u8 cfilt_sel_val = 0;
char *internal1_text = "Internal1";
char *internal2_text = "Internal2";
char *internal3_text = "Internal3";
enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
- pr_debug("%s %d\n", __func__, event);
- switch (w->reg) {
- case TAIKO_A_MICB_1_CTL:
+ pr_debug("%s: w->name %s event %d\n", __func__, w->name, event);
+ if (strnstr(w->name, "MIC BIAS1", sizeof("MIC BIAS1"))) {
+ micb_ctl_reg = TAIKO_A_MICB_1_CTL;
micb_int_reg = TAIKO_A_MICB_1_INT_RBIAS;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias1_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
- break;
- case TAIKO_A_MICB_2_CTL:
+ } else if (strnstr(w->name, "MIC BIAS2", sizeof("MIC BIAS2"))) {
+ micb_ctl_reg = TAIKO_A_MICB_2_CTL;
micb_int_reg = TAIKO_A_MICB_2_INT_RBIAS;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias2_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
- break;
- case TAIKO_A_MICB_3_CTL:
+ } else if (strnstr(w->name, "MIC BIAS3", sizeof("MIC BIAS3"))) {
+ micb_ctl_reg = TAIKO_A_MICB_2_CTL;
micb_int_reg = TAIKO_A_MICB_3_INT_RBIAS;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias3_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
- break;
- case TAIKO_A_MICB_4_CTL:
+ } else if (strnstr(w->name, "MIC BIAS4", sizeof("MIC BIAS4"))) {
+ micb_ctl_reg = TAIKO_A_MICB_2_CTL;
micb_int_reg = taiko->resmgr.reg_addr->micb_4_int_rbias;
cfilt_sel_val = taiko->resmgr.pdata->micbias.bias4_cfilt_sel;
e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_4_ON;
e_post_on = WCD9XXX_EVENT_POST_MICBIAS_4_ON;
e_post_off = WCD9XXX_EVENT_POST_MICBIAS_4_OFF;
- break;
- default:
- pr_err("%s: Error, invalid micbias register\n", __func__);
+ } else {
+ pr_err("%s: Error, invalid micbias %s\n", __func__, w->name);
return -EINVAL;
}
@@ -2226,6 +2225,16 @@
else if (strnstr(w->name, internal3_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+ if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+ WCD9XXX_BCL_LOCK(&taiko->resmgr);
+ wcd9xxx_resmgr_add_cond_update_bits(&taiko->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, w->shift,
+ false);
+ WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+ } else
+ snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
+ 1 << w->shift);
break;
case SND_SOC_DAPM_POST_PMU:
usleep_range(20000, 20000);
@@ -2233,6 +2242,16 @@
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_on);
break;
case SND_SOC_DAPM_POST_PMD:
+ if (micb_ctl_reg == TAIKO_A_MICB_2_CTL) {
+ WCD9XXX_BCL_LOCK(&taiko->resmgr);
+ wcd9xxx_resmgr_rm_cond_update_bits(&taiko->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ micb_ctl_reg, 7, false);
+ WCD9XXX_BCL_UNLOCK(&taiko->resmgr);
+ } else
+ snd_soc_update_bits(codec, micb_ctl_reg, 1 << w->shift,
+ 0);
+
/* Let MBHC module know so micbias switch to be off */
wcd9xxx_resmgr_notifier_call(&taiko->resmgr, e_post_off);
@@ -4220,15 +4239,18 @@
SND_SOC_DAPM_INPUT("AMIC1"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAIKO_A_MICB_1_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAIKO_A_MICB_1_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAIKO_A_MICB_1_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC1", NULL, TAIKO_A_TX_1_2_EN, 7, 0,
taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
@@ -4311,31 +4333,38 @@
SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
SND_SOC_DAPM_INPUT("AMIC2"),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAIKO_A_MICB_2_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAIKO_A_MICB_2_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAIKO_A_MICB_2_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAIKO_A_MICB_2_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAIKO_A_MICB_3_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAIKO_A_MICB_3_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAIKO_A_MICB_3_CTL, 7, 0,
- taiko_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TAIKO_A_MICB_4_CTL, 7,
- 0, taiko_codec_enable_micbias,
- SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", SND_SOC_NOPM, 7, 0,
+ taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", SND_SOC_NOPM, 7,
+ 0, taiko_codec_enable_micbias,
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC2", NULL, TAIKO_A_TX_1_2_EN, 3, 0,
taiko_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index a358be1..b3549cc 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -374,8 +374,14 @@
}
}
-static void wcd9xxx_jack_report(struct snd_soc_jack *jack, int status, int mask)
+static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
+ struct snd_soc_jack *jack, int status, int mask)
{
+ if (jack == &mbhc->headset_jack)
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH_MIC,
+ status & SND_JACK_MICROPHONE);
+
snd_soc_jack_report_no_dapm(jack, status, mask);
}
@@ -388,7 +394,7 @@
codec = mbhc->codec;
if (mbhc->hph_status & jack_status) {
mbhc->hph_status &= ~jack_status;
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD9XXX_JACK_MASK);
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
0x00);
@@ -618,14 +624,14 @@
else if (mbhc->buttons_pressed) {
pr_debug("%s: release of button press%d\n",
__func__, jack_type);
- wcd9xxx_jack_report(&mbhc->button_jack, 0,
+ wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
mbhc->buttons_pressed);
mbhc->buttons_pressed &=
~WCD9XXX_JACK_BUTTON_MASK;
}
pr_debug("%s: Reporting removal %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
- wcd9xxx_jack_report(&mbhc->headset_jack, mbhc->hph_status,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
WCD9XXX_JACK_MASK);
wcd9xxx_set_and_turnoff_hph_padac(mbhc);
hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
@@ -638,7 +644,7 @@
if (mbhc->hph_status && mbhc->hph_status != jack_type) {
pr_debug("%s: Reporting removal (%x)\n",
__func__, mbhc->hph_status);
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
0, WCD9XXX_JACK_MASK);
mbhc->hph_status = 0;
}
@@ -658,7 +664,7 @@
}
pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
jack_type, mbhc->hph_status);
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD9XXX_JACK_MASK);
wcd9xxx_clr_and_turnon_hph_padac(mbhc);
}
@@ -1606,6 +1612,14 @@
pr_debug("%s: enter, removal interrupt\n", __func__);
WCD9XXX_BCL_LOCK(mbhc->resmgr);
+ /*
+ * While we don't know whether MIC is there or not, let the resmgr know
+ * so micbias can be disabled temporarily
+ */
+ if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH_MIC, false);
+
vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
mbhc->mbhc_micbias_switched);
if (vddio)
@@ -1624,6 +1638,10 @@
*/
if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
__wcd9xxx_switch_micbias(mbhc, 1, true, true);
+
+ if (mbhc->current_plug == PLUG_TYPE_HEADSET)
+ wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
+ WCD9XXX_COND_HPH_MIC, true);
WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
return IRQ_HANDLED;
@@ -1679,7 +1697,7 @@
pr_debug("%s: STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
pr_debug("%s: Reporting long button press event\n", __func__);
- wcd9xxx_jack_report(&mbhc->button_jack, mbhc->buttons_pressed,
+ wcd9xxx_jack_report(mbhc, &mbhc->button_jack, mbhc->buttons_pressed,
mbhc->buttons_pressed);
pr_debug("%s: leave\n", __func__);
@@ -2357,7 +2375,7 @@
if (ret == 0) {
pr_debug("%s: Reporting long button release event\n",
__func__);
- wcd9xxx_jack_report(&mbhc->button_jack, 0,
+ wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
mbhc->buttons_pressed);
} else {
if (wcd9xxx_is_fake_press(mbhc)) {
@@ -2370,12 +2388,14 @@
} else {
pr_debug("%s: Reporting btn press\n",
__func__);
- wcd9xxx_jack_report(&mbhc->button_jack,
+ wcd9xxx_jack_report(mbhc,
+ &mbhc->button_jack,
mbhc->buttons_pressed,
mbhc->buttons_pressed);
pr_debug("%s: Reporting btn release\n",
__func__);
- wcd9xxx_jack_report(&mbhc->button_jack,
+ wcd9xxx_jack_report(mbhc,
+ &mbhc->button_jack,
0, mbhc->buttons_pressed);
}
}
@@ -2414,7 +2434,7 @@
WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
mbhc->hphlocp_cnt = 0;
mbhc->hph_status |= SND_JACK_OC_HPHL;
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status,
WCD9XXX_JACK_MASK);
}
@@ -2443,7 +2463,7 @@
WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
mbhc->hphrocp_cnt = 0;
mbhc->hph_status |= SND_JACK_OC_HPHR;
- wcd9xxx_jack_report(&mbhc->headset_jack,
+ wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
mbhc->hph_status, WCD9XXX_JACK_MASK);
}
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.c b/sound/soc/codecs/wcd9xxx-resmgr.c
index 17edd4a..2011346 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.c
+++ b/sound/soc/codecs/wcd9xxx-resmgr.c
@@ -94,6 +94,14 @@
"WCD9XXX_EVENT_LAST",
};
+struct wcd9xxx_resmgr_cond_entry {
+ unsigned short reg;
+ int shift;
+ bool invert;
+ enum wcd9xxx_resmgr_cond cond;
+ struct list_head list;
+};
+
static enum wcd9xxx_clock_type wcd9xxx_save_clock(struct wcd9xxx_resmgr
*resmgr);
static void wcd9xxx_restore_clock(struct wcd9xxx_resmgr *resmgr,
@@ -640,6 +648,93 @@
return rc;
}
+void wcd9xxx_resmgr_cond_trigger_cond(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond)
+{
+ struct list_head *l;
+ struct wcd9xxx_resmgr_cond_entry *e;
+ bool set;
+
+ pr_debug("%s: enter\n", __func__);
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ set = !!test_bit(cond, &resmgr->cond_flags);
+ list_for_each(l, &resmgr->update_bit_cond_h) {
+ e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
+ if (e->cond == cond)
+ snd_soc_update_bits(resmgr->codec, e->reg,
+ 1 << e->shift,
+ (set ? !e->invert : e->invert)
+ << e->shift);
+ }
+ pr_debug("%s: leave\n", __func__);
+}
+
+void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond, bool set)
+{
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ if ((set && !test_and_set_bit(cond, &resmgr->cond_flags)) ||
+ (!set && test_and_clear_bit(cond, &resmgr->cond_flags))) {
+ pr_debug("%s: Resource %d condition changed to %s\n", __func__,
+ cond, set ? "set" : "clear");
+ wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+ }
+}
+
+int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond,
+ unsigned short reg, int shift,
+ bool invert)
+{
+ struct wcd9xxx_resmgr_cond_entry *entry;
+
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->cond = cond;
+ entry->reg = reg;
+ entry->shift = shift;
+ entry->invert = invert;
+ list_add_tail(&entry->list, &resmgr->update_bit_cond_h);
+
+ wcd9xxx_resmgr_cond_trigger_cond(resmgr, cond);
+
+ return 0;
+}
+
+/*
+ * wcd9xxx_resmgr_rm_cond_update_bits :
+ * Clear bit and remove from the conditional bit update list
+ */
+int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond,
+ unsigned short reg, int shift,
+ bool invert)
+{
+ struct list_head *l, *next;
+ struct wcd9xxx_resmgr_cond_entry *e = NULL;
+
+ pr_debug("%s: enter\n", __func__);
+ WCD9XXX_BCL_ASSERT_LOCKED(resmgr);
+ list_for_each_safe(l, next, &resmgr->update_bit_cond_h) {
+ e = list_entry(l, struct wcd9xxx_resmgr_cond_entry, list);
+ if (e->reg == reg && e->shift == shift && e->invert == invert) {
+ snd_soc_update_bits(resmgr->codec, e->reg,
+ 1 << e->shift,
+ e->invert << e->shift);
+ list_del(&e->list);
+ kfree(e);
+ return 0;
+ }
+ }
+ pr_err("%s: Cannot find update bit entry reg 0x%x, shift %d\n",
+ __func__, e ? e->reg : 0, e ? e->shift : 0);
+
+ return -EINVAL;
+}
+
int wcd9xxx_resmgr_register_notifier(struct wcd9xxx_resmgr *resmgr,
struct notifier_block *nblock)
{
@@ -669,6 +764,8 @@
resmgr->pdata = pdata;
resmgr->reg_addr = reg_addr;
+ INIT_LIST_HEAD(&resmgr->update_bit_cond_h);
+
BLOCKING_INIT_NOTIFIER_HEAD(&resmgr->notifier);
mutex_init(&resmgr->codec_resource_lock);
diff --git a/sound/soc/codecs/wcd9xxx-resmgr.h b/sound/soc/codecs/wcd9xxx-resmgr.h
index 6c30eeb..53c48f6 100644
--- a/sound/soc/codecs/wcd9xxx-resmgr.h
+++ b/sound/soc/codecs/wcd9xxx-resmgr.h
@@ -125,6 +125,9 @@
/* Notifier needs mbhc pointer with resmgr */
struct wcd9xxx_mbhc *mbhc;
+ unsigned long cond_flags;
+ struct list_head update_bit_cond_h;
+
/*
* Currently, only used for mbhc purpose, to protect
* concurrent execution of mbhc threaded irq handlers and
@@ -189,4 +192,18 @@
void wcd9xxx_resmgr_notifier_call(struct wcd9xxx_resmgr *resmgr,
const enum wcd9xxx_notify_event e);
+enum wcd9xxx_resmgr_cond {
+ WCD9XXX_COND_HPH_MIC = 1,
+};
+int wcd9xxx_resmgr_rm_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond,
+ unsigned short reg, int shift,
+ bool invert);
+int wcd9xxx_resmgr_add_cond_update_bits(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond,
+ unsigned short reg, int shift,
+ bool invert);
+void wcd9xxx_resmgr_cond_update_cond(struct wcd9xxx_resmgr *resmgr,
+ enum wcd9xxx_resmgr_cond cond, bool set);
+
#endif /* __WCD9XXX_COMMON_H__ */
diff --git a/sound/soc/msm/qdsp6v2/audio_ocmem.c b/sound/soc/msm/qdsp6v2/audio_ocmem.c
index 145f095..1969fe8 100644
--- a/sound/soc/msm/qdsp6v2/audio_ocmem.c
+++ b/sound/soc/msm/qdsp6v2/audio_ocmem.c
@@ -30,6 +30,15 @@
#define AUDIO_OCMEM_BUF_SIZE (512 * SZ_1K)
+#define _BIT_MASK_\
+ ((1 << OCMEM_STATE_EXIT) |\
+ (1 << OCMEM_STATE_GROW) |\
+ (1 << OCMEM_STATE_SHRINK))
+
+#define set_bit_pos(x, y) (atomic_set(&x, (atomic_read(&x) | (1 << y))))
+#define clear_bit_pos(x, y) (atomic_set(&x, (atomic_read(&x) & (~(1 << y)))))
+#define test_bit_pos(x, y) ((atomic_read(&x)) & (1 << y))
+
static int enable_ocmem_audio_voice = 1;
module_param(enable_ocmem_audio_voice, int,
S_IRUGO | S_IWUSR | S_IWGRP);
@@ -48,6 +57,8 @@
OCMEM_STATE_MAP_FAIL,
OCMEM_STATE_UNMAP_FAIL,
OCMEM_STATE_EXIT,
+ OCMEM_STATE_SSR,
+ OCMEM_STATE_DISABLE,
};
static void audio_ocmem_process_workdata(struct work_struct *work);
@@ -74,6 +85,7 @@
atomic_t audio_cond;
atomic_t audio_exit;
spinlock_t audio_lock;
+ struct mutex protect_lock;
struct workqueue_struct *audio_ocmem_workqueue;
struct workqueue_struct *voice_ocmem_workqueue;
bool ocmem_en;
@@ -81,7 +93,6 @@
static struct audio_ocmem_prv audio_ocmem_lcl;
-
static int audio_ocmem_client_cb(struct notifier_block *this,
unsigned long event1, void *data)
{
@@ -97,7 +108,9 @@
switch (event1) {
case OCMEM_MAP_DONE:
pr_debug("%s: map done\n", __func__);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_COMPL);
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_TRANSITION);
+ set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_COMPL);
break;
case OCMEM_MAP_FAIL:
pr_debug("%s: map fail\n", __func__);
@@ -105,7 +118,9 @@
break;
case OCMEM_UNMAP_DONE:
pr_debug("%s: unmap done\n", __func__);
- atomic_set(&audio_ocmem_lcl.audio_state,
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_TRANSITION);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
OCMEM_STATE_UNMAP_COMPL);
break;
case OCMEM_UNMAP_FAIL:
@@ -115,13 +130,13 @@
break;
case OCMEM_ALLOC_GROW:
rbuf = data;
- if (rbuf->len == AUDIO_OCMEM_BUF_SIZE) {
+ if ((rbuf->len == AUDIO_OCMEM_BUF_SIZE)) {
audio_ocmem_lcl.buf = data;
pr_debug("%s: Alloc grow request received buf->addr: 0x%08lx\n",
__func__,
(audio_ocmem_lcl.buf)->addr);
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_GROW);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_GROW);
} else {
pr_debug("%s: Alloc grow request with size: %ld",
__func__,
@@ -132,19 +147,33 @@
break;
case OCMEM_ALLOC_SHRINK:
pr_debug("%s: Alloc shrink request received\n", __func__);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_SHRINK);
+ set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_SHRINK);
break;
default:
pr_err("%s: Invalid event[%ld]\n", __func__, event1);
break;
}
spin_unlock_irqrestore(&audio_ocmem_lcl.audio_lock, flags);
- if (!vwait && (atomic_read(&audio_ocmem_lcl.audio_cond))) {
atomic_set(&audio_ocmem_lcl.audio_cond, 0);
wake_up(&audio_ocmem_lcl.audio_wait);
- }
return rc;
}
+int get_state_to_process(atomic_t *state)
+{
+
+ if (test_bit_pos((*state), OCMEM_STATE_SHRINK)) {
+ pr_debug("%s: returning shrink state\n", __func__);
+ return OCMEM_STATE_SHRINK;
+ } else if (test_bit_pos((*state), OCMEM_STATE_GROW)) {
+ pr_debug("%s: returning grow state\n", __func__);
+ return OCMEM_STATE_GROW;
+ } else if (test_bit_pos((*state), OCMEM_STATE_EXIT)) {
+ pr_debug("%s: returning exit state\n", __func__);
+ return OCMEM_STATE_EXIT;
+ } else
+ return -EINVAL;
+
+}
/**
* audio_ocmem_enable() - Exercise OCMEM for audio
@@ -159,36 +188,12 @@
{
int ret;
int i, j;
+ int state_bit;
struct ocmem_buf *buf = NULL;
struct avcs_cmd_rsp_get_low_power_segments_info_t *lp_segptr;
pr_debug("%s\n", __func__);
- /* Non-blocking ocmem allocate (asynchronous) */
- buf = ocmem_allocate_nb(cid, AUDIO_OCMEM_BUF_SIZE);
- if (IS_ERR_OR_NULL(buf)) {
- pr_err("%s: failed: %d\n", __func__, cid);
- return -ENOMEM;
- }
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_ALLOC);
-
- audio_ocmem_lcl.buf = buf;
- atomic_set(&audio_ocmem_lcl.audio_exit, 0);
- atomic_set(&audio_ocmem_lcl.audio_cond, 1);
- pr_debug("%s: buf->len: %ld\n", __func__, buf->len);
- if (!buf->len) {
- pr_debug("%s: buf.len is 0, waiting for ocmem region\n",
- __func__);
- wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- (atomic_read(&audio_ocmem_lcl.audio_cond) == 0) ||
- (atomic_read(&audio_ocmem_lcl.audio_exit) == 1));
- if (atomic_read(&audio_ocmem_lcl.audio_exit)) {
- pr_err("%s: audio playback ended while waiting for ocmem\n",
- __func__);
- ret = -EINVAL;
- goto fail_cmd;
- }
- }
- pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
+ atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
if (audio_ocmem_lcl.lp_memseg_ptr == NULL) {
/* Retrieve low power segments */
ret = core_get_low_power_segments(
@@ -213,6 +218,42 @@
(uint32_t)audio_ocmem_lcl.mlist.chunks[j].ddr_paddr,
(uint32_t)audio_ocmem_lcl.mlist.chunks[j].size);
}
+ /* Non-blocking ocmem allocate (asynchronous) */
+ buf = ocmem_allocate_nb(cid, AUDIO_OCMEM_BUF_SIZE);
+ if (IS_ERR_OR_NULL(buf)) {
+ pr_err("%s: failed: %d\n", __func__, cid);
+ return -ENOMEM;
+ }
+
+ set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_ALLOC);
+
+ audio_ocmem_lcl.buf = buf;
+ atomic_set(&audio_ocmem_lcl.audio_exit, 0);
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ pr_debug("%s: buf->len: %ld\n", __func__, buf->len);
+ if (!buf->len) {
+ pr_debug("%s: buf.len is 0, waiting for ocmem region\n",
+ __func__);
+ mutex_unlock(&audio_ocmem_lcl.protect_lock);
+ wait_event_interruptible(audio_ocmem_lcl.audio_wait,
+ (atomic_read(&audio_ocmem_lcl.audio_cond) == 0) ||
+ (atomic_read(&audio_ocmem_lcl.audio_exit) == 1));
+ if (atomic_read(&audio_ocmem_lcl.audio_exit)) {
+ ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+ if (ret) {
+ pr_err("%s: ocmem_free failed, state[%d]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ }
+ pr_info("%s: audio playback ended while waiting for ocmem\n",
+ __func__);
+ ret = 0;
+ goto fail_cmd;
+ }
+ clear_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_GROW);
+ mutex_trylock(&audio_ocmem_lcl.protect_lock);
+ }
+ pr_debug("%s: buf->len: %ld\n", __func__, (audio_ocmem_lcl.buf)->len);
/* vote for ocmem bus bandwidth */
ret = msm_bus_scale_client_update_request(
@@ -221,7 +262,7 @@
if (ret)
pr_err("%s: failed to vote for bus bandwidth\n", __func__);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
+ set_bit_pos(audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_TRANSITION);
pr_debug("%s: buf->addr: 0x%08lx, len: %ld, audio_state[0x%x]\n",
__func__,
@@ -236,16 +277,25 @@
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_MAP_FAIL);
}
+ wait_event_interruptible(audio_ocmem_lcl.audio_wait,
+ test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL) != 0);
+ atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+
+ mutex_unlock(&audio_ocmem_lcl.protect_lock);
pr_debug("%s: audio_cond[%d] audio_state[0x%x]\n", __func__,
atomic_read(&audio_ocmem_lcl.audio_cond),
atomic_read(&audio_ocmem_lcl.audio_state));
- while ((atomic_read(&audio_ocmem_lcl.audio_state) !=
- OCMEM_STATE_EXIT)) {
+
+ while ((test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_DISABLE)) == 0) {
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
+ (atomic_read(&audio_ocmem_lcl.audio_state) &
+ _BIT_MASK_) != 0);
- switch (atomic_read(&audio_ocmem_lcl.audio_state)) {
+ state_bit = get_state_to_process(&audio_ocmem_lcl.audio_state);
+ switch (state_bit) {
case OCMEM_STATE_MAP_COMPL:
pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n",
__func__, atomic_read(&audio_ocmem_lcl.audio_cond),
@@ -258,6 +308,10 @@
pr_debug("%s: ocmem shrink request process\n",
__func__);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_TRANSITION);
ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
&audio_ocmem_lcl.mlist);
if (ret) {
@@ -267,12 +321,9 @@
goto fail_cmd;
}
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_UNMAP_TRANSITION);
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_UNMAP_COMPL);
+ test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_COMPL) != 0);
ret = ocmem_shrink(cid, audio_ocmem_lcl.buf, 0);
if (ret) {
pr_err("%s: ocmem_shrink failed, state[%d]\n",
@@ -281,11 +332,18 @@
goto fail_cmd;
}
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_SHRINK);
+ pr_debug("%s:shrink process complete\n", __func__);
break;
case OCMEM_STATE_GROW:
pr_debug("%s: ocmem grow request process\n",
__func__);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_COMPL);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_TRANSITION);
ret = ocmem_map(cid, audio_ocmem_lcl.buf,
&audio_ocmem_lcl.mlist);
if (ret) {
@@ -294,14 +352,102 @@
atomic_read(&audio_ocmem_lcl.audio_state));
goto fail_cmd;
}
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_MAP_TRANSITION);
wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
- atomic_set(&audio_ocmem_lcl.audio_state,
- OCMEM_STATE_MAP_COMPL);
+ test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL) != 0);
+
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_GROW);
atomic_set(&audio_ocmem_lcl.audio_cond, 1);
break;
+ case OCMEM_STATE_EXIT:
+ if (test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL)) {
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_MAP_COMPL);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_TRANSITION);
+ ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
+ &audio_ocmem_lcl.mlist);
+ if (ret) {
+ pr_err("%s: ocmem_unmap failed, state[0x%x]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ goto fail_cmd;
+ }
+ wait_event_interruptible(
+ audio_ocmem_lcl.audio_wait,
+ test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_UNMAP_COMPL) != 0);
+ }
+
+ if (test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_SHRINK)) {
+ pr_debug("%s: SHRINK while exiting\n",
+ __func__);
+ ret = ocmem_shrink(cid, audio_ocmem_lcl.buf,
+ 0);
+ if (ret) {
+ pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ goto fail_cmd;
+ }
+ clear_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_SHRINK);
+
+ }
+
+ pr_debug("%s: calling ocmem free\n", __func__);
+ ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
+ if (ret == -EAGAIN) {
+ pr_debug("%s: received EAGAIN\n", __func__);
+ if (test_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_SHRINK)) {
+ ret = ocmem_shrink(cid,
+ audio_ocmem_lcl.buf,
+ 0);
+ if (ret) {
+ pr_err("%s: ocmem_shrink failed, state[0x%x]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ goto fail_cmd;
+ }
+ pr_debug("calling free after EAGAIN");
+ ret = ocmem_free(OCMEM_LP_AUDIO,
+ audio_ocmem_lcl.buf);
+ if (ret) {
+ pr_err("%s: ocmem_free failed\n",
+ __func__);
+ goto fail_cmd;
+ }
+ } else {
+ pr_debug("%s: shrink callback already processed\n",
+ __func__);
+ goto fail_cmd;
+ }
+ } else if (ret) {
+ pr_err("%s: ocmem_free failed, state[0x%x], ret:%d\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_state),
+ ret);
+ goto fail_cmd;
+ }
+ pr_debug("%s: ocmem_free success\n", __func__);
+ msm_bus_scale_client_update_request(
+ audio_ocmem_lcl.audio_ocmem_bus_client,
+ 0);
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_DISABLE);
+ break;
+
+
+ case -EINVAL:
+ pr_info("%s: audio_cond[%d] audio_state[0x%x]\n",
+ __func__,
+ atomic_read(&audio_ocmem_lcl.audio_cond),
+ atomic_read(&audio_ocmem_lcl.audio_state));
+ break;
}
}
ret = 0;
@@ -320,64 +466,17 @@
*/
int audio_ocmem_disable(int cid)
{
- int ret;
- int cur_state;
-
- pr_debug("%s: disable\n", __func__);
- cur_state = atomic_read(&audio_ocmem_lcl.audio_state);
- if (atomic_cmpxchg(&audio_ocmem_lcl.audio_cond, 1, 0)) {
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
- wake_up(&audio_ocmem_lcl.audio_wait);
- }
pr_debug("%s: audio_cond[0x%x], audio_state[0x%x]\n", __func__,
atomic_read(&audio_ocmem_lcl.audio_cond),
atomic_read(&audio_ocmem_lcl.audio_state));
- switch (cur_state) {
- case OCMEM_STATE_MAP_COMPL:
- atomic_set(&audio_ocmem_lcl.audio_cond, 1);
- ret = ocmem_unmap(cid, audio_ocmem_lcl.buf,
- &audio_ocmem_lcl.mlist);
- if (ret) {
- pr_err("%s: ocmem_unmap failed, state[%d]\n",
- __func__,
- atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
- }
+ set_bit_pos(audio_ocmem_lcl.audio_state,
+ OCMEM_STATE_EXIT);
+ wake_up(&audio_ocmem_lcl.audio_wait);
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
-
- wait_event_interruptible(audio_ocmem_lcl.audio_wait,
- atomic_read(&audio_ocmem_lcl.audio_cond) == 0);
- case OCMEM_STATE_UNMAP_COMPL:
- case OCMEM_STATE_MAP_FAIL:
- case OCMEM_STATE_MAP_TRANSITION:
- case OCMEM_STATE_ALLOC:
- ret = ocmem_free(OCMEM_LP_AUDIO, audio_ocmem_lcl.buf);
- if (ret) {
- pr_err("%s: ocmem_free failed, state[%d]\n",
- __func__,
- atomic_read(&audio_ocmem_lcl.audio_state));
- goto fail_cmd;
- }
- pr_debug("%s: state=%d", __func__,
- atomic_read(&audio_ocmem_lcl.audio_state));
- atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_EXIT);
- pr_debug("%s: ocmem_free success\n", __func__);
- break;
-
- default:
- pr_debug("%s:error: state=%d", __func__,
- atomic_read(&audio_ocmem_lcl.audio_state));
- break;
-
- }
- msm_bus_scale_client_update_request(
- audio_ocmem_lcl.audio_ocmem_bus_client,
- 0);
+ mutex_unlock(&audio_ocmem_lcl.protect_lock);
+ pr_debug("%s: exit\n", __func__);
return 0;
-fail_cmd:
- return ret;
}
static void voice_ocmem_process_workdata(struct work_struct *work)
@@ -497,6 +596,10 @@
container_of(work, struct audio_ocmem_workdata, work);
en = audio_ocm_work->en;
+ mutex_lock(&audio_ocmem_lcl.protect_lock);
+ /* if previous work waiting for ocmem - signal it to exit */
+ atomic_set(&audio_ocmem_lcl.audio_exit, 1);
+ pr_debug("%s: acquired mutex for %d\n", __func__, en);
switch (audio_ocm_work->id) {
case AUDIO:
cid = OCMEM_LP_AUDIO;
@@ -548,9 +651,6 @@
workdata->id = id;
workdata->en = enable;
- /* if previous work waiting for ocmem - signal it to exit */
- atomic_set(&audio_ocmem_lcl.audio_exit, 1);
-
INIT_WORK(&workdata->work, audio_ocmem_process_workdata);
queue_work(audio_ocmem_lcl.audio_ocmem_workqueue,
&workdata->work);
@@ -611,6 +711,7 @@
atomic_set(&audio_ocmem_lcl.audio_state, OCMEM_STATE_DEFAULT);
atomic_set(&audio_ocmem_lcl.audio_exit, 0);
spin_lock_init(&audio_ocmem_lcl.audio_lock);
+ mutex_init(&audio_ocmem_lcl.protect_lock);
audio_ocmem_lcl.ocmem_en = true;
/* populate platform data */