Merge "ARM: dts: msm8226: Add support for L2 GDHS"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
index d07eba6..3947f75 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm_thermal.txt
@@ -28,11 +28,21 @@
core can be used for freq control.
- qcom,core-limit-temp: Threshold temperature to start shutting down cores
in degC
-- qcom,core-temp-hysterisis: Degrees C below which the cores will be brought
+- qcom,core-temp-hysteresis: Degrees C below which the cores will be brought
online in sequence.
- qcom,core-control-mask: The cpu mask that will be used to determine if a
core can be controlled or not. A mask of 0 indicates
the feature is disabled.
+- qcom,hotplug-temp: Threshold temperature to start shutting down cores
+ in degC. This will be used when polling based
+ core control is disabled. The difference between hotplug-temp
+ and core-limit-temp is that core-limit-temp is used during
+ early boot prior to thermal_sys being available for hotplug.
+- qcom,hotplug-temp-hysteresis: Degrees C below which thermal will not force the
+ cores to be offlined. Cores can be brought online if needed.
+- qcpm,cpu-sensors: List of type names in thermal zone device struct which maps
+ to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many
+ cpus there are.
- qcom,vdd-restriction-temp: When temperature is below this threshold, will
enable vdd restriction which will set higher voltage on
key voltage rails, in degC.
@@ -81,8 +91,12 @@
qcom,freq-step = <2>;
qcom,freq-control-mask = <0xf>
qcom,core-limit-temp = <90>;
- qcom,core-temp-hysterisis = <10>;
+ qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <7>;
+ qcom,hotplug-temp = <110>;
+ qcom,hotplug-temp-hysteresis = <20>;
+ qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
+ "tsens_tz_sensor7", "tsens_tz_sensor8";
qcom,pmic-sw-mode-temp = <90>;
qcom,pmic-sw-mode-temp-hysteresis = <80>;
qcom,pmic-sw-mode-regs = "vdd-dig";
diff --git a/Documentation/devicetree/bindings/sound/taiko_codec.txt b/Documentation/devicetree/bindings/sound/taiko_codec.txt
index 9abf54e..489eb38 100644
--- a/Documentation/devicetree/bindings/sound/taiko_codec.txt
+++ b/Documentation/devicetree/bindings/sound/taiko_codec.txt
@@ -35,6 +35,12 @@
- qcom,cdc-vddcx-2-voltage: cx-2 supply's voltage level min and max in mV.
- qcom,cdc-vddcx-2-current: cx-2 supply's max current in mA.
+ - cdc-vdd-buckhelper-supply: phandle of helper regulator supply's
+ device tree node. This supply is a helper regulator for
+ cdc-vdd-buck-supply regulator.
+ - cdc-vdd-buckhelper-voltage: helper supply's voltage level min and max in mV.
+ - qcom,cdc-vdd-buckhelper-current: helper supply's max current in mA.
+
- qcom,cdc-static-supplies: List of supplies to be enabled prior to codec
hardware probe. Supplies in this list will be
stay enabled.
@@ -76,6 +82,10 @@
dynamically.
Supplies in this list are off by default.
+- qcom,cdc-cp-supplies: List of supplies required for codec chargepump enable
+ Supplies in this list can be enabled/disabled dynamically and
+ are off by default.
+
- qcom,cdc-micbias2-headset-only: Boolean. Allow micbias 2 only to headset mic.
Example:
diff --git a/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi b/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi
new file mode 100644
index 0000000..e44e943
--- /dev/null
+++ b/arch/arm/boot/dts/batterydata-qrd-4v2-1800mah.dtsi
@@ -0,0 +1,105 @@
+/* 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.
+ */
+
+qcom,qrd-4v2-1800mah-data {
+ qcom,fcc-mah = <1800>;
+ qcom,default-rbatt-mohm = <146>;
+ qcom,rbatt-capacitive-mohm = <0>;
+ qcom,flat-ocv-threshold-uv = <3800000>;
+ qcom,max-voltage-uv = <4200000>;
+ qcom,v-cutoff-uv = <3400000>;
+ qcom,chg-term-ua = <100000>;
+ qcom,batt-id-kohm = <47>;
+
+ qcom,rbatt-sf-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-row-legend = <100 95 90 85 80>,
+ <75 70 65 60 55>,
+ <50 45 40 35 30>,
+ <25 20 15 10 9>,
+ <8 7 6 5 4>,
+ <3 2 1 0>;
+ qcom,lut-data = <904 234 100 85 80>,
+ <905 234 100 85 80>,
+ <934 244 102 86 81>,
+ <928 254 105 87 82>,
+ <933 268 109 89 84>,
+ <924 280 114 91 85>,
+ <913 283 123 96 88>,
+ <916 267 135 103 91>,
+ <930 252 137 110 95>,
+ <954 247 117 106 95>,
+ <990 247 103 88 85>,
+ <1036 253 104 86 84>,
+ <1101 264 108 89 85>,
+ <1211 286 112 93 88>,
+ <1366 340 120 95 87>,
+ <1601 394 128 95 87>,
+ <2178 402 128 97 89>,
+ <5419 423 126 97 89>,
+ <10789 528 128 97 91>,
+ <13463 589 132 100 91>,
+ <17695 678 137 102 92>,
+ <23046 814 145 104 93>,
+ <30725 1019 153 106 93>,
+ <41382 1359 156 106 93>,
+ <56311 1959 165 108 95>,
+ <77209 3523 189 117 99>,
+ <104609 6039 235 127 105>,
+ <138858 9711 352 141 112>,
+ <165825 15373 1069 246 226>;
+ };
+
+ qcom,fcc-temp-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-data = <1859 1868 1873 1861 1859>;
+ };
+
+ qcom,pc-temp-ocv-lut {
+ qcom,lut-col-legend = <(-20) 0 25 40 60>;
+ qcom,lut-row-legend = <100 95 90 85 80>,
+ <75 70 65 60 55>,
+ <50 45 40 35 30>,
+ <25 20 15 10 9>,
+ <8 7 6 5 4>,
+ <3 2 1 0>;
+ qcom,lut-data = <4178 4176 4174 4169 4163>,
+ <4090 4100 4105 4101 4099>,
+ <4029 4049 4053 4050 4048>,
+ <3973 3998 4006 4004 4002>,
+ <3932 3959 3965 3962 3960>,
+ <3891 3920 3928 3925 3922>,
+ <3855 3882 3894 3891 3889>,
+ <3825 3844 3862 3862 3859>,
+ <3803 3813 3829 3834 3831>,
+ <3788 3792 3797 3802 3800>,
+ <3777 3780 3778 3776 3773>,
+ <3764 3775 3771 3767 3763>,
+ <3749 3769 3766 3763 3757>,
+ <3725 3756 3758 3755 3750>,
+ <3687 3727 3736 3735 3729>,
+ <3631 3675 3698 3698 3691>,
+ <3571 3607 3637 3642 3637>,
+ <3514 3548 3568 3572 3570>,
+ <3458 3506 3519 3522 3522>,
+ <3444 3498 3511 3516 3515>,
+ <3430 3489 3503 3509 3508>,
+ <3413 3477 3493 3500 3500>,
+ <3395 3461 3478 3488 3486>,
+ <3373 3433 3446 3463 3456>,
+ <3346 3394 3397 3418 3410>,
+ <3307 3341 3334 3361 3352>,
+ <3251 3270 3254 3287 3277>,
+ <3160 3167 3152 3183 3172>,
+ <3000 3000 3000 3000 3000>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm-pm8841.dtsi b/arch/arm/boot/dts/msm-pm8841.dtsi
index a2d80ec..43bd0c9 100644
--- a/arch/arm/boot/dts/msm-pm8841.dtsi
+++ b/arch/arm/boot/dts/msm-pm8841.dtsi
@@ -238,5 +238,28 @@
reg = <0x2b00 0x100>;
};
};
+
+ krait_regulator_pmic: qcom,krait-regulator-pmic@2000 {
+ spmi-dev-container;
+ compatible = "qcom,krait-regulator-pmic";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ qcom,ctl@2000 {
+ status = "disabled";
+ reg = <0x2000 0x100>;
+ };
+
+ qcom,ps@2100 {
+ status = "disabled";
+ reg = <0x2100 0x100>;
+ };
+
+ qcom,freq@2200 {
+ status = "disabled";
+ reg = <0x2200 0x100>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/msm-pma8084.dtsi b/arch/arm/boot/dts/msm-pma8084.dtsi
index 3ff1b60..c070443 100644
--- a/arch/arm/boot/dts/msm-pma8084.dtsi
+++ b/arch/arm/boot/dts/msm-pma8084.dtsi
@@ -814,5 +814,28 @@
compatible = "qcom,qpnp-regulator";
status = "disabled";
};
+
+ krait_regulator_pmic: qcom,krait-regulator-pmic@2900 {
+ spmi-dev-container;
+ compatible = "qcom,krait-regulator-pmic";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+
+ qcom,ctl@2900 {
+ reg = <0x2900 0x100>;
+ status = "disabled";
+ };
+
+ qcom,ps@2a00 {
+ reg = <0x2a00 0x100>;
+ status = "disabled";
+ };
+
+ qcom,freq@2b00 {
+ reg = <0x2b00 0x100>;
+ status = "disabled";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
index 0a3148b..9e98681 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-dvt.dts
@@ -31,3 +31,7 @@
qcom,cont-splash-enabled;
};
};
+
+&pm8226_bms {
+ qcom,use-external-rsense;
+};
diff --git a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
index 95af304..320cea1 100644
--- a/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
+++ b/arch/arm/boot/dts/msm8226-v2-qrd-skuf.dts
@@ -160,3 +160,7 @@
qcom,fast-avg-setup = <0>;
};
};
+
+&pm8226_iadc {
+ qcom,rsense = <10000000>;
+};
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index edb409d..b3e18fb 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -339,12 +339,18 @@
qcom,cdc-vdd-cx-voltage = <1200000 1200000>;
qcom,cdc-vdd-cx-current = <10000>;
- qcom,cdc-static-supplies = "cdc-vdd-buck",
- "cdc-vdd-h",
+ cdc-vdd-buckhelper-supply = <&pm8226_l25>;
+ qcom,cdc-vdd-buckhelper-voltage = <1775000 2125000>;
+ qcom,cdc-vdd-buckhelper-current = <10000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-h",
"cdc-vdd-px",
"cdc-vdd-a-1p2v",
"cdc-vdd-cx";
+ qcom,cdc-cp-supplies = "cdc-vdd-buck",
+ "cdc-vdd-buckhelper";
+
qcom,cdc-micbias-ldoh-v = <0x3>;
qcom,cdc-micbias-cfilt1-mv = <1800>;
qcom,cdc-micbias-cfilt2-mv = <2700>;
diff --git a/arch/arm/boot/dts/msm8610-bus.dtsi b/arch/arm/boot/dts/msm8610-bus.dtsi
index cef04ef..6b72e66 100644
--- a/arch/arm/boot/dts/msm8610-bus.dtsi
+++ b/arch/arm/boot/dts/msm8610-bus.dtsi
@@ -952,6 +952,7 @@
cell-id = <2048>;
label = "fab_mmss_noc";
qcom,masterp = <1>;
+ qcom,gateway;
qcom,qport = <1>;
qcom,buswidth = <8>;
qcom,ws = <10000>;
diff --git a/arch/arm/boot/dts/msm8610-cdp.dts b/arch/arm/boot/dts/msm8610-cdp.dtsi
similarity index 95%
rename from arch/arm/boot/dts/msm8610-cdp.dts
rename to arch/arm/boot/dts/msm8610-cdp.dtsi
index f3470c2..bfccb78 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dtsi
@@ -10,19 +10,6 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
-
-/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
-/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
-
-/ {
- model = "Qualcomm MSM 8610 CDP";
- compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
- qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
- <163 1 0>, <164 1 0>, <166 1 0>;
-};
-
&soc {
serial@f991e000 {
status = "ok";
@@ -52,7 +39,7 @@
/* Object 6, Instance = 0 */
00 00 00 00 00 00
/* Object 38, Instance = 0 */
- 1D 02 00 0A 06 0D 00 00
+ 1D 03 00 1E 07 0D 00 00
/* Object 7, Instance = 0 */
20 08 32
/* Object 8, Instance = 0 */
@@ -60,7 +47,7 @@
/* Object 9, Instance = 0 */
83 00 00 13 0B 00 20 32 01 03
00 32 05 30 0A 05 0A 00 70 03
- FC 01 00 36 2F D8 00 00 40 00
+ FC 01 04 2F F8 DC 00 00 40 00
00 0A 00 00 02
/* Object 18, Instance = 0 */
00 00
@@ -143,6 +130,10 @@
"AMIC1", "MIC BIAS External",
"AMIC2", "MIC BIAS Internal2";
};
+
+ qcom,dsi_v2_truly_wvga_video {
+ qcom,cont-splash-enabled;
+ };
};
&i2c_cdc {
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dtsi
similarity index 95%
rename from arch/arm/boot/dts/msm8610-mtp.dts
rename to arch/arm/boot/dts/msm8610-mtp.dtsi
index 0d4c174..349c8f7 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dtsi
@@ -10,19 +10,6 @@
* GNU General Public License for more details.
*/
-/dts-v1/;
-
-/include/ "msm8610.dtsi"
-/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
-/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
-
-/ {
- model = "Qualcomm MSM 8610 MTP";
- compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
- qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
- <163 8 0>, <164 8 0>, <166 8 0>;
-};
-
&soc {
serial@f991e000 {
status = "ok";
@@ -52,7 +39,7 @@
/* Object 6, Instance = 0 */
00 00 00 00 00 00
/* Object 38, Instance = 0 */
- 1D 02 00 0A 06 0D 00 00
+ 1D 03 00 1E 07 0D 00 00
/* Object 7, Instance = 0 */
20 08 32
/* Object 8, Instance = 0 */
@@ -60,7 +47,7 @@
/* Object 9, Instance = 0 */
83 00 00 13 0B 00 20 32 01 03
00 32 05 30 0A 05 0A 00 70 03
- FC 01 00 36 2F D8 00 00 40 00
+ FC 01 04 2F F8 DC 00 00 40 00
00 0A 00 00 02
/* Object 18, Instance = 0 */
00 00
@@ -181,6 +168,10 @@
"AMIC1", "MIC BIAS External",
"AMIC2", "MIC BIAS Internal2";
};
+
+ qcom,dsi_v2_truly_wvga_video {
+ qcom,cont-splash-enabled;
+ };
};
&i2c_cdc {
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index d31a65c..beeeed3 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -24,7 +24,7 @@
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
- qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
};
@@ -41,7 +41,7 @@
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
- qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
};
@@ -58,7 +58,7 @@
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 06 26 30 0f];
- qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 07 60 3b 76 76
+ qcom,saw2-spm-cmd-pc = [00 20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 06 26 30 0f];
};
@@ -75,7 +75,7 @@
qcom,saw2-spm-cmd-wfi = [60 03 60 0b 0f];
qcom,saw2-spm-cmd-spc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
- qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 07 60 3b 76 76
+ qcom,saw2-spm-cmd-pc = [20 10 80 30 90 5b 60 03 60 3b 76 76
0b 94 5b 80 10 26 30 0f];
};
@@ -208,45 +208,43 @@
qcom,gpio-parent = <&msmgpio>;
qcom,gpio-map = <3 1>,
- <4 4 >,
- <5 5 >,
- <6 9 >,
- <7 13>,
- <8 17>,
- <9 21>,
- <10 27>,
- <11 29>,
- <12 31>,
- <13 33>,
- <14 35>,
- <15 37>,
- <16 38>,
- <17 39>,
- <18 41>,
- <19 46>,
- <20 48>,
- <21 49>,
- <22 50>,
- <23 51>,
- <24 52>,
- <25 54>,
- <26 62>,
- <27 63>,
- <28 64>,
- <29 65>,
- <30 66>,
- <31 67>,
- <32 68>,
- <33 69>,
- <34 71>,
- <35 72>,
- <36 106>,
- <37 107>,
- <38 108>,
- <39 109>,
- <40 110>,
- <54 111>,
- <55 113>;
+ <4 5 >,
+ <5 9 >,
+ <6 14>,
+ <7 15>,
+ <8 32>,
+ <9 33>,
+ <10 34>,
+ <11 35>,
+ <12 41>,
+ <13 42>,
+ <14 72>,
+ <15 73>,
+ <16 74>,
+ <17 75>,
+ <18 76>,
+ <19 77>,
+ <20 78>,
+ <21 79>,
+ <22 80>,
+ <23 81>,
+ <24 82>,
+ <25 83>,
+ <26 84>,
+ <27 85>,
+ <28 87>,
+ <29 90>,
+ <30 91>,
+ <31 92>,
+ <32 93>,
+ <33 94>,
+ <34 95>,
+ <35 96>,
+ <36 97>,
+ <37 98>,
+ <38 99>,
+ <39 100>,
+ <40 101>;
};
qcom,pm-8x60@fe805664 {
diff --git a/arch/arm/boot/dts/msm8610-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index bd1705f..d9de889 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -26,8 +26,6 @@
* };
*/
-/include/ "msm8610.dtsi"
-
&soc {
i2c@f9923000{
focaltech@38{
@@ -344,3 +342,10 @@
mpp@a300 { /* MPP 4 */
};
};
+
+&pm8110_vadc {
+ chan@30 {
+ label = "batt_therm";
+ qcom,scale-function = <6>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-v1-cdp.dts b/arch/arm/boot/dts/msm8610-v1-cdp.dts
new file mode 100644
index 0000000..ba0851f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v1-cdp.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v1.dtsi"
+/include/ "msm8610-cdp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610 CDP";
+ compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
+ qcom,msm-id = <147 1 0>, <165 1 0>, <161 1 0>, <162 1 0>,
+ <163 1 0>, <164 1 0>, <166 1 0>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v1-mtp.dts b/arch/arm/boot/dts/msm8610-v1-mtp.dts
new file mode 100644
index 0000000..010903f
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v1-mtp.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v1.dtsi"
+/include/ "msm8610-mtp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610 MTP";
+ compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
+ qcom,msm-id = <147 8 0>, <165 8 0>, <161 8 0>, <162 8 0>,
+ <163 8 0>, <164 8 0>, <166 8 0>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
similarity index 92%
rename from arch/arm/boot/dts/msm8610-qrd-skuaa.dts
rename to arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
index aeaf8ca..5abe5c0 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuaa.dts
@@ -12,6 +12,7 @@
/dts-v1/;
+/include/ "msm8610-v1.dtsi"
/include/ "msm8610-qrd.dtsi"
/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
/include/ "msm8610-qrd-camera-sensor.dtsi"
@@ -45,3 +46,10 @@
status = "ok";
qcom,batt-type = <5>;
};
+
+&pm8110_vadc {
+ chan@30 {
+ label = "batt_therm";
+ qcom,scale-function = <7>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610-qrd-skuab.dts b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
similarity index 83%
rename from arch/arm/boot/dts/msm8610-qrd-skuab.dts
rename to arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
index 947a312..b4559ff 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dts
+++ b/arch/arm/boot/dts/msm8610-v1-qrd-skuab.dts
@@ -12,6 +12,7 @@
/dts-v1/;
+/include/ "msm8610-v1.dtsi"
/include/ "msm8610-qrd.dtsi"
/include/ "dsi-v2-panel-otm8018b-fwvga-video.dtsi"
/include/ "msm8612-qrd-camera-sensor.dtsi"
@@ -80,7 +81,30 @@
};
};
+ usb@f9a55000 {
+ qcom,hsusb-otg-phy-init-seq =
+ <0x44 0x80 0x6a 0x81 0x34 0x82 0x23 0x83 0xffffffff>;
+ };
+
qcom,dsi_v2_otm8018b_fwvga_video {
status = "ok";
};
};
+
+/ {
+ qrd_batterydata: qcom,battery-data {
+ qcom,rpull-up-kohm = <100>;
+ qcom,vref-batt-therm = <1800000>;
+
+ /include/ "batterydata-qrd-4v2-1800mah.dtsi"
+ };
+};
+
+&pm8110_bms {
+ status = "ok";
+ qcom,battery-data = <&qrd_batterydata>;
+};
+
+&pm8110_chg {
+ qcom,battery-data = <&qrd_batterydata>;
+};
diff --git a/arch/arm/boot/dts/msm8610-v1.dtsi b/arch/arm/boot/dts/msm8610-v1.dtsi
new file mode 100644
index 0000000..5052b96
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v1.dtsi
@@ -0,0 +1,19 @@
+/* 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
+ * msm8610.dtsi file.
+ */
+
+/include/ "msm8610.dtsi"
diff --git a/arch/arm/boot/dts/msm8610-v2-cdp.dts b/arch/arm/boot/dts/msm8610-v2-cdp.dts
new file mode 100644
index 0000000..51ef7a2
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-cdp.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v2.dtsi"
+/include/ "msm8610-cdp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610v2 CDP";
+ compatible = "qcom,msm8610-cdp", "qcom,msm8610", "qcom,cdp";
+ qcom,msm-id = <147 1 0x10001>, <165 1 0x10001>, <161 1 0x10001>, <162 1 0x10001>,
+ <163 1 0x10001>, <164 1 0x10001>, <166 1 0x10001>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v2-mtp.dts b/arch/arm/boot/dts/msm8610-v2-mtp.dts
new file mode 100644
index 0000000..e1c9bb8
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-mtp.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v2.dtsi"
+/include/ "msm8610-mtp.dtsi"
+/include/ "dsi-v2-panel-truly-wvga-video.dtsi"
+/include/ "msm8610-camera-sensor-cdp-mtp.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610v2 MTP";
+ compatible = "qcom,msm8610-mtp", "qcom,msm8610", "qcom,mtp";
+ qcom,msm-id = <147 8 0x10001>, <165 8 0x10001>, <161 8 0x10001>, <162 8 0x10001>,
+ <163 8 0x10001>, <164 8 0x10001>, <166 8 0x10001>;
+};
+
+
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
new file mode 100644
index 0000000..6ad8cb5
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuaa.dts
@@ -0,0 +1,27 @@
+/* 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/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd.dtsi"
+/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
+/include/ "msm8610-qrd-camera-sensor.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610v2 QRD";
+ compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+ qcom,board-id = <11 1>, <11 0>;
+ qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
+ <163 0x10001>, <164 0x10001>, <166 0x10001>;
+};
+
diff --git a/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
new file mode 100644
index 0000000..225be06
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2-qrd-skuab.dts
@@ -0,0 +1,24 @@
+/* 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/ "msm8610-v2.dtsi"
+/include/ "msm8610-qrd.dtsi"
+
+/ {
+ model = "Qualcomm MSM 8610v2 QRD";
+ compatible = "qcom,msm8610-qrd", "qcom,msm8610", "qcom,qrd";
+ qcom,board-id = <11 3>;
+ qcom,msm-id = <147 0x10001>, <165 0x10001>, <161 0x10001>, <162 0x10001>,
+ <163 0x10001>, <164 0x10001>, <166 0x10001>;
+};
diff --git a/arch/arm/boot/dts/msm8610-v2.dtsi b/arch/arm/boot/dts/msm8610-v2.dtsi
new file mode 100644
index 0000000..5052b96
--- /dev/null
+++ b/arch/arm/boot/dts/msm8610-v2.dtsi
@@ -0,0 +1,19 @@
+/* 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
+ * msm8610.dtsi file.
+ */
+
+/include/ "msm8610.dtsi"
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index c6104bf..efa68b9 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -472,6 +472,7 @@
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 2 0>;
qcom,scl-gpio = <&msmgpio 3 0>;
+ qcom,master-id = <86>;
};
i2c_cdc: i2c@f9927000 { /* BLSP1 QUP5 */
@@ -484,6 +485,8 @@
interrupt-names = "qup_err_intr";
interrupts = <0 99 0>;
qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,master-id = <86>;
};
i2c: i2c@f9928000 { /* BLSP1 QUP6 */
@@ -499,6 +502,7 @@
qcom,i2c-src-freq = <19200000>;
qcom,sda-gpio = <&msmgpio 16 0>;
qcom,scl-gpio = <&msmgpio 17 0>;
+ qcom,master-id = <86>;
};
i2c@f9925000 { /* BLSP-1 QUP-3 */
@@ -511,6 +515,10 @@
interrupt-names = "qup_err_intr";
interrupts = <0 97 0>;
qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ qcom,sda-gpio = <&msmgpio 10 0>;
+ qcom,scl-gpio = <&msmgpio 11 0>;
+ qcom,master-id = <86>;
};
spi_4: spi@f9926000 { /* BLSP1 QUP4 */
@@ -929,10 +937,16 @@
};
&gdsc_vfe {
+ qcom,clock-names = "core_clk", "iface_clk", "bus_clk";
+ qcom,skip-logic-collapse;
+ qcom,retain-periph;
+ qcom,retain-mem;
status = "ok";
};
&gdsc_oxili_cx {
+ qcom,clock-names = "core_clk", "iface_clk", "mem_clk";
+ qcom,skip-logic-collapse;
status = "ok";
};
diff --git a/arch/arm/boot/dts/msm8926.dtsi b/arch/arm/boot/dts/msm8926.dtsi
index 5afcb4e..9159ba2 100644
--- a/arch/arm/boot/dts/msm8926.dtsi
+++ b/arch/arm/boot/dts/msm8926.dtsi
@@ -78,6 +78,10 @@
qcom,slope = <2901 2846 3038 2955 2901 2846>;
};
+&msmgpio {
+ ngpio = <120>;
+};
+
&memory_hole {
qcom,memblock-remove = <0x08000000 0x7500000
0x0fa00000 0x500000>; /* Address and size of the hole */
diff --git a/arch/arm/boot/dts/msm8974-ion.dtsi b/arch/arm/boot/dts/msm8974-ion.dtsi
index 63f6d59..455ed2d 100644
--- a/arch/arm/boot/dts/msm8974-ion.dtsi
+++ b/arch/arm/boot/dts/msm8974-ion.dtsi
@@ -55,5 +55,12 @@
qcom,memory-reservation-type = "EBI1"; /* reserve EBI memory */
qcom,memory-reservation-size = <0x614000>;
};
+
+ qcom,ion-heap@23 { /* OTHER PIL HEAP */
+ compatible = "qcom,msm-ion-reserve";
+ reg = <23>;
+ qcom,heap-align = <0x1000>;
+ qcom,memory-fixed = <0x05d00000 0x1e00000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/msm8974-v1.dtsi b/arch/arm/boot/dts/msm8974-v1.dtsi
index 86a61cd..249c963 100644
--- a/arch/arm/boot/dts/msm8974-v1.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1.dtsi
@@ -165,3 +165,19 @@
qcom,retain-mem;
qcom,retain-periph;
};
+
+&krait_regulator_pmic {
+ status = "ok";
+
+ qcom,ctl@2000 {
+ status = "ok";
+ };
+
+ qcom,ps@2100 {
+ status = "ok";
+ };
+
+ qcom,freq@2200 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974-v2.dtsi b/arch/arm/boot/dts/msm8974-v2.dtsi
index 9d5e50b..af4030f 100644
--- a/arch/arm/boot/dts/msm8974-v2.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2.dtsi
@@ -168,3 +168,19 @@
&tspp {
vdd_cx-supply = <&pm8841_s2_corner>;
};
+
+&krait_regulator_pmic {
+ status = "ok";
+
+ qcom,ctl@2000 {
+ status = "ok";
+ };
+
+ qcom,ps@2100 {
+ status = "ok";
+ };
+
+ qcom,freq@2200 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index c8e3d96..bcea24e 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1504,6 +1504,10 @@
qcom,core-limit-temp = <80>;
qcom,core-temp-hysteresis = <10>;
qcom,core-control-mask = <0xe>;
+ qcom,hotplug-temp = <110>;
+ qcom,hotplug-temp-hysteresis = <20>;
+ qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6",
+ "tsens_tz_sensor7", "tsens_tz_sensor8";
qcom,vdd-restriction-temp = <5>;
qcom,vdd-restriction-temp-hysteresis = <10>;
qcom,pmic-sw-mode-temp = <85>;
@@ -1540,7 +1544,7 @@
memory_hole: qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
- qcom,memblock-remove = <0x7b00000 0x8400000>; /* Address and Size of Hole */
+ qcom,memblock-remove = <0x5d00000 0xa200000>; /* Address and Size of Hole */
};
uart7: uart@f995d000 { /*BLSP #2, UART #7 */
diff --git a/arch/arm/boot/dts/msm8974pro-ab.dtsi b/arch/arm/boot/dts/msm8974pro-ab.dtsi
index 88687bd..5809069 100644
--- a/arch/arm/boot/dts/msm8974pro-ab.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ab.dtsi
@@ -39,3 +39,19 @@
&tspp {
vdd_cx-supply = <&pm8841_s2_corner>;
};
+
+&krait_regulator_pmic {
+ status = "ok";
+
+ qcom,ctl@2000 {
+ status = "ok";
+ };
+
+ qcom,ps@2100 {
+ status = "ok";
+ };
+
+ qcom,freq@2200 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
index 250afd2..debf7fb 100644
--- a/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac-mtp.dtsi
@@ -62,10 +62,6 @@
vbus_dwc3-supply = <&pm8941_mvs1>;
};
- qcom,mdss_dsi_toshiba_720p_video {
- qcom,rst-gpio = <&pma8084_gpios 20 0>;
- };
-
gpio_keys {
camera_snapshot {
gpios = <&pma8084_gpios 3 0x1>;
diff --git a/arch/arm/boot/dts/msm8974pro-ac.dtsi b/arch/arm/boot/dts/msm8974pro-ac.dtsi
index 032c256..4c55169 100644
--- a/arch/arm/boot/dts/msm8974pro-ac.dtsi
+++ b/arch/arm/boot/dts/msm8974pro-ac.dtsi
@@ -52,6 +52,7 @@
vdd-supply = <&pma8084_l22>;
vddio-supply = <&pma8084_l12>;
vdda-supply = <&pma8084_l2>;
+ qcom,platform-reset-gpio = <&pma8084_gpios 20 0>;
};
qcom,mdss_dsi@fd922e00 {
@@ -188,3 +189,19 @@
&tspp {
vdd_cx-supply = <&pma8084_s2_corner>;
};
+
+&krait_regulator_pmic {
+ status = "ok";
+
+ qcom,ctl@2900 {
+ status = "ok";
+ };
+
+ qcom,ps@2a00 {
+ status = "ok";
+ };
+
+ qcom,freq@2b00 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro-pm.dtsi b/arch/arm/boot/dts/msm8974pro-pm.dtsi
new file mode 100644
index 0000000..31bff88
--- /dev/null
+++ b/arch/arm/boot/dts/msm8974pro-pm.dtsi
@@ -0,0 +1,340 @@
+/* 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.
+ */
+
+&soc {
+ qcom,spm@f9089000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9089000 0x1000>;
+ qcom,core-id = <0>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ };
+
+ qcom,spm@f9099000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9099000 0x1000>;
+ qcom,core-id = <1>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ };
+
+ qcom,spm@f90a9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90a9000 0x1000>;
+ qcom,core-id = <2>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ };
+
+ qcom,spm@f90b9000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf90b9000 0x1000>;
+ qcom,core-id = <3>;
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x01>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-spm-cmd-wfi = [03 0b 0f];
+ qcom,saw2-spm-cmd-ret = [42 1b 00 d8 5B 03 d8 5b 0b 00 42 1b 0f];
+ qcom,saw2-spm-cmd-spc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ qcom,saw2-spm-cmd-pc = [00 20 80 10 E8 5B 03 3B E8 5B 82 10 0B
+ 30 06 26 30 0F];
+ };
+
+ qcom,spm@f9012000 {
+ compatible = "qcom,spm-v2";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xf9012000 0x1000>;
+ qcom,core-id = <0xffff>; /* L2/APCS SAW */
+ qcom,saw2-ver-reg = <0xfd0>;
+ qcom,saw2-cfg = <0x14>;
+ qcom,saw2-avs-ctl = <0>;
+ qcom,saw2-avs-hysteresis = <0>;
+ qcom,saw2-avs-limit = <0>;
+ qcom,saw2-avs-dly= <0>;
+ qcom,saw2-spm-dly= <0x3C102800>;
+ qcom,saw2-spm-ctl = <0x1>;
+ qcom,saw2-pmic-data0 = <0x02030080>;
+ qcom,saw2-pmic-data1 = <0x00030000>;
+ qcom,vctl-timeout-us = <50>;
+ qcom,vctl-port = <0x0>;
+ qcom,phase-port = <0x1>;
+ qcom,pfm-port = <0x2>;
+ qcom,saw2-spm-cmd-ret = [1f 00 03 00 0f];
+ qcom,saw2-spm-cmd-gdhs = [00 32 42 07 44 50 02 32 50 0f];
+ qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
+ 50 02 32 50 0f];
+ };
+
+ qcom,lpm-levels {
+ compatible = "qcom,lpm-levels";
+ qcom,default-l2-state = "l2_cache_retention";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ qcom,lpm-level@0 {
+ reg = <0x0>;
+ qcom,mode = "wfi";
+ qcom,l2 = "l2_cache_retention";
+ qcom,latency-us = <1>;
+ qcom,ss-power = <715>;
+ qcom,energy-overhead = <17700>;
+ qcom,time-overhead = <2>;
+ };
+
+ qcom,lpm-level@1 {
+ reg = <0x1>;
+ qcom,mode = "retention";
+ qcom,l2 = "l2_cache_retention";
+ qcom,latency-us = <35>;
+ qcom,ss-power = <542>;
+ qcom,energy-overhead = <34920>;
+ qcom,time-overhead = <40>;
+ };
+
+
+ qcom,lpm-level@2 {
+ reg = <0x2>;
+ qcom,mode = "standalone_pc";
+ qcom,l2 = "l2_cache_retention";
+ qcom,latency-us = <300>;
+ qcom,ss-power = <476>;
+ qcom,energy-overhead = <225300>;
+ qcom,time-overhead = <350>;
+ };
+
+ qcom,lpm-level@3 {
+ reg = <0x3>;
+ qcom,mode = "pc";
+ qcom,l2 = "l2_cache_gdhs";
+ qcom,gpio-detectable;
+ qcom,latency-us = <20000>;
+ qcom,ss-power = <163>;
+ qcom,energy-overhead = <1577736>;
+ qcom,time-overhead = <5067>;
+ };
+
+ qcom,lpm-level@4 {
+ reg = <0x4>;
+ qcom,mode = "pc";
+ qcom,l2 = "l2_cache_pc";
+ qcom,latency-us = <30000>;
+ qcom,ss-power = <83>;
+ qcom,energy-overhead = <2274420>;
+ qcom,time-overhead = <6605>;
+ };
+ };
+
+ qcom,pm-boot {
+ compatible = "qcom,pm-boot";
+ qcom,mode = "tz";
+ };
+
+ qcom,mpm@fc4281d0 {
+ compatible = "qcom,mpm-v2";
+ reg = <0xfc4281d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */
+ <0xf9011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
+ reg-names = "vmpm", "ipc";
+ interrupts = <0 171 1>;
+
+ qcom,ipc-bit-offset = <1>;
+
+ qcom,gic-parent = <&intc>;
+ qcom,gic-map = <2 216>, /* tsens_upper_lower_int */
+ <47 165>, /* usb30_hs_phy_irq */
+ <50 172>, /* usb1_hs_async_wakeup_irq */
+ <53 104>, /* mdss_irq */
+ <62 222>, /* ee0_krait_hlos_spmi_periph_irq */
+ <0xff 56>, /* modem_watchdog */
+ <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 61>, /* mss_a2_bam_irq */
+ <0xff 70>, /* iommu_pmon_nonsecure_irq */
+ <0xff 97>, /* iommu_nonsecure_irq */
+ <0xff 105>, /* iommu_pmon_nonsecure_irq */
+ <0xff 173>, /* o_wcss_apss_smd_hi */
+ <0xff 174>, /* o_wcss_apss_smd_med */
+ <0xff 175>, /* o_wcss_apss_smd_low */
+ <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 181>, /* wcnss watchdog */
+ <0xff 188>, /* lpass_irq_out_apcs(0) */
+ <0xff 189>, /* lpass_irq_out_apcs(1) */
+ <0xff 190>, /* lpass_irq_out_apcs(2) */
+ <0xff 191>, /* lpass_irq_out_apcs(3) */
+ <0xff 192>, /* lpass_irq_out_apcs(4) */
+ <0xff 193>, /* lpass_irq_out_apcs(5) */
+ <0xff 194>, /* lpass_irq_out_apcs(6) */
+ <0xff 195>, /* lpass_irq_out_apcs(7) */
+ <0xff 196>, /* lpass_irq_out_apcs(8) */
+ <0xff 197>, /* lpass_irq_out_apcs(9) */
+ <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 211>, /* usb_dwc3_otg */
+ <0xff 240>; /* summary_irq_kpss */
+
+ qcom,gpio-parent = <&msmgpio>;
+ qcom,gpio-map = <3 102>,
+ <4 1 >,
+ <5 5 >,
+ <6 9 >,
+ <7 18>,
+ <8 20>,
+ <9 24>,
+ <10 27>,
+ <11 28>,
+ <12 34>,
+ <13 35>,
+ <14 37>,
+ <15 42>,
+ <16 44>,
+ <17 46>,
+ <18 50>,
+ <19 54>,
+ <20 59>,
+ <21 61>,
+ <22 62>,
+ <23 64>,
+ <24 65>,
+ <25 66>,
+ <26 67>,
+ <27 68>,
+ <28 71>,
+ <29 72>,
+ <30 73>,
+ <31 74>,
+ <32 75>,
+ <33 77>,
+ <34 79>,
+ <35 80>,
+ <36 82>,
+ <37 86>,
+ <38 92>,
+ <39 93>,
+ <40 95>,
+ <41 144>;
+ };
+
+ qcom,pm-8x60@fe805664 {
+ compatible = "qcom,pm-8x60";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0xfe805664 0x40>;
+ qcom,pc-mode = "tz_l2_int";
+ qcom,use-sync-timer;
+ qcom,cpus-as-clocks;
+
+ qcom,pm-snoc-client {
+ compatible = "qcom,pm-snoc-client";
+ qcom,msm-bus,name = "ocimem_snoc";
+ qcom,msm-bus,num-cases = <2>;
+ qcom,msm-bus,num-paths = <1>;
+ qcom,msm-bus,active-only;
+ qcom,msm-bus,vectors-KBps =
+ <54 585 0 0>,
+ <54 585 0 800000>;
+ };
+ };
+
+ qcom,cpu-sleep-status@f9088008{
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x100>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
+ };
+
+ qcom,rpm-log@fc19dc00 {
+ compatible = "qcom,rpm-log";
+ reg = <0xfc19dc00 0x4000>;
+ qcom,rpm-addr-phys = <0xfc000000>;
+ qcom,offset-version = <4>;
+ qcom,offset-page-buffer-addr = <36>;
+ qcom,offset-log-len = <40>;
+ qcom,offset-log-len-mask = <44>;
+ qcom,offset-page-indices = <56>;
+ };
+
+ qcom,rpm-stats@fc19dba0 {
+ compatible = "qcom,rpm-stats";
+ reg = <0xfc19dba0 0x1000>;
+ reg-names = "phys_addr_base";
+ qcom,sleep-stats-version = <2>;
+ };
+
+ qcom,rpm-rbcpr-stats@fc000000 {
+ compatible = "qcom,rpmrbcpr-stats";
+ reg = <0xfc000000 0x1a0000>;
+ qcom,start-offset = <0x190010>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8974pro.dtsi b/arch/arm/boot/dts/msm8974pro.dtsi
index e7c6a48..7914a6a 100644
--- a/arch/arm/boot/dts/msm8974pro.dtsi
+++ b/arch/arm/boot/dts/msm8974pro.dtsi
@@ -19,7 +19,7 @@
/include/ "msm8974.dtsi"
/include/ "msm8974-v2-iommu.dtsi"
/include/ "msm8974-v2-iommu-domains.dtsi"
-/include/ "msm8974-v2-pm.dtsi"
+/include/ "msm8974pro-pm.dtsi"
/include/ "msm8974pro-ion.dtsi"
&soc {
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index 67ed35c..47b425c 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -1,6 +1,5 @@
# CONFIG_ARM_PATCH_PHYS_VIRT is not set
CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
@@ -72,6 +71,7 @@
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index d42d54d..97c3664 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -1,6 +1,5 @@
# CONFIG_ARM_PATCH_PHYS_VIRT is not set
CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
@@ -73,6 +72,7 @@
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_XPU_ERR_FATAL=y
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 795a50d..b8dc0d7b 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -71,6 +71,7 @@
CONFIG_SENSORS_ADSP=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index a5f0704..dd4274a 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -1,6 +1,5 @@
# CONFIG_ARM_PATCH_PHYS_VIRT is not set
CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_IKCONFIG=y
@@ -71,6 +70,7 @@
CONFIG_MSM_RTB_SEPARATE_CPUS=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_BOOT_STATS=y
+CONFIG_STRICT_MEMORY_RWX=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index e4a647f..6078901 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -296,7 +296,7 @@
obj-$(CONFIG_ARCH_MSM8610) += gdsc.o
obj-$(CONFIG_ARCH_MPQ8092) += gdsc.o
obj-$(CONFIG_ARCH_APQ8084) += gdsc.o
-obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o
+obj-$(CONFIG_KRAIT_REGULATOR) += krait-regulator.o krait-regulator-pmic.o
obj-$(CONFIG_ARCH_MSMKRYPTON) += board-krypton.o board-krypton-gpiomux.o
obj-$(CONFIG_ARCH_MSMSAMARIUM) += board-samarium.o board-samarium-gpiomux.o
obj-$(CONFIG_ARCH_MSM9625) += board-9625.o board-9625-gpiomux.o
diff --git a/arch/arm/mach-msm/Makefile.boot b/arch/arm/mach-msm/Makefile.boot
index 01c7a2a..910264e 100644
--- a/arch/arm/mach-msm/Makefile.boot
+++ b/arch/arm/mach-msm/Makefile.boot
@@ -134,12 +134,16 @@
# MSM8610
zreladdr-$(CONFIG_ARCH_MSM8610) := 0x00008000
- dtb-$(CONFIG_ARCH_MSM8610) += msm8610-cdp.dtb
- dtb-$(CONFIG_ARCH_MSM8610) += msm8610-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v1-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v2-cdp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v1-mtp.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v2-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-rumi.dtb
dtb-$(CONFIG_ARCH_MSM8610) += msm8610-sim.dtb
- dtb-$(CONFIG_ARCH_MSM8610) += msm8610-qrd-skuaa.dtb
- dtb-$(CONFIG_ARCH_MSM8610) += msm8610-qrd-skuab.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v1-qrd-skuaa.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v1-qrd-skuab.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v2-qrd-skuaa.dtb
+ dtb-$(CONFIG_ARCH_MSM8610) += msm8610-v2-qrd-skuab.dtb
# MSMSAMARIUM
zreladdr-$(CONFIG_ARCH_MSMSAMARIUM) := 0x00008000
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 39916ef..f8c206b 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -240,6 +240,7 @@
#define GFX3D_CMD_RCGR 0x4000
#define OXILI_GFX3D_CBCR 0x4028
#define OXILI_GFX3D_BCR 0x4030
+#define GMEM_GFX3D_BCR 0x4040
#define OXILI_AHB_BCR 0x4044
#define OXILI_AHB_CBCR 0x403C
#define AHB_CMD_RCGR 0x5000
@@ -2147,6 +2148,7 @@
static struct branch_clk csi_vfe_clk = {
.cbcr_reg = CSI_VFE_CBCR,
+ .bcr_reg = CSI_VFE_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2217,6 +2219,7 @@
static struct branch_clk gmem_gfx3d_clk = {
.cbcr_reg = GMEM_GFX3D_CBCR,
+ .bcr_reg = GMEM_GFX3D_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2358,6 +2361,7 @@
static struct branch_clk oxili_ahb_clk = {
.cbcr_reg = OXILI_AHB_CBCR,
+ .bcr_reg = OXILI_AHB_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2369,6 +2373,7 @@
static struct branch_clk oxili_gfx3d_clk = {
.cbcr_reg = OXILI_GFX3D_CBCR,
+ .bcr_reg = OXILI_GFX3D_BCR,
.has_sibling = 0,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2381,6 +2386,7 @@
static struct branch_clk vfe_clk = {
.cbcr_reg = VFE_CBCR,
+ .bcr_reg = VFE_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2393,6 +2399,7 @@
static struct branch_clk vfe_ahb_clk = {
.cbcr_reg = VFE_AHB_CBCR,
+ .bcr_reg = VFE_AHB_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
.c = {
@@ -2404,6 +2411,7 @@
static struct branch_clk vfe_axi_clk = {
.cbcr_reg = VFE_AXI_CBCR,
+ .bcr_reg = VFE_AXI_BCR,
.has_sibling = 1,
.base = &virt_bases[MMSS_BASE],
/* FIXME: Remove this once simulation is fixed. */
@@ -3133,6 +3141,14 @@
CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "fd404000.qcom,qcrypto"),
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "fd404000.qcom,qcrypto"),
CLK_LOOKUP("core_clk_src", ce1_clk_src.c, "fd404000.qcom,qcrypto"),
+
+ /* GDSC clocks */
+ CLK_LOOKUP("core_clk", vfe_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("iface_clk", vfe_ahb_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("bus_clk", vfe_axi_clk.c, "fd8c36a4.qcom,gdsc"),
+ CLK_LOOKUP("core_clk", oxili_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
+ CLK_LOOKUP("iface_clk", oxili_ahb_clk.c, "fd8c4034.qcom,gdsc"),
+ CLK_LOOKUP("mem_clk", gmem_gfx3d_clk.c, "fd8c4034.qcom,gdsc"),
};
static struct clk_lookup msm_clocks_8610_rumi[] = {
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index b7852fe..4488869 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -549,19 +549,21 @@
u32 cbcr_val;
unsigned long irq_flags;
struct branch_clk *branch = to_branch_clk(c);
- int ret = 0;
+ int delay_us = 0, ret = 0;
spin_lock_irqsave(&local_clock_reg_lock, irq_flags);
cbcr_val = readl_relaxed(CBCR_REG(branch));
switch (flags) {
case CLKFLAG_RETAIN_PERIPH:
cbcr_val |= BIT(13);
+ delay_us = 1;
break;
case CLKFLAG_NORETAIN_PERIPH:
cbcr_val &= ~BIT(13);
break;
case CLKFLAG_RETAIN_MEM:
cbcr_val |= BIT(14);
+ delay_us = 1;
break;
case CLKFLAG_NORETAIN_MEM:
cbcr_val &= ~BIT(14);
@@ -570,17 +572,11 @@
ret = -EINVAL;
}
writel_relaxed(cbcr_val, CBCR_REG(branch));
- /*
- * 8974v2.2 has a requirement that writes to set bits 13 and 14 are
- * separated by at least 2 bus cycles. Cover one of these cycles by
- * performing an extra write here. The other cycle is covered by the
- * read-modify-write design of this function.
- */
- writel_relaxed(cbcr_val, CBCR_REG(branch));
- spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
-
- /* Make sure write is issued before returning. */
+ /* Make sure power is enabled before returning. */
mb();
+ udelay(delay_us);
+
+ spin_unlock_irqrestore(&local_clock_reg_lock, irq_flags);
return ret;
}
diff --git a/arch/arm/mach-msm/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 774548c..ea4865d 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -111,6 +111,13 @@
uint32_t regval;
int i, ret = 0;
+ for (i = sc->clock_count-1; i >= 0; i--) {
+ if (sc->toggle_mem)
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ if (sc->toggle_periph)
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
+
if (sc->toggle_logic) {
regval = readl_relaxed(sc->gdscr);
regval |= SW_COLLAPSE_MASK;
@@ -123,18 +130,11 @@
dev_err(&rdev->dev, "%s disable timed out\n",
sc->rdesc.name);
} else {
- for (i = 0; i < sc->clock_count; i++)
+ for (i = sc->clock_count-1; i >= 0; i--)
clk_reset(sc->clocks[i], CLK_RESET_ASSERT);
sc->resets_asserted = true;
}
- for (i = 0; i < sc->clock_count; i++) {
- if (sc->toggle_mem)
- clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
- if (sc->toggle_periph)
- clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
- }
-
return ret;
}
@@ -225,20 +225,9 @@
retain_mem = of_property_read_bool(pdev->dev.of_node,
"qcom,retain-mem");
+ sc->toggle_mem = !retain_mem;
retain_periph = of_property_read_bool(pdev->dev.of_node,
"qcom,retain-periph");
- for (i = 0; i < sc->clock_count; i++) {
- if (retain_mem || (regval & PWR_ON_MASK))
- clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
- else
- clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
-
- if (retain_periph || (regval & PWR_ON_MASK))
- clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
- else
- clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
- }
- sc->toggle_mem = !retain_mem;
sc->toggle_periph = !retain_periph;
sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
"qcom,skip-logic-collapse");
@@ -255,6 +244,18 @@
}
}
+ for (i = 0; i < sc->clock_count; i++) {
+ if (retain_mem || (regval & PWR_ON_MASK))
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ else
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+
+ if (retain_periph || (regval & PWR_ON_MASK))
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ else
+ clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
+ }
+
sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
pdev->dev.of_node);
if (IS_ERR(sc->rdev)) {
diff --git a/arch/arm/mach-msm/krait-regulator-pmic.c b/arch/arm/mach-msm/krait-regulator-pmic.c
new file mode 100644
index 0000000..5081e7b
--- /dev/null
+++ b/arch/arm/mach-msm/krait-regulator-pmic.c
@@ -0,0 +1,403 @@
+/* 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.
+ */
+
+#define pr_fmt(fmt) "PMIC PDN %s: " fmt, __func__
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/spmi.h>
+#include <linux/delay.h>
+
+#define KRAIT_REG_PMIC_DEV_NAME "qcom,krait-regulator-pmic"
+
+#define REG_DIG_MAJOR 0x01
+#define REG_DIG_MINOR 0x00
+
+#define REG_PERPH_TYPE 0x04
+#define CTRL_TYPE_VAL 0x1C
+#define PS_TYPE_VAL 0x1C
+#define FREQ_TYPE_VAL 0x1D
+
+#define REG_PERPH_SUBTYPE 0x05
+#define CTRL_SUBTYPE_VAL 0x08
+#define PS_SUBTYPE_VAL 0x01
+#define FREQ_SUBTYPE_VAL 0x19
+
+#define REG_V_CTL1 0x40
+#define V_CTL1_VAL 0x00
+
+#define REG_MODE_CTL 0x45
+#define NPM_MODE_BIT BIT(7)
+#define AUTO_MODE_BIT BIT(6)
+
+#define REG_EN_CTL 0x46
+#define EN_BIT BIT(7)
+
+#define REG_PD_CTL 0x48
+#define PD_CTL_VAL 0x08
+
+#define REG_MULTIPHASE_CTL 0x51
+#define MULTIPHASE_EN_BIT BIT(7)
+
+#define REG_PHASE_CTL 0x52
+#define BALANCE_EN_BIT BIT(7)
+
+#define REG_VS_CTL 0x61
+#define VS_CTL_VAL 0x85
+
+#define REG_GANG_CTL2 0xC1
+#define GANG_EN_BIT BIT(7)
+
+#define REG_PWM_CL 0x60
+
+struct krait_vreg_pmic_chip {
+ struct spmi_device *spmi;
+ u16 ctrl_base;
+ u16 ps_base;
+ u16 freq_base;
+ u8 ctrl_dig_major;
+ u8 ctrl_dig_minor;
+};
+
+static struct krait_vreg_pmic_chip *the_chip;
+
+static struct of_device_id krait_vreg_pmic_match_table[] = {
+ { .compatible = KRAIT_REG_PMIC_DEV_NAME },
+ {}
+};
+
+static int read_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+{
+ int rc;
+
+ rc = spmi_ext_register_readl(spmi->ctrl, spmi->sid, addr, val, 1);
+ if (rc) {
+ pr_err("SPMI read failed [%d,0x%04x] rc=%d\n",
+ spmi->sid, addr, rc);
+ return rc;
+ }
+ return 0;
+}
+
+static int write_byte(struct spmi_device *spmi, u16 addr, u8 *val)
+{
+ int rc;
+
+ rc = spmi_ext_register_writel(spmi->ctrl, spmi->sid, addr, val, 1);
+ if (rc) {
+ pr_err("SPMI write failed [%d,0x%04x] val = 0x%02x rc=%d\n",
+ spmi->sid, addr, *val, rc);
+ return rc;
+ }
+ return 0;
+}
+
+#define ISTEP_MA 500
+#define IOFFSET_MA 1000
+#define OVERSHOOT_DIG_MAJOR 1
+#define OVERSHOOT_DIG_MINOR 1
+static bool v_overshoot_fixed(void)
+{
+ if (the_chip->ctrl_dig_major > OVERSHOOT_DIG_MAJOR
+ || (the_chip->ctrl_dig_major == OVERSHOOT_DIG_MAJOR
+ && the_chip->ctrl_dig_minor > OVERSHOOT_DIG_MINOR)) {
+ pr_debug("fixed in h/w\n");
+ return true;
+ }
+ return false;
+}
+
+/**
+ * krait_pmic_is_ready - function to check if the driver is initialized
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: true if this driver has initialized, false otherwise
+ */
+bool krait_pmic_is_ready(void)
+{
+ if (the_chip == NULL) {
+ pr_debug("kait_regulator_pmic not ready yet\n");
+ return false;
+ }
+ return true;
+}
+EXPORT_SYMBOL(krait_pmic_is_ready);
+
+#define I_PFM_MA 2000
+
+/**
+ * krait_pmic_post_pfm_entry - workarounds after entering pfm mode
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: 0 on success, error code on failure
+ */
+int krait_pmic_post_pfm_entry(void)
+{
+ u8 setpoint;
+ int rc;
+
+ if (the_chip == NULL) {
+ pr_debug("kait_regulator_pmic not ready yet\n");
+ return -ENXIO;
+ }
+
+ if (v_overshoot_fixed())
+ return 0;
+
+ setpoint = (I_PFM_MA - IOFFSET_MA) / ISTEP_MA;
+ rc = write_byte(the_chip->spmi,
+ the_chip->ps_base + REG_PWM_CL, &setpoint);
+ pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
+ the_chip->spmi->sid,
+ the_chip->ps_base + REG_PWM_CL, rc);
+ return rc;
+}
+EXPORT_SYMBOL(krait_pmic_post_pfm_entry);
+
+#define I_PWM_MA 3500
+/**
+ * krait_pmic_post_pwm_entry - workarounds after entering pwm mode
+ *
+ * CONTEXT: Can be called in atomic context
+ *
+ * RETURNS: 0 on success, error code on failure
+ */
+int krait_pmic_post_pwm_entry(void)
+{
+ u8 setpoint;
+ int rc;
+
+ if (the_chip == NULL) {
+ pr_debug("kait_regulator_pmic not ready yet\n");
+ return -ENXIO;
+ }
+
+ if (v_overshoot_fixed())
+ return 0;
+
+ udelay(50);
+ setpoint = (I_PWM_MA - IOFFSET_MA) / ISTEP_MA;
+
+ rc = write_byte(the_chip->spmi,
+ the_chip->ps_base + REG_PWM_CL, &setpoint);
+ pr_debug("wrote 0x%02x->[%d 0x%04x] rc = %d\n", setpoint,
+ the_chip->spmi->sid,
+ the_chip->ps_base + REG_PWM_CL, rc);
+ return rc;
+}
+EXPORT_SYMBOL(krait_pmic_post_pwm_entry);
+
+#define READ_BYTE(chip, addr, val, rc) \
+do { \
+ rc = read_byte(chip->spmi, (addr), &val); \
+ if (rc) \
+ pr_err("register read failed rc=%d\n", rc); \
+} while (0)
+
+#define GANGED_VREG_COUNT 4
+static int gang_configuration_check(struct krait_vreg_pmic_chip *chip)
+{
+ u8 val;
+ int rc;
+ int i;
+
+ return 0;
+
+ READ_BYTE(chip, chip->ctrl_base + REG_V_CTL1, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(val != V_CTL1_VAL);
+
+ READ_BYTE(chip, chip->ctrl_base + REG_MODE_CTL, val, rc);
+ if (rc)
+ return rc;
+ /* The Auto mode should be off */
+ BUG_ON(val & AUTO_MODE_BIT);
+ /* The NPM mode should be on */
+ BUG_ON(!(val & NPM_MODE_BIT));
+
+ READ_BYTE(chip, chip->ctrl_base + REG_EN_CTL, val, rc);
+ if (rc)
+ return rc;
+ /* The en bit should be set */
+ BUG_ON(val & EN_BIT);
+
+ READ_BYTE(chip, chip->ctrl_base + REG_PD_CTL, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(val != PD_CTL_VAL);
+
+ READ_BYTE(chip, chip->ctrl_base + REG_MULTIPHASE_CTL, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(!(val & MULTIPHASE_EN_BIT));
+
+ READ_BYTE(chip, chip->ctrl_base + REG_PHASE_CTL, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(!(val & BALANCE_EN_BIT));
+
+ READ_BYTE(chip, chip->ctrl_base + REG_VS_CTL, val, rc);
+ if (rc)
+ return rc;
+ BUG_ON(val != VS_CTL_VAL);
+
+ for (i = 0; i < GANGED_VREG_COUNT; i++) {
+ READ_BYTE(chip,
+ chip->ctrl_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+ if (rc)
+ return rc;
+
+ if (!(val & GANG_EN_BIT)) {
+ pr_err("buck = %d, ctrl gang not enabled\n", i);
+ BUG();
+ }
+ }
+
+ for (i = 0; i < GANGED_VREG_COUNT; i++) {
+ READ_BYTE(chip,
+ chip->ps_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+ if (rc)
+ return rc;
+
+ if (!(val & GANG_EN_BIT)) {
+ pr_err("buck = %d, ps gang not enabled\n", i);
+ BUG();
+ }
+ }
+
+ for (i = 0; i < GANGED_VREG_COUNT; i++) {
+ READ_BYTE(chip,
+ chip->freq_base + i * 0x300 + REG_GANG_CTL2, val, rc);
+ if (rc)
+ return rc;
+
+ if (!(val & GANG_EN_BIT)) {
+ pr_err("buck = %d, freq gang not enabled\n", i);
+ BUG();
+ }
+ }
+ return 0;
+}
+
+static int __devinit krait_vreg_pmic_probe(struct spmi_device *spmi)
+{
+ u8 type, subtype;
+ int rc;
+ struct krait_vreg_pmic_chip *chip;
+ struct spmi_resource *spmi_resource;
+ struct resource *resource;
+
+ chip = devm_kzalloc(&spmi->dev, sizeof *chip, GFP_KERNEL);
+ if (chip == NULL) {
+ pr_err("kzalloc() failed.\n");
+ return -ENOMEM;
+ }
+
+ chip->spmi = spmi;
+
+ spmi_for_each_container_dev(spmi_resource, spmi) {
+ if (!spmi_resource) {
+ pr_err("spmi resource absent\n");
+ return -ENXIO;
+ }
+
+ resource = spmi_get_resource(spmi, spmi_resource,
+ IORESOURCE_MEM, 0);
+ if (!(resource && resource->start)) {
+ pr_err("node %s IO resource absent!\n",
+ spmi->dev.of_node->full_name);
+ return -ENXIO;
+ }
+
+ rc = read_byte(chip->spmi,
+ resource->start + REG_PERPH_TYPE,
+ &type);
+ if (rc) {
+ pr_err("Peripheral type read failed rc=%d\n", rc);
+ return -ENXIO;
+ }
+
+ rc = read_byte(chip->spmi,
+ resource->start + REG_PERPH_SUBTYPE,
+ &subtype);
+ if (rc) {
+ pr_err("Peripheral subtype read failed rc=%d\n", rc);
+ return -ENXIO;
+ }
+
+ if (type == CTRL_TYPE_VAL && subtype == CTRL_SUBTYPE_VAL)
+ chip->ctrl_base = resource->start;
+ else if (type == PS_TYPE_VAL && subtype == PS_SUBTYPE_VAL)
+ chip->ps_base = resource->start;
+ else if (type == FREQ_TYPE_VAL && subtype == FREQ_SUBTYPE_VAL)
+ chip->freq_base = resource->start;
+ }
+
+ if (chip->ctrl_base == 0) {
+ pr_err("ctrl base address missing\n");
+ return -ENXIO;
+ }
+
+ if (chip->ps_base == 0) {
+ pr_err("ps base address missing\n");
+ return -ENXIO;
+ }
+
+ if (chip->freq_base == 0) {
+ pr_err("freq base address missing\n");
+ return -ENXIO;
+ }
+
+ READ_BYTE(chip, chip->ctrl_base + REG_DIG_MAJOR,
+ chip->ctrl_dig_major, rc);
+ if (rc)
+ return rc;
+
+ READ_BYTE(chip, chip->ctrl_base + REG_DIG_MINOR,
+ chip->ctrl_dig_minor, rc);
+ if (rc)
+ return rc;
+
+ gang_configuration_check(chip);
+
+ the_chip = chip;
+ return 0;
+}
+
+static struct spmi_driver qpnp_revid_driver = {
+ .probe = krait_vreg_pmic_probe,
+ .driver = {
+ .name = KRAIT_REG_PMIC_DEV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = krait_vreg_pmic_match_table,
+ },
+};
+
+static int __init qpnp_revid_init(void)
+{
+ return spmi_driver_register(&qpnp_revid_driver);
+}
+
+static void __exit qpnp_revid_exit(void)
+{
+ return spmi_driver_unregister(&qpnp_revid_driver);
+}
+
+module_init(qpnp_revid_init);
+module_exit(qpnp_revid_exit);
+
+MODULE_DESCRIPTION("KRAIT REGULATOR PMIC DRIVER");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/krait-regulator-pmic.h b/arch/arm/mach-msm/krait-regulator-pmic.h
new file mode 100644
index 0000000..06ca3ea
--- /dev/null
+++ b/arch/arm/mach-msm/krait-regulator-pmic.h
@@ -0,0 +1,18 @@
+/* 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 __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
+#define __ARCH_ARM_MACH_MSM_KRAIT_REGULATOR_PMIC_H
+bool krait_pmic_is_ready(void);
+int krait_pmic_post_pfm_entry(void);
+int krait_pmic_post_pwm_entry(void);
+#endif
diff --git a/arch/arm/mach-msm/krait-regulator.c b/arch/arm/mach-msm/krait-regulator.c
index 9c5f197..4b2259e 100644
--- a/arch/arm/mach-msm/krait-regulator.c
+++ b/arch/arm/mach-msm/krait-regulator.c
@@ -29,7 +29,9 @@
#include <linux/regulator/krait-regulator.h>
#include <linux/debugfs.h>
#include <linux/syscore_ops.h>
+#include <linux/cpu.h>
#include <mach/msm_iomap.h>
+#include "krait-regulator-pmic.h"
#include "spm.h"
#include "pm.h"
@@ -222,8 +224,9 @@
int cpu_num;
int coeff1;
int coeff2;
- bool online;
+ bool reg_en;
int online_at_probe;
+ bool force_bhs;
};
DEFINE_PER_CPU(struct krait_power_vreg *, krait_vregs);
@@ -372,7 +375,7 @@
phase_scaling_factor = pvreg->efuse_phase_scaling_factor;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (!kvreg->online)
+ if (!kvreg->reg_en)
continue;
if (kvreg->mode == LDO_MODE) {
@@ -414,7 +417,7 @@
struct krait_power_vreg *kvreg;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (kvreg->online)
+ if (kvreg->reg_en)
online_total++;
}
return online_total;
@@ -427,7 +430,7 @@
struct pmic_gang_vreg *pvreg = from->pvreg;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (!kvreg->online)
+ if (!kvreg->reg_en)
continue;
load_total += kvreg->load;
}
@@ -474,16 +477,18 @@
}
/* First check if the coeff is low for PFM mode */
- if (load_total <= pvreg->pfm_threshold && n_online == 1) {
+ if (load_total <= pvreg->pfm_threshold
+ && n_online == 1
+ && krait_pmic_is_ready()) {
if (!pvreg->pfm_mode) {
rc = msm_spm_enable_fts_lpm(PMIC_FTS_MODE_PFM);
if (rc) {
pr_err("%s PFM en failed load_t %d rc = %d\n",
from->name, load_total, rc);
return rc;
- } else {
- pvreg->pfm_mode = true;
}
+ krait_pmic_post_pfm_entry();
+ pvreg->pfm_mode = true;
}
return rc;
}
@@ -495,10 +500,10 @@
pr_err("%s PFM exit failed load %d rc = %d\n",
from->name, coeff_total, rc);
return rc;
- } else {
- pvreg->pfm_mode = false;
- udelay(PWM_SETTLING_TIME_US);
}
+ pvreg->pfm_mode = false;
+ krait_pmic_post_pwm_entry();
+ udelay(PWM_SETTLING_TIME_US);
}
/* calculate phases */
@@ -565,7 +570,7 @@
mutex_lock(&pvreg->krait_power_vregs_lock);
kvreg->load = load_uA;
- if (!kvreg->online) {
+ if (!kvreg->reg_en) {
mutex_unlock(&pvreg->krait_power_vregs_lock);
return kvreg->mode;
}
@@ -588,10 +593,10 @@
return kvreg->mode;
}
-static int switch_to_using_hs(struct krait_power_vreg *kvreg)
+static void __switch_to_using_bhs(void *info)
{
- if (kvreg->mode == HS_MODE)
- return 0;
+ struct krait_power_vreg *kvreg = info;
+
/* enable bhs */
if (version > KPSS_VERSION_2P0) {
krait_masked_write(kvreg, APC_PWR_GATE_MODE,
@@ -645,21 +650,18 @@
kvreg->mode = HS_MODE;
pr_debug("%s using BHS\n", kvreg->name);
- return 0;
}
-static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+static void __switch_to_using_ldo(void *info)
{
- if (kvreg->mode == LDO_MODE
- && get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
- return 0;
+ struct krait_power_vreg *kvreg = info;
/*
* if the krait is in ldo mode and a voltage change is requested on the
* ldo switch to using hs before changing ldo voltage
*/
if (kvreg->mode == LDO_MODE)
- switch_to_using_hs(kvreg);
+ __switch_to_using_bhs(kvreg);
set_krait_ldo_uv(kvreg, kvreg->uV - kvreg->ldo_delta_uV);
if (version > KPSS_VERSION_2P0) {
@@ -698,7 +700,25 @@
kvreg->mode = LDO_MODE;
pr_debug("%s using LDO\n", kvreg->name);
- return 0;
+}
+
+static int switch_to_using_ldo(struct krait_power_vreg *kvreg)
+{
+ if (kvreg->mode == LDO_MODE
+ && get_krait_ldo_uv(kvreg) == kvreg->uV - kvreg->ldo_delta_uV)
+ return 0;
+
+ return smp_call_function_single(kvreg->cpu_num,
+ __switch_to_using_ldo, kvreg, 1);
+}
+
+static int switch_to_using_bhs(struct krait_power_vreg *kvreg)
+{
+ if (kvreg->mode == HS_MODE)
+ return 0;
+
+ return smp_call_function_single(kvreg->cpu_num,
+ __switch_to_using_bhs, kvreg, 1);
}
static int set_pmic_gang_voltage(struct pmic_gang_vreg *pvreg, int uV)
@@ -750,6 +770,41 @@
return rc;
}
+static int configure_ldo_or_hs_one(struct krait_power_vreg *kvreg, int vmax)
+{
+ int rc;
+
+ if (!kvreg->reg_en)
+ return 0;
+
+ if (kvreg->force_bhs)
+ /*
+ * The cpu is in transitory phase where it is being
+ * prepared to be offlined or onlined and is being
+ * forced to run on BHS during that time
+ */
+ return 0;
+
+ if (kvreg->uV <= kvreg->ldo_threshold_uV
+ && kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
+ <= vmax) {
+ rc = switch_to_using_ldo(kvreg);
+ if (rc < 0) {
+ pr_err("could not switch %s to ldo rc = %d\n",
+ kvreg->name, rc);
+ return rc;
+ }
+ } else {
+ rc = switch_to_using_bhs(kvreg);
+ if (rc < 0) {
+ pr_err("could not switch %s to hs rc = %d\n",
+ kvreg->name, rc);
+ return rc;
+ }
+ }
+ return 0;
+}
+
static int configure_ldo_or_hs_all(struct krait_power_vreg *from, int vmax)
{
struct pmic_gang_vreg *pvreg = from->pvreg;
@@ -757,27 +812,12 @@
int rc = 0;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (!kvreg->online)
- continue;
- if (kvreg->uV <= kvreg->ldo_threshold_uV
- && kvreg->uV - kvreg->ldo_delta_uV + kvreg->headroom_uV
- <= vmax) {
- rc = switch_to_using_ldo(kvreg);
- if (rc < 0) {
- pr_err("could not switch %s to ldo rc = %d\n",
- kvreg->name, rc);
- return rc;
- }
- } else {
- rc = switch_to_using_hs(kvreg);
- if (rc < 0) {
- pr_err("could not switch %s to hs rc = %d\n",
- kvreg->name, rc);
- return rc;
- }
+ rc = configure_ldo_or_hs_one(kvreg, vmax);
+ if (rc) {
+ pr_err("could not switch %s\n", kvreg->name);
+ break;
}
}
-
return rc;
}
@@ -856,7 +896,7 @@
struct krait_power_vreg *kvreg;
list_for_each_entry(kvreg, &pvreg->krait_power_vregs, link) {
- if (!kvreg->online)
+ if (!kvreg->reg_en)
continue;
v = kvreg->uV;
@@ -896,7 +936,7 @@
rc = krait_voltage_decrease(kvreg, vmax);
if (rc < 0) {
- dev_err(&rdev->dev, "%s failed to set %duV from %duV rc = %d\n",
+ pr_err("%s failed to set %duV from %duV rc = %d\n",
kvreg->name, requested_uV, orig_krait_uV, rc);
}
@@ -927,7 +967,7 @@
}
mutex_lock(&pvreg->krait_power_vregs_lock);
- if (!kvreg->online) {
+ if (!kvreg->reg_en) {
kvreg->uV = min_uV;
mutex_unlock(&pvreg->krait_power_vregs_lock);
return 0;
@@ -943,7 +983,7 @@
{
struct krait_power_vreg *kvreg = rdev_get_drvdata(rdev);
- return kvreg->online;
+ return kvreg->reg_en;
}
static int krait_power_enable(struct regulator_dev *rdev)
@@ -953,8 +993,9 @@
int rc;
mutex_lock(&pvreg->krait_power_vregs_lock);
+ pr_debug("enable %s\n", kvreg->name);
__krait_power_mdd_enable(kvreg, true);
- kvreg->online = true;
+ kvreg->reg_en = true;
rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
if (rc < 0)
goto en_err;
@@ -975,7 +1016,8 @@
int rc;
mutex_lock(&pvreg->krait_power_vregs_lock);
- kvreg->online = false;
+ pr_debug("disable %s\n", kvreg->name);
+ kvreg->reg_en = false;
rc = _get_optimum_mode(rdev, kvreg->uV, kvreg->uV, kvreg->load);
if (rc < 0)
@@ -999,6 +1041,69 @@
.is_enabled = krait_power_is_enabled,
};
+static int krait_regulator_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ int cpu = (int)hcpu;
+ struct krait_power_vreg *kvreg = per_cpu(krait_vregs, cpu);
+ struct pmic_gang_vreg *pvreg = kvreg->pvreg;
+
+ pr_debug("start state=0x%02x, cpu=%d is_online=%d\n",
+ (int)action, cpu, cpu_online(cpu));
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_UP_PREPARE:
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ kvreg->force_bhs = true;
+ /*
+ * cpu is offline at this point, force bhs on which ever cpu
+ * this callback is running on
+ */
+ pr_debug("%s force BHS locally\n", kvreg->name);
+ __switch_to_using_bhs(kvreg);
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ break;
+ case CPU_UP_CANCELED:
+ case CPU_ONLINE:
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ kvreg->force_bhs = false;
+ /*
+ * switch the cpu to proper bhs/ldo, the cpu is online at this
+ * point. The gang voltage and mode votes for the cpu were
+ * submitted in CPU_UP_PREPARE phase
+ */
+ configure_ldo_or_hs_one(kvreg, pvreg->pmic_vmax_uV);
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ break;
+ case CPU_DOWN_PREPARE:
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ kvreg->force_bhs = true;
+ /*
+ * switch the cpu to run on bhs using smp function calls. Note
+ * that the cpu is online at this point.
+ */
+ pr_debug("%s force BHS remotely\n", kvreg->name);
+ switch_to_using_bhs(kvreg);
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ break;
+ case CPU_DOWN_FAILED:
+ mutex_lock(&pvreg->krait_power_vregs_lock);
+ kvreg->force_bhs = false;
+ configure_ldo_or_hs_one(kvreg, pvreg->pmic_vmax_uV);
+ mutex_unlock(&pvreg->krait_power_vregs_lock);
+ break;
+ default:
+ break;
+ }
+
+ pr_debug("done state=0x%02x, cpu=%d is_online=%d\n",
+ (int)action, cpu, cpu_online(cpu));
+ return NOTIFY_OK;
+}
+
+static struct notifier_block krait_cpu_notifier = {
+ .notifier_call = krait_regulator_cpu_callback,
+};
+
static struct dentry *dent;
static int get_retention_dbg_uV(void *data, u64 *val)
{
@@ -1481,11 +1586,14 @@
KRAIT_REGULATOR_DRIVER_NAME, rc);
return rc;
}
+
+ register_hotcpu_notifier(&krait_cpu_notifier);
return platform_driver_register(&krait_pdn_driver);
}
static void __exit krait_power_exit(void)
{
+ unregister_hotcpu_notifier(&krait_cpu_notifier);
platform_driver_unregister(&krait_power_driver);
platform_driver_unregister(&krait_pdn_driver);
}
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_id.c b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
index 7e9883f..25a749a 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_id.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_id.c
@@ -35,16 +35,22 @@
if (!fabreg->info[i].gateway) {
fabreg->info[i].priv_id = fabid + fabreg->info[i].id;
if (fabreg->info[i].id < SLAVE_ID_KEY) {
- WARN(fabreg->info[i].id >= MSM_BUS_MASTER_LAST,
- "id %d exceeds array size!\n",
- fabreg->info[i].id);
+ if (fabreg->info[i].id >= MSM_BUS_MASTER_LAST) {
+ WARN(1, "id %d exceeds array size!\n",
+ fabreg->info[i].id);
+ continue;
+ }
+
master_iids[fabreg->info[i].id] =
fabreg->info[i].priv_id;
} else {
- WARN((fabreg->info[i].id - SLAVE_ID_KEY) >=
- (MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY),
- "id %d exceeds array size!\n",
- fabreg->info[i].id);
+ if ((fabreg->info[i].id - SLAVE_ID_KEY) >=
+ (MSM_BUS_SLAVE_LAST - SLAVE_ID_KEY)) {
+ WARN(1, "id %d exceeds array size!\n",
+ fabreg->info[i].id);
+ continue;
+ }
+
slave_iids[fabreg->info[i].id - (SLAVE_ID_KEY)]
= fabreg->info[i].priv_id;
}
diff --git a/arch/arm/mach-msm/msm_cache_dump.c b/arch/arm/mach-msm/msm_cache_dump.c
index 86e8963..a5593bf 100644
--- a/arch/arm/mach-msm/msm_cache_dump.c
+++ b/arch/arm/mach-msm/msm_cache_dump.c
@@ -23,15 +23,16 @@
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/dma-mapping.h>
#include <mach/scm.h>
#include <mach/msm_cache_dump.h>
-#include <mach/memory.h>
#include <mach/msm_iomap.h>
#include <mach/msm_memory_dump.h>
#define L2_DUMP_OFFSET 0x14
-static unsigned long msm_cache_dump_addr;
+static dma_addr_t msm_cache_dump_addr;
+static void *msm_cache_dump_vaddr;
/*
* These should not actually be dereferenced. There's no
@@ -76,7 +77,6 @@
unsigned long buf;
unsigned long size;
} l1_cache_data;
- void *temp;
u32 l1_size, l2_size;
unsigned long total_size;
@@ -102,19 +102,20 @@
};
total_size = l1_size + l2_size;
- msm_cache_dump_addr = allocate_contiguous_ebi_nomap(total_size, SZ_4K);
+ msm_cache_dump_vaddr = (void *) dma_alloc_coherent(&pdev->dev,
+ total_size, &msm_cache_dump_addr,
+ GFP_KERNEL);
- if (!msm_cache_dump_addr) {
+ if (!msm_cache_dump_vaddr) {
pr_err("%s: Could not get memory for cache dumping\n",
__func__);
return -ENOMEM;
}
- temp = ioremap(msm_cache_dump_addr, total_size);
- memset(temp, 0xFF, total_size);
+ memset(msm_cache_dump_vaddr, 0xFF, total_size);
/* Clean caches before sending buffer to TZ */
- clean_caches((unsigned long) temp, total_size, msm_cache_dump_addr);
- iounmap(temp);
+ clean_caches((unsigned long) msm_cache_dump_vaddr, total_size,
+ msm_cache_dump_addr);
l1_cache_data.buf = msm_cache_dump_addr;
l1_cache_data.size = l1_size;
@@ -126,8 +127,9 @@
pr_err("%s: could not register L1 buffer ret = %d.\n",
__func__, ret);
- l1_dump = (struct l1_cache_dump *)msm_cache_dump_addr;
- l2_dump = (struct l2_cache_dump *)(msm_cache_dump_addr + l1_size);
+ l1_dump = (struct l1_cache_dump *)(uint32_t)msm_cache_dump_addr;
+ l2_dump = (struct l2_cache_dump *)(uint32_t)(msm_cache_dump_addr
+ + l1_size);
#if defined(CONFIG_MSM_CACHE_DUMP_ON_PANIC)
l1_cache_data.buf = msm_cache_dump_addr + l1_size;
diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c
index a24fc54..aa88b37 100644
--- a/drivers/char/diag/diag_debugfs.c
+++ b/drivers/char/diag/diag_debugfs.c
@@ -350,19 +350,21 @@
bytes_written = scnprintf(buf+bytes_in_buffer, bytes_remaining,
"i: %3d, cmd_code: %4x, subsys_id: %4x, "
"client: %2d, cmd_code_lo: %4x, "
- "cmd_code_hi: %4x, process_id: %5d\n",
+ "cmd_code_hi: %4x, process_id: %5d %s\n",
i,
driver->table[i].cmd_code,
driver->table[i].subsys_id,
driver->table[i].client_id,
driver->table[i].cmd_code_lo,
driver->table[i].cmd_code_hi,
- driver->table[i].process_id);
+ driver->table[i].process_id,
+ (diag_find_polling_reg(i) ? "<- Polling cmd reg" : ""));
bytes_in_buffer += bytes_written;
/* Check if there is room to add another table entry */
bytes_remaining = buf_size - bytes_in_buffer;
+
if (bytes_remaining < bytes_written)
break;
}
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index c91095e..755f0a1 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -19,9 +19,13 @@
#include "diagfwd_cntl.h"
#include "diag_masks.h"
-int diag_event_config;
int diag_event_num_bytes;
+#define DIAG_CTRL_MASK_INVALID 0
+#define DIAG_CTRL_MASK_ALL_DISABLED 1
+#define DIAG_CTRL_MASK_ALL_ENABLED 2
+#define DIAG_CTRL_MASK_VALID 3
+
#define ALL_EQUIP_ID 100
#define ALL_SSID -1
#define MAX_SSID_PER_RANGE 100
@@ -106,6 +110,8 @@
uint8_t *parse_ptr, *ptr = driver->msg_masks;
mutex_lock(&driver->diagchar_mutex);
+ driver->msg_status = rt_mask ? DIAG_CTRL_MASK_ALL_ENABLED :
+ DIAG_CTRL_MASK_ALL_DISABLED;
while (*(uint32_t *)(ptr + 4)) {
first_ssid = *(uint32_t *)ptr;
ptr += 8; /* increment by 8 to skip 'last' */
@@ -131,7 +137,6 @@
uint8_t *ptr_buffer_end = &(*(driver->msg_masks)) + MSG_MASK_SIZE;
mutex_lock(&driver->diagchar_mutex);
-
/* First SSID can be zero : So check that last is non-zero */
while (*(uint32_t *)(ptr + 4)) {
first = *(uint32_t *)ptr;
@@ -177,6 +182,7 @@
} else
pr_alert("diag: Not enough buffer space for MSG_MASK\n");
}
+ driver->msg_status = DIAG_CTRL_MASK_VALID;
mutex_unlock(&driver->diagchar_mutex);
diag_print_mask_table();
}
@@ -186,28 +192,29 @@
uint8_t *ptr = driver->event_masks;
mutex_lock(&driver->diagchar_mutex);
- if (toggle)
+ if (toggle) {
+ driver->event_status = DIAG_CTRL_MASK_ALL_ENABLED;
memset(ptr, 0xFF, EVENT_MASK_SIZE);
- else
+ } else {
+ driver->event_status = DIAG_CTRL_MASK_ALL_DISABLED;
memset(ptr, 0, EVENT_MASK_SIZE);
+ }
mutex_unlock(&driver->diagchar_mutex);
}
-static void diag_update_event_mask(uint8_t *buf, int toggle, int num_bytes)
+static void diag_update_event_mask(uint8_t *buf, int num_bytes)
{
uint8_t *ptr = driver->event_masks;
uint8_t *temp = buf + 2;
mutex_lock(&driver->diagchar_mutex);
- if (!toggle)
- memset(ptr, 0 , EVENT_MASK_SIZE);
- else
- if (CHK_OVERFLOW(ptr, ptr,
- ptr+EVENT_MASK_SIZE, num_bytes))
- memcpy(ptr, temp , num_bytes);
- else
- printk(KERN_CRIT "Not enough buffer space for EVENT_MASK\n");
+ if (CHK_OVERFLOW(ptr, ptr, ptr+EVENT_MASK_SIZE, num_bytes)) {
+ memcpy(ptr, temp, num_bytes);
+ driver->event_status = DIAG_CTRL_MASK_VALID;
+ } else {
+ pr_err("diag: In %s, not enough buffer space\n", __func__);
+ }
mutex_unlock(&driver->diagchar_mutex);
}
@@ -226,6 +233,7 @@
(parse_ptr->num_items + 7)/8);
parse_ptr++;
}
+ driver->log_status = DIAG_CTRL_MASK_ALL_DISABLED;
mutex_unlock(&driver->diagchar_mutex);
}
@@ -282,10 +290,13 @@
}
ptr_data = driver->log_masks + offset;
if (CHK_OVERFLOW(driver->log_masks, ptr_data, driver->log_masks
- + LOG_MASK_SIZE, (num_items+7)/8))
- memcpy(ptr_data, temp , (num_items+7)/8);
- else
+ + LOG_MASK_SIZE, (num_items+7)/8)) {
+ memcpy(ptr_data, temp, (num_items+7)/8);
+ driver->log_status = DIAG_CTRL_MASK_VALID;
+ } else {
pr_err("diag: Not enough buffer space for LOG_MASK\n");
+ driver->log_status = DIAG_CTRL_MASK_INVALID;
+ }
mutex_unlock(&driver->diagchar_mutex);
}
@@ -330,15 +341,36 @@
driver->log_mask->num_items = ptr->num_items;
driver->log_mask->data_len = 11 + size;
driver->log_mask->stream_id = 1; /* 2, if dual stream */
- driver->log_mask->status = 3; /* status for valid mask */
driver->log_mask->equip_id = ptr->equip_id;
- driver->log_mask->log_mask_size = size;
+ driver->log_mask->status = driver->log_status;
+ switch (driver->log_status) {
+ case DIAG_CTRL_MASK_ALL_DISABLED:
+ driver->log_mask->log_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_ALL_ENABLED:
+ driver->log_mask->log_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_VALID:
+ driver->log_mask->log_mask_size = size;
+ break;
+ default:
+ /* Log status is not set or the buffer is corrupted */
+ pr_err("diag: In %s, invalid status %d", __func__,
+ driver->log_status);
+ driver->log_mask->status = DIAG_CTRL_MASK_INVALID;
+ }
+
+ if (driver->msg_mask->status == DIAG_CTRL_MASK_INVALID) {
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return;
+ }
/* send only desired update, NOT ALL */
if (equip_id == ALL_EQUIP_ID || equip_id ==
driver->log_mask->equip_id) {
memcpy(buf, driver->log_mask, header_size);
- memcpy(buf+header_size, driver->log_masks+ptr->index,
- size);
+ if (driver->log_status == DIAG_CTRL_MASK_VALID)
+ memcpy(buf + header_size,
+ driver->log_masks+ptr->index, size);
if (ch) {
while (retry_count < 3) {
wr_size = smd_write(ch, buf,
@@ -380,11 +412,34 @@
driver->event_mask->cmd_type = DIAG_CTRL_MSG_EVENT_MASK;
driver->event_mask->data_len = 7 + num_bytes;
driver->event_mask->stream_id = 1; /* 2, if dual stream */
- driver->event_mask->status = 3; /* status for valid mask */
- driver->event_mask->event_config = diag_event_config; /* event config */
- driver->event_mask->event_mask_size = num_bytes;
+ driver->event_mask->status = driver->event_status;
+
+ switch (driver->event_status) {
+ case DIAG_CTRL_MASK_ALL_DISABLED:
+ driver->event_mask->event_config = 0;
+ driver->event_mask->event_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_ALL_ENABLED:
+ driver->event_mask->event_config = 1;
+ driver->event_mask->event_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_VALID:
+ driver->event_mask->event_config = 1;
+ driver->event_mask->event_mask_size = num_bytes;
+ memcpy(buf + header_size, driver->event_masks, num_bytes);
+ break;
+ default:
+ /* Event status is not set yet or the buffer is corrupted */
+ pr_err("diag: In %s, invalid status %d", __func__,
+ driver->event_status);
+ driver->event_mask->status = DIAG_CTRL_MASK_INVALID;
+ }
+
+ if (driver->event_mask->status == DIAG_CTRL_MASK_INVALID) {
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return;
+ }
memcpy(buf, driver->event_mask, header_size);
- memcpy(buf+header_size, driver->event_masks, num_bytes);
if (ch) {
while (retry_count < 3) {
wr_size = smd_write(ch, buf, header_size + num_bytes);
@@ -418,44 +473,68 @@
ptr += 4;
actual_last = *(uint32_t *)ptr;
ptr += 4;
- if ((updated_ssid_first >= first && updated_ssid_last <=
- actual_last) || (updated_ssid_first == ALL_SSID)) {
- /* send f3 mask update */
- driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
- driver->msg_mask->msg_mask_size = actual_last -
- first + 1;
- driver->msg_mask->data_len = 11 +
- 4 * (driver->msg_mask->msg_mask_size);
- driver->msg_mask->stream_id = 1; /* 2, if dual stream */
- driver->msg_mask->status = 3; /* status valid mask */
- driver->msg_mask->msg_mode = 0; /* Legcay mode */
- driver->msg_mask->ssid_first = first;
- driver->msg_mask->ssid_last = actual_last;
- memcpy(buf, driver->msg_mask, header_size);
+ if (!((updated_ssid_first >= first && updated_ssid_last <=
+ actual_last) || (updated_ssid_first == ALL_SSID))) {
+ ptr += MAX_SSID_PER_RANGE*4;
+ continue;
+ }
+ /* send f3 mask update */
+ driver->msg_mask->cmd_type = DIAG_CTRL_MSG_F3_MASK;
+ driver->msg_mask->status = driver->msg_status;
+ switch (driver->msg_status) {
+ case DIAG_CTRL_MASK_ALL_DISABLED:
+ driver->msg_mask->msg_mask_size = 0;
+ break;
+ case DIAG_CTRL_MASK_ALL_ENABLED:
+ driver->msg_mask->msg_mask_size = 1;
memcpy(buf+header_size, ptr,
4 * (driver->msg_mask->msg_mask_size));
- if (ch) {
- while (retry_count < 3) {
- size = smd_write(ch, buf, header_size +
- 4*(driver->msg_mask->msg_mask_size));
- if (size == -ENOMEM) {
- retry_count++;
- usleep_range(10000, 10100);
- } else
- break;
- }
- if (size != header_size +
- 4*(driver->msg_mask->msg_mask_size))
- pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
- proc, size, (header_size +
- 4*(driver->msg_mask->msg_mask_size)));
- else
- pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
- first, actual_last, proc);
- } else
- pr_err("diag: proc %d, ch invalid msg mask update\n",
- proc);
+ break;
+ case DIAG_CTRL_MASK_VALID:
+ driver->msg_mask->msg_mask_size = actual_last -
+ first + 1;
+ memcpy(buf+header_size, ptr,
+ 4 * (driver->msg_mask->msg_mask_size));
+ break;
+ default:
+ /* Msg status is not set or the buffer is corrupted */
+ pr_err("diag: In %s, invalid status %d", __func__,
+ driver->msg_status);
+ driver->msg_mask->status = DIAG_CTRL_MASK_INVALID;
}
+
+ if (driver->msg_mask->status == DIAG_CTRL_MASK_INVALID) {
+ mutex_unlock(&driver->diag_cntl_mutex);
+ return;
+ }
+ driver->msg_mask->data_len = 11 +
+ 4 * (driver->msg_mask->msg_mask_size);
+ driver->msg_mask->stream_id = 1; /* 2, if dual stream */
+ driver->msg_mask->msg_mode = 0; /* Legcay mode */
+ driver->msg_mask->ssid_first = first;
+ driver->msg_mask->ssid_last = actual_last;
+ memcpy(buf, driver->msg_mask, header_size);
+ if (ch) {
+ while (retry_count < 3) {
+ size = smd_write(ch, buf, header_size +
+ 4*(driver->msg_mask->msg_mask_size));
+ if (size == -ENOMEM) {
+ retry_count++;
+ usleep_range(10000, 10100);
+ } else
+ break;
+ }
+ if (size != header_size +
+ 4*(driver->msg_mask->msg_mask_size))
+ pr_err("diag: proc %d, msg mask update fail %d, tried %d\n",
+ proc, size, (header_size +
+ 4*(driver->msg_mask->msg_mask_size)));
+ else
+ pr_debug("diag: sending mask update for ssid first %d, last %d on PROC %d\n",
+ first, actual_last, proc);
+ } else
+ pr_err("diag: proc %d, ch invalid msg mask update\n",
+ proc);
ptr += MAX_SSID_PER_RANGE*4;
}
mutex_unlock(&driver->diag_cntl_mutex);
@@ -706,8 +785,8 @@
#endif
} else if (*buf == 0x82) { /* event mask change */
buf += 4;
- diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
- diag_update_event_mask(buf, 1, (*(uint16_t *)buf)/8+1);
+ diag_event_num_bytes = (*(uint16_t *)buf)/8+1;
+ diag_update_event_mask(buf, diag_event_num_bytes);
diag_update_userspace_clients(EVENT_MASKS_TYPE);
#if defined(CONFIG_DIAG_OVER_USB)
if (chk_apps_only()) {
@@ -729,7 +808,6 @@
}
#endif
} else if (*buf == 0x60) {
- diag_event_config = *(buf+1);
diag_toggle_event_mask(*(buf+1));
diag_update_userspace_clients(EVENT_MASKS_TYPE);
#if defined(CONFIG_DIAG_OVER_USB)
@@ -764,6 +842,10 @@
void diag_masks_init(void)
{
+ driver->event_status = DIAG_CTRL_MASK_INVALID;
+ driver->msg_status = DIAG_CTRL_MASK_INVALID;
+ driver->log_status = DIAG_CTRL_MASK_INVALID;
+
if (driver->event_mask == NULL) {
driver->event_mask = kzalloc(sizeof(
struct diag_ctrl_event_mask), GFP_KERNEL);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index 7ef1d80..45314d9 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -362,9 +362,12 @@
struct work_struct diag_drain_work;
struct workqueue_struct *diag_cntl_wq;
uint8_t *msg_masks;
+ uint8_t msg_status;
uint8_t *log_masks;
+ uint8_t log_status;
int log_masks_length;
uint8_t *event_masks;
+ uint8_t event_status;
uint8_t log_on_demand_support;
struct diag_master_table *table;
uint8_t *pkt_buf;
@@ -412,5 +415,6 @@
extern uint16_t wrap_count;
void diag_get_timestamp(char *time_str);
+int diag_find_polling_reg(int i);
#endif
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 24d7fac..6cc18da 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -327,17 +327,19 @@
subsys_id = driver->table[i].subsys_id;
cmd_code_lo = driver->table[i].cmd_code_lo;
cmd_code_hi = driver->table[i].cmd_code_hi;
- if (driver->table[i].cmd_code == 0x0C)
- return 1;
- else if (driver->table[i].cmd_code == 0xFF) {
- if (subsys_id == 0x04 && cmd_code_hi == 0x0E &&
- cmd_code_lo == 0x0E)
+
+ if (driver->table[i].cmd_code == 0xFF) {
+ if (subsys_id == 0xFF && cmd_code_hi >= 0x0C &&
+ cmd_code_lo <= 0x0C)
return 1;
- else if (subsys_id == 0x08 && cmd_code_hi == 0x02 &&
- cmd_code_lo == 0x02)
+ if (subsys_id == 0x04 && cmd_code_hi >= 0x0E &&
+ cmd_code_lo <= 0x0E)
return 1;
- else if (subsys_id == 0x32 && cmd_code_hi == 0x03 &&
- cmd_code_lo == 0x03)
+ else if (subsys_id == 0x08 && cmd_code_hi >= 0x02 &&
+ cmd_code_lo <= 0x02)
+ return 1;
+ else if (subsys_id == 0x32 && cmd_code_hi >= 0x03 &&
+ cmd_code_lo <= 0x03)
return 1;
}
return 0;
@@ -356,7 +358,8 @@
}
/* re-scan the registration table */
for (i = 0; i < diag_max_reg; i++) {
- if (diag_find_polling_reg(i) == 1) {
+ if (driver->table[i].process_id != 0 &&
+ diag_find_polling_reg(i) == 1) {
driver->polling_reg_flag = 1;
break;
}
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 418c488..1f60c65 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -346,6 +346,7 @@
dbs_tuners_ins.sampling_rate = new_rate
= max(new_rate, min_sampling_rate);
+ get_online_cpus();
for_each_online_cpu(cpu) {
struct cpufreq_policy *policy;
struct cpu_dbs_info_s *dbs_info;
@@ -380,6 +381,7 @@
}
mutex_unlock(&dbs_info->timer_mutex);
}
+ put_online_cpus();
}
static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c
index 8b0fcf4..9e0be59 100644
--- a/drivers/hwmon/qpnp-adc-common.c
+++ b/drivers/hwmon/qpnp-adc-common.c
@@ -131,57 +131,111 @@
};
static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
- {-200, 1672},
- {-180, 1656},
- {-160, 1639},
- {-140, 1620},
- {-120, 1599},
- {-100, 1577},
- {-80, 1553},
- {-60, 1527},
- {-40, 1550},
- {-20, 1471},
- {0, 1440},
- {20, 1408},
- {40, 1374},
- {60, 1339},
- {80, 1303},
- {100, 1266},
- {120, 1228},
- {140, 1190},
- {160, 1150},
- {180, 1111},
- {200, 1071},
- {220, 1032},
- {240, 992},
- {260, 953},
- {280, 915},
- {300, 877},
- {320, 841},
- {340, 805},
- {360, 770},
- {380, 736},
- {400, 704},
- {420, 673},
- {440, 643},
- {460, 614},
- {480, 587},
- {500, 561},
- {520, 536},
- {540, 513},
- {560, 491},
- {580, 470},
- {600, 450},
- {620, 431},
- {640, 414},
- {660, 397},
- {680, 382},
- {700, 367},
- {720, 353},
- {740, 340},
- {760, 328},
- {780, 317},
- {800, 306},
+ {-200, 1540},
+ {-180, 1517},
+ {-160, 1492},
+ {-140, 1467},
+ {-120, 1440},
+ {-100, 1412},
+ {-80, 1383},
+ {-60, 1353},
+ {-40, 1323},
+ {-20, 1292},
+ {0, 1260},
+ {20, 1228},
+ {40, 1196},
+ {60, 1163},
+ {80, 1131},
+ {100, 1098},
+ {120, 1066},
+ {140, 1034},
+ {160, 1002},
+ {180, 971},
+ {200, 941},
+ {220, 911},
+ {240, 882},
+ {260, 854},
+ {280, 826},
+ {300, 800},
+ {320, 774},
+ {340, 749},
+ {360, 726},
+ {380, 703},
+ {400, 681},
+ {420, 660},
+ {440, 640},
+ {460, 621},
+ {480, 602},
+ {500, 585},
+ {520, 568},
+ {540, 552},
+ {560, 537},
+ {580, 523},
+ {600, 510},
+ {620, 497},
+ {640, 485},
+ {660, 473},
+ {680, 462},
+ {700, 452},
+ {720, 442},
+ {740, 433},
+ {760, 424},
+ {780, 416},
+ {800, 408},
+};
+
+static const struct qpnp_vadc_map_pt adcmap_qrd_skuaa_btm_threshold[] = {
+ {-200, 1476},
+ {-180, 1450},
+ {-160, 1422},
+ {-140, 1394},
+ {-120, 1365},
+ {-100, 1336},
+ {-80, 1306},
+ {-60, 1276},
+ {-40, 1246},
+ {-20, 1216},
+ {0, 1185},
+ {20, 1155},
+ {40, 1126},
+ {60, 1096},
+ {80, 1068},
+ {100, 1040},
+ {120, 1012},
+ {140, 986},
+ {160, 960},
+ {180, 935},
+ {200, 911},
+ {220, 888},
+ {240, 866},
+ {260, 844},
+ {280, 824},
+ {300, 805},
+ {320, 786},
+ {340, 769},
+ {360, 752},
+ {380, 737},
+ {400, 722},
+ {420, 707},
+ {440, 694},
+ {460, 681},
+ {480, 669},
+ {500, 658},
+ {520, 648},
+ {540, 637},
+ {560, 628},
+ {580, 619},
+ {600, 611},
+ {620, 603},
+ {640, 595},
+ {660, 588},
+ {680, 582},
+ {700, 575},
+ {720, 569},
+ {740, 564},
+ {760, 559},
+ {780, 554},
+ {800, 549},
};
/* Voltage to temperature */
@@ -539,6 +593,25 @@
}
EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
+int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(struct qpnp_vadc_chip *chip,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_properties,
+ const struct qpnp_vadc_chan_properties *chan_properties,
+ struct qpnp_vadc_result *adc_chan_result)
+{
+ int64_t bat_voltage = 0;
+
+ bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
+ adc_properties, chan_properties);
+
+ return qpnp_adc_map_temp_voltage(
+ adcmap_qrd_skuaa_btm_threshold,
+ ARRAY_SIZE(adcmap_qrd_skuaa_btm_threshold),
+ bat_voltage,
+ &adc_chan_result->physical);
+}
+EXPORT_SYMBOL(qpnp_adc_scale_qrd_skuaa_batt_therm);
+
int32_t qpnp_adc_scale_therm_pu1(struct qpnp_vadc_chip *chip,
int32_t adc_code,
const struct qpnp_adc_properties *adc_properties,
diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c
index c4a2567..548764f 100644
--- a/drivers/hwmon/qpnp-adc-voltage.c
+++ b/drivers/hwmon/qpnp-adc-voltage.c
@@ -126,6 +126,7 @@
[SCALE_THERM_100K_PULLUP] = {qpnp_adc_scale_therm_pu2},
[SCALE_THERM_150K_PULLUP] = {qpnp_adc_scale_therm_pu1},
[SCALE_QRD_BATT_THERM] = {qpnp_adc_scale_qrd_batt_therm},
+ [SCALE_QRD_SKUAA_BATT_THERM] = {qpnp_adc_scale_qrd_skuaa_batt_therm},
};
static int32_t qpnp_vadc_read_reg(struct qpnp_vadc_chip *vadc, int16_t reg,
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index ded2b6e..e0d8a47 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -320,15 +320,19 @@
if (sensor->use_poll)
schedule_delayed_work(&sensor->input_work,
msecs_to_jiffies(sensor->poll_interval));
- else
+ else {
i2c_smbus_write_byte_data(sensor->client,
MPU3050_INT_CFG,
MPU3050_ACTIVE_LOW |
MPU3050_OPEN_DRAIN |
MPU3050_RAW_RDY_EN);
+ enable_irq(sensor->client->irq);
+ }
} else {
if (sensor->use_poll)
cancel_delayed_work_sync(&sensor->input_work);
+ else
+ disable_irq(sensor->client->irq);
gpio_set_value(sensor->enable_gpio, 0);
pm_runtime_put(sensor->dev);
}
@@ -448,6 +452,7 @@
mpu3050_config_regulator(client, 1);
udelay(10);
gpio_set_value(sensor->enable_gpio, 1);
+ msleep(60);
}
value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM);
@@ -709,7 +714,6 @@
}
mpu3050_set_power_mode(client, 1);
- msleep(10);
ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG);
if (ret < 0) {
@@ -864,6 +868,10 @@
static int mpu3050_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
+
+ if (!sensor->use_poll)
+ disable_irq(client->irq);
mpu3050_set_power_mode(client, 0);
@@ -879,9 +887,12 @@
static int mpu3050_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct mpu3050_sensor *sensor = i2c_get_clientdata(client);
mpu3050_set_power_mode(client, 1);
- msleep(100); /* wait for gyro chip resume */
+
+ if (!sensor->use_poll)
+ enable_irq(client->irq);
return 0;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
index 3256c5c..e17c94e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
@@ -21,55 +21,55 @@
.seq_type = SENSOR_VREG,
.seq_val = CAM_VIO,
.config_val = 0,
- .delay = 5,
+ .delay = 1,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VANA,
.config_val = 0,
- .delay = 5,
+ .delay = 1,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VDIG,
.config_val = 0,
- .delay = 5,
+ .delay = 1,
},
{
.seq_type = SENSOR_VREG,
.seq_val = CAM_VAF,
.config_val = 0,
- .delay = 15,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_LOW,
- .delay = 15,
+ .delay = 1,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_LOW,
- .delay = 40,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_HIGH,
- .delay = 40,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_HIGH,
- .delay = 40,
+ .delay = 10,
},
{
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 24000000,
- .delay = 5,
+ .delay = 10,
},
{
.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
index 56af02b..99bf03a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
@@ -46,7 +46,7 @@
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_RESET,
.config_val = GPIO_OUT_HIGH,
- .delay = 30,
+ .delay = 5,
},
{
.seq_type = SENSOR_GPIO,
@@ -58,13 +58,13 @@
.seq_type = SENSOR_GPIO,
.seq_val = SENSOR_GPIO_STANDBY,
.config_val = GPIO_OUT_HIGH,
- .delay = 30,
+ .delay = 10,
},
{
.seq_type = SENSOR_CLK,
.seq_val = SENSOR_CAM_MCLK,
.config_val = 24000000,
- .delay = 5,
+ .delay = 10,
},
{
.seq_type = SENSOR_I2C_MUX,
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
index 249f54d..494242d 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h
@@ -201,7 +201,7 @@
HAL_VIDEO_CODEC_VP6 = 0x00000400,
HAL_VIDEO_CODEC_VP7 = 0x00000800,
HAL_VIDEO_CODEC_VP8 = 0x00001000,
- HAL_VIDEO_CODEC_HEVC = 0x00010000,
+ HAL_VIDEO_CODEC_HEVC = 0x00002000,
HAL_UNUSED_CODEC = 0x10000000,
};
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
index 3f63357..61c6e15 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h
@@ -79,7 +79,7 @@
#define HFI_VIDEO_CODEC_VC1 0x00000100
#define HFI_VIDEO_CODEC_SPARK 0x00000200
#define HFI_VIDEO_CODEC_VP8 0x00001000
-#define HFI_VIDEO_CODEC_HEVC 0x00010000
+#define HFI_VIDEO_CODEC_HEVC 0x00002000
#define HFI_H264_PROFILE_BASELINE 0x00000001
#define HFI_H264_PROFILE_MAIN 0x00000002
diff --git a/drivers/mfd/wcd9xxx-core.c b/drivers/mfd/wcd9xxx-core.c
index 1eebe61..9c35a55 100644
--- a/drivers/mfd/wcd9xxx-core.c
+++ b/drivers/mfd/wcd9xxx-core.c
@@ -1195,15 +1195,54 @@
return 0;
}
+static int wcd9xxx_process_supplies(struct device *dev,
+ struct wcd9xxx_pdata *pdata, const char *supply_list,
+ int supply_cnt, bool is_ondemand, int index)
+{
+ int idx, ret = 0;
+ const char *name;
+
+ if (supply_cnt == 0) {
+ dev_dbg(dev, "%s: no supplies defined for %s\n", __func__,
+ supply_list);
+ return 0;
+ }
+
+ for (idx = 0; idx < supply_cnt; idx++) {
+ ret = of_property_read_string_index(dev->of_node,
+ supply_list, idx,
+ &name);
+ if (ret) {
+ dev_err(dev, "%s: of read string %s idx %d error %d\n",
+ __func__, supply_list, idx, ret);
+ goto err;
+ }
+
+ dev_dbg(dev, "%s: Found cdc supply %s as part of %s\n",
+ __func__, name, supply_list);
+ ret = wcd9xxx_dt_parse_vreg_info(dev,
+ &pdata->regulator[index + idx],
+ name, is_ondemand);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ return ret;
+
+}
+
static struct wcd9xxx_pdata *wcd9xxx_populate_dt_pdata(struct device *dev)
{
struct wcd9xxx_pdata *pdata;
- int ret, static_cnt, ond_cnt, idx, i;
- const char *name = NULL;
+ int ret, static_cnt, ond_cnt, cp_supplies_cnt;
u32 mclk_rate = 0;
u32 dmic_sample_rate = 0;
const char *static_prop_name = "qcom,cdc-static-supplies";
const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
+ const char *cp_supplies_name = "qcom,cdc-cp-supplies";
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
@@ -1223,44 +1262,34 @@
if (IS_ERR_VALUE(ond_cnt))
ond_cnt = 0;
- BUG_ON(static_cnt <= 0 || ond_cnt < 0);
- if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
+ /* cp-supplies list is an optional property */
+ cp_supplies_cnt = of_property_count_strings(dev->of_node,
+ cp_supplies_name);
+ if (IS_ERR_VALUE(cp_supplies_cnt))
+ cp_supplies_cnt = 0;
+
+ BUG_ON(static_cnt <= 0 || ond_cnt < 0 || cp_supplies_cnt < 0);
+ if ((static_cnt + ond_cnt + cp_supplies_cnt)
+ > ARRAY_SIZE(pdata->regulator)) {
dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
__func__, static_cnt, ARRAY_SIZE(pdata->regulator));
goto err;
}
- for (idx = 0; idx < static_cnt; idx++) {
- ret = of_property_read_string_index(dev->of_node,
- static_prop_name, idx,
- &name);
- if (ret) {
- dev_err(dev, "%s: of read string %s idx %d error %d\n",
- __func__, static_prop_name, idx, ret);
- goto err;
- }
+ ret = wcd9xxx_process_supplies(dev, pdata, static_prop_name,
+ static_cnt, false, 0);
+ if (ret)
+ goto err;
- dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
- name);
- ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
- name, false);
- if (ret)
- goto err;
- }
+ ret = wcd9xxx_process_supplies(dev, pdata, ond_prop_name,
+ ond_cnt, true, static_cnt);
+ if (ret)
+ goto err;
- for (i = 0; i < ond_cnt; i++, idx++) {
- ret = of_property_read_string_index(dev->of_node, ond_prop_name,
- i, &name);
- if (ret)
- goto err;
-
- dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
- name);
- ret = wcd9xxx_dt_parse_vreg_info(dev, &pdata->regulator[idx],
- name, true);
- if (ret)
- goto err;
- }
+ ret = wcd9xxx_process_supplies(dev, pdata, cp_supplies_name,
+ cp_supplies_cnt, false, static_cnt + ond_cnt);
+ if (ret)
+ goto err;
ret = wcd9xxx_dt_parse_micbias_info(dev, &pdata->micbias);
if (ret)
diff --git a/drivers/thermal/msm8974-tsens.c b/drivers/thermal/msm8974-tsens.c
index 69031dc..fcc5a8d 100644
--- a/drivers/thermal/msm8974-tsens.c
+++ b/drivers/thermal/msm8974-tsens.c
@@ -664,6 +664,15 @@
lower_thr = true;
}
if (upper_thr || lower_thr) {
+ unsigned long temp;
+ enum thermal_trip_type trip =
+ THERMAL_TRIP_CONFIGURABLE_LOW;
+
+ if (upper_thr)
+ trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ tsens_tz_get_temp(tm->sensor[i].tz_dev, &temp);
+ thermal_sensor_trip(tm->sensor[i].tz_dev, trip, temp);
+
/* Notify user space */
queue_work(tm->tsens_wq, &tm->sensor[i].work);
rc = tsens_get_sw_id_mapping(
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index 974cadc..00df613 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -14,9 +14,11 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/msm_tsens.h>
#include <linux/workqueue.h>
+#include <linux/completion.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/msm_tsens.h>
@@ -29,6 +31,7 @@
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/android_alarm.h>
+#include <linux/thermal.h>
#include <mach/cpufreq.h>
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
@@ -45,7 +48,10 @@
static uint32_t wakeup_ms;
static struct alarm thermal_rtc;
static struct kobject *tt_kobj;
+static struct kobject *cc_kobj;
static struct work_struct timer_work;
+static struct task_struct *hotplug_task;
+static struct completion hotplug_notify_complete;
static int enabled;
static int rails_cnt;
@@ -67,6 +73,14 @@
static DEFINE_MUTEX(vdd_rstr_mutex);
static DEFINE_MUTEX(psm_mutex);
+struct cpu_info {
+ uint32_t cpu;
+ bool offline;
+ bool user_offline;
+ const char *sensor_type;
+ struct sensor_threshold thresh[2];
+};
+
struct rail {
const char *name;
uint32_t freq_req;
@@ -91,6 +105,7 @@
static struct psm_rail *psm_rails;
static struct rail *rails;
+static struct cpu_info cpus[NR_CPUS];
struct vdd_rstr_enable {
struct kobj_attribute ko_attr;
@@ -658,11 +673,67 @@
}
mutex_unlock(&core_control_mutex);
}
+/* Call with core_control_mutex locked */
+static int __ref update_offline_cores(int val)
+{
+ int cpu = 0;
+ int ret = 0;
+
+ if (!core_control_enabled)
+ return 0;
+
+ cpus_offlined = msm_thermal_info.core_control_mask & val;
+
+ for_each_possible_cpu(cpu) {
+ if (!(cpus_offlined & BIT(cpu)))
+ continue;
+ if (!cpu_online(cpu))
+ continue;
+ ret = cpu_down(cpu);
+ if (ret)
+ pr_err("%s: Unable to offline cpu%d\n",
+ KBUILD_MODNAME, cpu);
+ }
+ return ret;
+}
+
+static __ref int do_hotplug(void *data)
+{
+ int ret = 0;
+ int cpu = 0;
+ uint32_t mask = 0;
+
+ if (!core_control_enabled)
+ return -EINVAL;
+
+ while (!kthread_should_stop()) {
+ wait_for_completion(&hotplug_notify_complete);
+ INIT_COMPLETION(hotplug_notify_complete);
+ mask = 0;
+
+ mutex_lock(&core_control_mutex);
+ for_each_possible_cpu(cpu) {
+ if (cpus[cpu].offline || cpus[cpu].user_offline)
+ mask |= BIT(cpu);
+ }
+ if (mask != cpus_offlined)
+ update_offline_cores(mask);
+ mutex_unlock(&core_control_mutex);
+ sysfs_notify(cc_kobj, NULL, "cpus_offlined");
+ }
+
+ return ret;
+}
#else
static void do_core_control(long temp)
{
return;
}
+
+static __ref int do_hotplug(void *data)
+{
+ return 0;
+}
#endif
static int do_vdd_restriction(void)
@@ -848,7 +919,7 @@
if (core_control_enabled &&
(msm_thermal_info.core_control_mask & BIT(cpu)) &&
(cpus_offlined & BIT(cpu))) {
- pr_info(
+ pr_debug(
"%s: Preventing cpu%d from coming online.\n",
KBUILD_MODNAME, cpu);
return NOTIFY_BAD;
@@ -896,6 +967,112 @@
ts.tv_sec, ts.tv_usec);
}
+static int hotplug_notify(enum thermal_trip_type type, int temp, void *data)
+{
+ struct cpu_info *cpu_node = (struct cpu_info *)data;
+
+ pr_info("%s: %s reach temp threshold: %d\n", KBUILD_MODNAME,
+ cpu_node->sensor_type, temp);
+
+ if (!(msm_thermal_info.core_control_mask & BIT(cpu_node->cpu)))
+ return 0;
+ switch (type) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ if (!(cpu_node->offline))
+ cpu_node->offline = 1;
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ if (cpu_node->offline)
+ cpu_node->offline = 0;
+ break;
+ default:
+ break;
+ }
+ if (hotplug_task)
+ complete(&hotplug_notify_complete);
+ else
+ pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
+ return 0;
+}
+/* Adjust cpus offlined bit based on temperature reading. */
+static int hotplug_init_cpu_offlined(void)
+{
+ struct tsens_device tsens_dev;
+ long temp = 0;
+ int cpu = 0;
+
+ mutex_lock(&core_control_mutex);
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
+ continue;
+ tsens_dev.sensor_num = sensor_get_id(\
+ (char *)cpus[cpu].sensor_type);
+ if (tsens_get_temp(&tsens_dev, &temp)) {
+ pr_err("%s: Unable to read TSENS sensor %d\n",
+ KBUILD_MODNAME, tsens_dev.sensor_num);
+ return -EINVAL;
+ }
+
+ if (temp >= msm_thermal_info.hotplug_temp_degC)
+ cpus[cpu].offline = 1;
+ else if (temp <= (msm_thermal_info.hotplug_temp_degC -
+ msm_thermal_info.hotplug_temp_hysteresis_degC))
+ cpus[cpu].offline = 0;
+ }
+ mutex_unlock(&core_control_mutex);
+
+ if (hotplug_task)
+ complete(&hotplug_notify_complete);
+ else {
+ pr_err("%s: Hotplug task is not initialized\n",
+ KBUILD_MODNAME);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void hotplug_init(void)
+{
+ int cpu = 0;
+
+ if (hotplug_task)
+ return;
+
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
+ continue;
+ cpus[cpu].cpu = (uint32_t)cpu;
+ cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
+ cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ cpus[cpu].thresh[0].notify = hotplug_notify;
+ cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
+ sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
+ &cpus[cpu].thresh[0]);
+
+ cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
+ msm_thermal_info.hotplug_temp_hysteresis_degC;
+ cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+ cpus[cpu].thresh[1].notify = hotplug_notify;
+ cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
+ sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
+ &cpus[cpu].thresh[1]);
+
+ }
+ init_completion(&hotplug_notify_complete);
+ hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
+ if (IS_ERR(hotplug_task)) {
+ pr_err("%s: Failed to create do_hotplug thread\n",
+ KBUILD_MODNAME);
+ return;
+ }
+ /*
+ * Adjust cpus offlined bit when hotplug intitializes so that the new
+ * cpus offlined state is based on hotplug threshold range
+ */
+ if (hotplug_init_cpu_offlined())
+ kthread_stop(hotplug_task);
+}
+
/*
* We will reset the cpu frequencies limits here. The core online/offline
* status will be carried over to the process stopping the msm_thermal, as
@@ -922,9 +1099,10 @@
int ret = 0;
ret = param_set_bool(val, kp);
- if (!enabled)
+ if (!enabled) {
disable_msm_thermal();
- else
+ hotplug_init();
+ } else
pr_info("%s: no action for enabled = %d\n",
KBUILD_MODNAME, enabled);
@@ -941,37 +1119,6 @@
module_param_cb(enabled, &module_ops, &enabled, 0644);
MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
-
-#ifdef CONFIG_SMP
-/* Call with core_control_mutex locked */
-static int __ref update_offline_cores(int val)
-{
- int cpu = 0;
- int ret = 0;
-
- cpus_offlined = msm_thermal_info.core_control_mask & val;
- if (!core_control_enabled)
- return 0;
-
- for_each_possible_cpu(cpu) {
- if (!(cpus_offlined & BIT(cpu)))
- continue;
- if (!cpu_online(cpu))
- continue;
- ret = cpu_down(cpu);
- if (ret)
- pr_err("%s: Unable to offline cpu%d\n",
- KBUILD_MODNAME, cpu);
- }
- return ret;
-}
-#else
-static int update_offline_cores(int val)
-{
- return 0;
-}
-#endif
-
static ssize_t show_cc_enabled(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@@ -984,7 +1131,6 @@
int ret = 0;
int val = 0;
- mutex_lock(&core_control_mutex);
ret = kstrtoint(buf, 10, &val);
if (ret) {
pr_err("%s: Invalid input %s\n", KBUILD_MODNAME, buf);
@@ -998,14 +1144,17 @@
if (core_control_enabled) {
pr_info("%s: Core control enabled\n", KBUILD_MODNAME);
register_cpu_notifier(&msm_thermal_cpu_notifier);
- update_offline_cores(cpus_offlined);
+ if (hotplug_task)
+ complete(&hotplug_notify_complete);
+ else
+ pr_err("%s: Hotplug task is not initialized\n",
+ KBUILD_MODNAME);
} else {
pr_info("%s: Core control disabled\n", KBUILD_MODNAME);
unregister_cpu_notifier(&msm_thermal_cpu_notifier);
}
done_store_cc:
- mutex_unlock(&core_control_mutex);
return count;
}
@@ -1020,6 +1169,7 @@
{
int ret = 0;
uint32_t val = 0;
+ int cpu;
mutex_lock(&core_control_mutex);
ret = kstrtouint(buf, 10, &val);
@@ -1034,10 +1184,16 @@
goto done_cc;
}
- if (cpus_offlined == val)
- goto done_cc;
+ for_each_possible_cpu(cpu) {
+ if (!(msm_thermal_info.core_control_mask & BIT(cpu)))
+ continue;
+ cpus[cpu].user_offline = !!(val & BIT(cpu));
+ }
- update_offline_cores(val);
+ if (hotplug_task)
+ complete(&hotplug_notify_complete);
+ else
+ pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
done_cc:
mutex_unlock(&core_control_mutex);
return count;
@@ -1108,7 +1264,6 @@
static __init int msm_thermal_add_cc_nodes(void)
{
struct kobject *module_kobj = NULL;
- struct kobject *cc_kobj = NULL;
int ret = 0;
module_kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
@@ -1190,8 +1345,7 @@
return -EINVAL;
enabled = 1;
- if (num_possible_cpus() > 1)
- core_control_enabled = 1;
+
INIT_DELAYED_WORK(&check_temp_work, check_temp);
schedule_delayed_work(&check_temp_work, 0);
@@ -1602,12 +1756,76 @@
return ret;
}
+static int probe_cc(struct device_node *node, struct msm_thermal_data *data,
+ struct platform_device *pdev)
+{
+ char *key = NULL;
+ int cpu_cnt = 0;
+ int ret = 0;
+ int cpu = 0;
+
+ key = "qcom,core-limit-temp";
+ ret = of_property_read_u32(node, key, &data->core_limit_temp_degC);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,core-temp-hysteresis";
+ ret = of_property_read_u32(node, key, &data->core_temp_hysteresis_degC);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,core-control-mask";
+ ret = of_property_read_u32(node, key, &data->core_control_mask);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,hotplug-temp";
+ ret = of_property_read_u32(node, key, &data->hotplug_temp_degC);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,hotplug-temp-hysteresis";
+ ret = of_property_read_u32(node, key,
+ &data->hotplug_temp_hysteresis_degC);
+ if (ret)
+ goto read_node_fail;
+
+ key = "qcom,cpu-sensors";
+ cpu_cnt = of_property_count_strings(node, key);
+ if (cpu_cnt != num_possible_cpus()) {
+ pr_err("%s: Wrong number of cpu\n", KBUILD_MODNAME);
+ goto read_node_fail;
+ }
+
+ for_each_possible_cpu(cpu) {
+ cpus[cpu].cpu = cpu;
+ cpus[cpu].offline = 0;
+ cpus[cpu].user_offline = 0;
+ ret = of_property_read_string_index(node, key, cpu,
+ &cpus[cpu].sensor_type);
+ if (ret)
+ goto read_node_fail;
+ }
+
+ if (num_possible_cpus() > 1)
+ core_control_enabled = 1;
+
+read_node_fail:
+ if (ret) {
+ dev_info(&pdev->dev,
+ "%s:Failed reading node=%s, key=%s. KTM continues\n",
+ KBUILD_MODNAME, node->full_name, key);
+ core_control_enabled = 0;
+ }
+
+ return ret;
+}
+
static int __devinit msm_thermal_dev_probe(struct platform_device *pdev)
{
int ret = 0;
char *key = NULL;
struct device_node *node = pdev->dev.of_node;
-
struct msm_thermal_data data;
memset(&data, 0, sizeof(struct msm_thermal_data));
@@ -1640,15 +1858,7 @@
key = "qcom,freq-control-mask";
ret = of_property_read_u32(node, key, &data.freq_control_mask);
- key = "qcom,core-limit-temp";
- ret = of_property_read_u32(node, key, &data.core_limit_temp_degC);
-
- key = "qcom,core-temp-hysteresis";
- ret = of_property_read_u32(node, key, &data.core_temp_hysteresis_degC);
-
- key = "qcom,core-control-mask";
- ret = of_property_read_u32(node, key, &data.core_control_mask);
-
+ ret = probe_cc(node, &data, pdev);
/*
* Probe optional properties below. Call probe_psm before
* probe_vdd_rstr because rpm_regulator_get has to be called
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
index fd1a2fc..1cf901e 100644
--- a/drivers/thermal/thermal_sys.c
+++ b/drivers/thermal/thermal_sys.c
@@ -4,6 +4,7 @@
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -60,6 +61,273 @@
static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock);
+static LIST_HEAD(sensor_info_list);
+static DEFINE_MUTEX(sensor_list_lock);
+
+static struct sensor_info *get_sensor(uint32_t sensor_id)
+{
+ struct sensor_info *pos, *var;
+
+ list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
+ if (pos->sensor_id == sensor_id)
+ break;
+ }
+
+ return pos;
+}
+
+int sensor_get_id(char *name)
+{
+ struct sensor_info *pos, *var;
+
+ list_for_each_entry_safe(pos, var, &sensor_info_list, sensor_list) {
+ if (!strcmp(pos->tz->type, name))
+ return pos->sensor_id;
+ }
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL(sensor_get_id);
+
+static void __update_sensor_thresholds(struct sensor_info *sensor)
+{
+ int min = INT_MIN;
+ int max = INT_MAX;
+ struct sensor_threshold *pos, *var;
+ enum thermal_trip_type type;
+ int i;
+ unsigned long curr_temp;
+
+ for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
+ (sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
+ i++) {
+ sensor->tz->ops->get_trip_type(sensor->tz, i, &type);
+ if (type == THERMAL_TRIP_CONFIGURABLE_HI)
+ sensor->max_idx = i;
+ if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
+ sensor->min_idx = i;
+ }
+
+ get_cpu();
+ sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
+ list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+ if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
+ (pos->temp < (int)curr_temp))
+ if (pos->temp > min)
+ min = pos->temp;
+ if ((pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
+ (pos->temp > (int)curr_temp))
+ if (pos->temp < max)
+ max = pos->temp;
+ }
+ put_cpu();
+
+ if (sensor->tz->ops->set_trip_temp) {
+ if (max != INT_MAX) {
+ sensor->tz->ops->set_trip_temp(sensor->tz,
+ sensor->max_idx, max);
+ sensor->threshold_max = max;
+ }
+ if (min != INT_MIN) {
+ sensor->tz->ops->set_trip_temp(sensor->tz,
+ sensor->min_idx, min);
+ sensor->threshold_min = min;
+ }
+ }
+
+ pr_debug("sensor %d, min: %d, max %d\n", sensor->sensor_id, min, max);
+}
+
+static void sensor_update_work(struct work_struct *work)
+{
+ struct sensor_info *sensor = container_of(work, struct sensor_info,
+ work);
+ mutex_lock(&sensor->lock);
+ __update_sensor_thresholds(sensor);
+ mutex_unlock(&sensor->lock);
+}
+
+/* May be called in an interrupt context.
+ * Do NOT call sensor_set_trip from this function
+ */
+int thermal_sensor_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type trip, unsigned long temp)
+{
+ struct sensor_threshold *pos, *var;
+ int ret = -ENODEV;
+
+ if (trip != THERMAL_TRIP_CONFIGURABLE_HI &&
+ trip != THERMAL_TRIP_CONFIGURABLE_LOW)
+ return 0;
+
+ if (list_empty(&tz->sensor.threshold_list))
+ return 0;
+
+ list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) {
+ if (pos->trip != trip)
+ continue;
+ if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
+ (pos->temp <= tz->sensor.threshold_min) &&
+ (pos->temp >= (int) temp)) ||
+ ((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
+ (pos->temp >= tz->sensor.threshold_max) &&
+ (pos->temp <= (int)temp))) {
+ pos->notify(trip, temp, pos->data);
+ }
+ }
+
+ schedule_work(&tz->sensor.work);
+
+ return ret;
+}
+EXPORT_SYMBOL(thermal_sensor_trip);
+
+int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
+{
+ struct sensor_threshold *pos, *var;
+ struct sensor_info *sensor = get_sensor(sensor_id);
+
+ if (!sensor)
+ return -ENODEV;
+
+ if (!threshold || !threshold->notify)
+ return -EFAULT;
+
+ mutex_lock(&sensor->lock);
+ list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+ if (pos == threshold)
+ break;
+ }
+
+ if (pos != threshold) {
+ INIT_LIST_HEAD(&threshold->list);
+ list_add(&threshold->list, &sensor->threshold_list);
+ }
+
+ __update_sensor_thresholds(sensor);
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+
+}
+EXPORT_SYMBOL(sensor_set_trip);
+
+int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
+{
+ struct sensor_threshold *pos, *var;
+ struct sensor_info *sensor = get_sensor(sensor_id);
+
+ if (!sensor)
+ return -ENODEV;
+
+ mutex_lock(&sensor->lock);
+ list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
+ if (pos == threshold) {
+ list_del(&pos->list);
+ break;
+ }
+ }
+
+ __update_sensor_thresholds(sensor);
+ mutex_unlock(&sensor->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(sensor_cancel_trip);
+
+static int sensor_get_trip_temp(struct thermal_zone_device *tz,
+ int type, unsigned long *temp)
+{
+ struct sensor_info *sensor = get_sensor(tz->id);
+
+ if (!sensor)
+ return -EFAULT;
+
+ switch (type) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ *temp = tz->sensor.threshold_max;
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ *temp = tz->sensor.threshold_min;
+ break;
+ default:
+ tz->ops->get_trip_temp(tz, type, temp);
+ break;
+ }
+
+ return 0;
+}
+
+static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data)
+{
+ struct thermal_zone_device *tz = (struct thermal_zone_device *)data;
+
+ pr_debug("sensor %d tripped: type %d temp %d\n",
+ tz->sensor.sensor_id, type, temp);
+
+ return 0;
+}
+
+int sensor_set_trip_temp(struct thermal_zone_device *tz,
+ int trip, long temp)
+{
+ int ret = 0;
+ enum thermal_trip_type type;
+
+ if (!tz->ops->get_trip_type)
+ return -EPERM;
+
+ tz->ops->get_trip_type(tz, trip, &type);
+ switch (type) {
+ case THERMAL_TRIP_CONFIGURABLE_HI:
+ tz->tz_threshold[0].temp = temp;
+ tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
+ tz->tz_threshold[0].notify = tz_notify_trip;
+ tz->tz_threshold[0].data = tz;
+ ret = sensor_set_trip(tz->sensor.sensor_id,
+ &tz->tz_threshold[0]);
+ break;
+ case THERMAL_TRIP_CONFIGURABLE_LOW:
+ tz->tz_threshold[1].temp = temp;
+ tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
+ tz->tz_threshold[1].notify = tz_notify_trip;
+ tz->tz_threshold[1].data = tz;
+ ret = sensor_set_trip(tz->sensor.sensor_id,
+ &tz->tz_threshold[1]);
+ break;
+ default:
+ ret = tz->ops->set_trip_temp(tz, trip, temp);
+ break;
+ }
+
+ return ret;
+}
+
+int sensor_init(struct thermal_zone_device *tz)
+{
+ struct sensor_info *sensor = &tz->sensor;
+
+ sensor->sensor_id = tz->id;
+ sensor->tz = tz;
+ sensor->threshold_min = 0;
+ sensor->threshold_max = INT_MAX;
+ sensor->max_idx = -1;
+ sensor->min_idx = -1;
+ mutex_init(&sensor->lock);
+ INIT_LIST_HEAD(&sensor->sensor_list);
+ INIT_LIST_HEAD(&sensor->threshold_list);
+ INIT_LIST_HEAD(&tz->tz_threshold[0].list);
+ INIT_LIST_HEAD(&tz->tz_threshold[1].list);
+ tz->tz_threshold[0].notify = NULL;
+ tz->tz_threshold[0].data = NULL;
+ tz->tz_threshold[1].notify = NULL;
+ tz->tz_threshold[1].data = NULL;
+ list_add(&sensor->sensor_list, &sensor_info_list);
+ INIT_WORK(&sensor->work, sensor_update_work);
+
+ return 0;
+}
+
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{
int err;
@@ -243,7 +511,7 @@
if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
return -EINVAL;
- ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+ ret = sensor_get_trip_temp(tz, trip, &temperature);
if (ret)
return ret;
@@ -268,7 +536,8 @@
if (!sscanf(buf, "%ld", &temperature))
return -EINVAL;
- ret = tz->ops->set_trip_temp(tz, trip, temperature);
+ ret = sensor_set_trip_temp(tz, trip, temperature);
+
if (ret)
return ret;
@@ -1313,6 +1582,7 @@
if (result)
break;
}
+ sensor_init(tz);
mutex_unlock(&thermal_list_lock);
INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
@@ -1372,6 +1642,10 @@
&trip_point_attrs[count * 2 + 1]);
}
thermal_remove_hwmon_sysfs(tz);
+ flush_work(&tz->sensor.work);
+ mutex_lock(&thermal_list_lock);
+ list_del(&tz->sensor.sensor_list);
+ mutex_unlock(&thermal_list_lock);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr);
mutex_destroy(&tz->lock);
diff --git a/drivers/tty/serial/msm_serial_hs_lite.c b/drivers/tty/serial/msm_serial_hs_lite.c
index d520253..a4a4f28 100644
--- a/drivers/tty/serial/msm_serial_hs_lite.c
+++ b/drivers/tty/serial/msm_serial_hs_lite.c
@@ -47,6 +47,8 @@
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/wakelock.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
#include <mach/board.h>
#include <mach/msm_serial_hs_lite.h>
#include <mach/msm_bus.h>
@@ -166,12 +168,17 @@
static inline void msm_hsl_write(struct uart_port *port,
unsigned int val, unsigned int off)
{
- iowrite32(val, port->membase + off);
+ __iowmb();
+ __raw_writel_no_log((__force __u32)cpu_to_le32(val),
+ port->membase + off);
}
static inline unsigned int msm_hsl_read(struct uart_port *port,
unsigned int off)
{
- return ioread32(port->membase + off);
+ unsigned int v = le32_to_cpu((__force __le32)__raw_readl_no_log(
+ port->membase + off));
+ __iormb();
+ return v;
}
static unsigned int msm_serial_hsl_has_gsbi(struct uart_port *port)
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index db6fec9..98c6884 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -111,7 +111,33 @@
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(mode);
+ /*
+ * Set this bit so that device attempts three more times at SS, even
+ * if it failed previously to operate in SS mode.
+ */
+ reg |= DWC3_GCTL_U2RSTECN;
+ if (mode == DWC3_GCTL_PRTCAP_HOST) {
+ /*
+ * Allow ITP generated off of ref clk based counter instead
+ * of UTMI/ULPI clk based counter, when superspeed only is
+ * active so that UTMI/ULPI PHY can be suspened.
+ */
+ reg |= DWC3_GCTL_SOFITPSYNC;
+ reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(2);
+ } else if (mode == DWC3_GCTL_PRTCAP_DEVICE) {
+ reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(2);
+ reg &= ~(DWC3_GCTL_SOFITPSYNC);
+ }
+ reg |= DWC3_GCTL_U2EXIT_LFPS;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+ reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+ reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+ reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+ dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
/**
@@ -127,6 +153,9 @@
reg |= DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+ if (dwc->revision >= DWC3_REVISION_230A)
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);
+
/* Assert USB3 PHY reset */
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
@@ -155,6 +184,9 @@
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+ if (dwc->revision >= DWC3_REVISION_230A)
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);
}
/**
@@ -473,6 +505,20 @@
dwc3_gadget_restart(dwc);
}
+static void (*notify_event) (struct dwc3 *, unsigned);
+void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned))
+{
+ notify_event = notify;
+}
+EXPORT_SYMBOL(dwc3_set_notifier);
+
+void dwc3_notify_event(struct dwc3 *dwc, unsigned event)
+{
+ if (dwc->notify_event)
+ dwc->notify_event(dwc, event);
+}
+EXPORT_SYMBOL(dwc3_notify_event);
+
#define DWC3_ALIGN_MASK (16 - 1)
static u64 dwc3_dma_mask = DMA_BIT_MASK(64);
@@ -504,6 +550,7 @@
if (!dev->coherent_dma_mask)
dev->coherent_dma_mask = DMA_BIT_MASK(64);
+ dwc->notify_event = notify_event;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
dev_err(dev, "missing IRQ\n");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 2064c13..328f6f4 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -163,7 +163,10 @@
/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
+#define DWC3_GCTL_PWRDNSCALEMASK (0xFFF80000)
#define DWC3_GCTL_U2RSTECN (1 << 16)
+#define DWC3_GCTL_SOFITPSYNC (1 << 10)
+#define DWC3_GCTL_U2EXIT_LFPS (1 << 2)
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
#define DWC3_GCTL_CLK_BUS (0)
#define DWC3_GCTL_CLK_PIPE (1)
@@ -643,6 +646,9 @@
__le64 dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
};
+#define DWC3_CONTROLLER_ERROR_EVENT 0
+#define DWC3_CONTROLLER_RESET_EVENT 1
+#define DWC3_CONTROLLER_POST_RESET_EVENT 2
/**
* struct dwc3 - representation of our controller
* @ctrl_req: usb control request which is used for ep0
@@ -771,6 +777,7 @@
/* Indicate if software connect was issued by the usb_gadget_driver */
bool softconnect;
+ void (*notify_event) (struct dwc3 *, unsigned);
};
/* -------------------------------------------------------------------------- */
@@ -922,6 +929,9 @@
void dwc3_post_host_reset_core_init(struct dwc3 *dwc);
int dwc3_event_buffers_setup(struct dwc3 *dwc);
+extern void dwc3_set_notifier(
+ void (*notify) (struct dwc3 *dwc3, unsigned event));
+extern void dwc3_notify_event(struct dwc3 *dwc3, unsigned event);
extern int dwc3_get_device_id(void);
extern void dwc3_put_device_id(int id);
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h
index b156c5f..4901f4b 100644
--- a/drivers/usb/dwc3/debug.h
+++ b/drivers/usb/dwc3/debug.h
@@ -46,6 +46,7 @@
extern void dbg_setup(u8, const struct usb_ctrlrequest*);
extern int dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_exit(struct dwc3 *);
+extern void dbg_print_reg(const char *name, int reg);
#else
static inline void dbg_event(u8, const char*, int)
{ }
@@ -57,6 +58,8 @@
{ }
static inline void dbg_setup(u8, const struct usb_ctrlrequest*)
{ }
+static inline void dbg_print_reg(const char *name, int reg)
+{ }
static inline int dwc3_debugfs_init(struct dwc3 *d)
{ return 0; }
static inline void dwc3_debugfs_exit(struct dwc3 *d)
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index df95646..a2580fc 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -972,6 +972,28 @@
}
/**
+ * dbg_print_reg: prints a reg value
+ * @name: reg name
+ * @reg: reg value to be printed
+ */
+void dbg_print_reg(const char *name, int reg)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&dbg_dwc3_data.lck, flags);
+
+ scnprintf(dbg_dwc3_data.buf[dbg_dwc3_data.idx], DBG_DATA_MSG,
+ "%s = 0x%08x\n", name, reg);
+
+ dbg_inc(&dbg_dwc3_data.idx);
+
+ write_unlock_irqrestore(&dbg_dwc3_data.lck, flags);
+
+ if (dbg_dwc3_data.tty != 0)
+ pr_notice("%s = 0x%08x\n", name, reg);
+}
+
+/**
* store_events: configure if events are going to be also printed to console
*
*/
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index d3ea3be..d7721dc 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -50,6 +50,7 @@
#include "dwc3_otg.h"
#include "core.h"
#include "gadget.h"
+#include "debug.h"
/* ADC threshold values */
static int adc_low_threshold = 700;
@@ -140,6 +141,7 @@
#define QSCRATCH_REG_OFFSET (0x000F8800)
#define QSCRATCH_CTRL_REG (QSCRATCH_REG_OFFSET + 0x04)
#define QSCRATCH_GENERAL_CFG (QSCRATCH_REG_OFFSET + 0x08)
+#define QSCRATCH_RAM1_REG (QSCRATCH_REG_OFFSET + 0x0C)
#define HS_PHY_CTRL_REG (QSCRATCH_REG_OFFSET + 0x10)
#define PARAMETER_OVERRIDE_X_REG (QSCRATCH_REG_OFFSET + 0x14)
#define CHARGING_DET_CTRL_REG (QSCRATCH_REG_OFFSET + 0x18)
@@ -156,6 +158,8 @@
#define SS_CR_PROTOCOL_CAP_DATA_REG (QSCRATCH_REG_OFFSET + 0x48)
#define SS_CR_PROTOCOL_READ_REG (QSCRATCH_REG_OFFSET + 0x4C)
#define SS_CR_PROTOCOL_WRITE_REG (QSCRATCH_REG_OFFSET + 0x50)
+#define PWR_EVNT_IRQ_STAT_REG (QSCRATCH_REG_OFFSET + 0x58)
+#define PWR_EVNT_IRQ_MASK_REG (QSCRATCH_REG_OFFSET + 0x5C)
struct dwc3_msm_req_complete {
struct list_head list_item;
@@ -223,7 +227,7 @@
bool ext_inuse;
enum dwc3_id_state id_state;
unsigned long lpm_flags;
-#define MDWC3_CORECLK_OFF BIT(0)
+#define MDWC3_PHY_REF_AND_CORECLK_OFF BIT(0)
#define MDWC3_TCXO_SHUTDOWN BIT(1)
u32 qscratch_ctl_val;
@@ -410,6 +414,37 @@
}
/**
+ * Dump all QSCRATCH registers.
+ *
+ */
+static void dwc3_msm_dump_phy_info(struct dwc3_msm *mdwc)
+{
+
+ dbg_print_reg("SSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+ SS_PHY_CTRL_REG));
+ dbg_print_reg("HSPHY_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+ HS_PHY_CTRL_REG));
+ dbg_print_reg("QSCRATCH_CTRL_REG", dwc3_msm_read_reg(mdwc->base,
+ QSCRATCH_CTRL_REG));
+ dbg_print_reg("QSCRATCH_GENERAL_CFG", dwc3_msm_read_reg(mdwc->base,
+ QSCRATCH_GENERAL_CFG));
+ dbg_print_reg("PARAMETER_OVERRIDE_X_REG", dwc3_msm_read_reg(mdwc->base,
+ PARAMETER_OVERRIDE_X_REG));
+ dbg_print_reg("HS_PHY_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
+ HS_PHY_IRQ_STAT_REG));
+ dbg_print_reg("SS_PHY_PARAM_CTRL_1", dwc3_msm_read_reg(mdwc->base,
+ SS_PHY_PARAM_CTRL_1));
+ dbg_print_reg("SS_PHY_PARAM_CTRL_2", dwc3_msm_read_reg(mdwc->base,
+ SS_PHY_PARAM_CTRL_2));
+ dbg_print_reg("QSCRATCH_RAM1_REG", dwc3_msm_read_reg(mdwc->base,
+ QSCRATCH_RAM1_REG));
+ dbg_print_reg("PWR_EVNT_IRQ_STAT_REG", dwc3_msm_read_reg(mdwc->base,
+ PWR_EVNT_IRQ_STAT_REG));
+ dbg_print_reg("PWR_EVNT_IRQ_MASK_REG", dwc3_msm_read_reg(mdwc->base,
+ PWR_EVNT_IRQ_MASK_REG));
+}
+
+/**
* Return DBM EP number according to usb endpoint number.
*
*/
@@ -1381,8 +1416,14 @@
}
/* Initialize QSCRATCH registers for HSPHY and SSPHY operation */
-static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc)
+static void dwc3_msm_qscratch_reg_init(struct dwc3_msm *mdwc,
+ unsigned event_status)
{
+ if (event_status == DWC3_CONTROLLER_POST_RESET_EVENT) {
+ dwc3_msm_ss_phy_reg_init(mdwc);
+ return;
+ }
+
/* SSPHY Initialization: Use ref_clk from pads and set its parameters */
dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
msleep(30);
@@ -1393,7 +1434,7 @@
dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210002);
usleep_range(2000, 2200);
/* Ref clock must be stable now, enable ref clock for HS mode */
- dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x10210102);
+ dwc3_msm_write_reg(mdwc->base, SS_PHY_CTRL_REG, 0x11210102);
usleep_range(2000, 2200);
/*
* HSPHY Initialization: Enable UTMI clock and clamp enable HVINTs,
@@ -1401,8 +1442,8 @@
*/
dwc3_msm_write_reg(mdwc->base, HS_PHY_CTRL_REG, 0x5220bb2);
usleep_range(2000, 2200);
- /* Disable (bypass) VBUS and ID filters */
- dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x78);
+ /* Set XHCI_REV bit (2) to 1 - XHCI version 1.0 */
+ dwc3_msm_write_reg(mdwc->base, QSCRATCH_GENERAL_CFG, 0x4);
/*
* write HSPHY init value to QSCRATCH reg to set HSPHY parameters like
* VBUS valid threshold, disconnect valid threshold, DC voltage level,
@@ -1415,14 +1456,14 @@
PARAMETER_OVERRIDE_X_REG, 0x03FFFFFF,
mdwc->hsphy_init_seq & 0x03FFFFFF);
- /* Enable master clock for RAMs to allow BAM to access RAMs when
- * RAM clock gating is enabled via DWC3's GCTL. Otherwise, issues
+ /*
+ * Enable master clock for RAMs to allow BAM to access RAMs when
+ * RAM clock gating is enabled via DWC3's GCTL. Otherwise issues
* are seen where RAM clocks get turned OFF in SS mode
*/
dwc3_msm_write_reg(mdwc->base, CGCTL_REG,
dwc3_msm_read_reg(mdwc->base, CGCTL_REG) | 0x18);
- dwc3_msm_ss_phy_reg_init(mdwc);
/*
* This is required to restore the POR value after userspace
* is done with charger detection.
@@ -1431,6 +1472,31 @@
dwc3_msm_read_reg(mdwc->base, QSCRATCH_CTRL_REG);
}
+static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
+{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dwc->dev->parent);
+
+ switch (event) {
+ case DWC3_CONTROLLER_ERROR_EVENT:
+ dev_info(mdwc->dev, "DWC3_CONTROLLER_ERROR_EVENT received\n");
+ dwc3_msm_dump_phy_info(mdwc);
+ break;
+ case DWC3_CONTROLLER_RESET_EVENT:
+ dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
+ dwc3_msm_qscratch_reg_init(mdwc, DWC3_CONTROLLER_RESET_EVENT);
+ break;
+ case DWC3_CONTROLLER_POST_RESET_EVENT:
+ dev_dbg(mdwc->dev,
+ "DWC3_CONTROLLER_POST_RESET_EVENT received\n");
+ dwc3_msm_qscratch_reg_init(mdwc,
+ DWC3_CONTROLLER_POST_RESET_EVENT);
+ break;
+ default:
+ dev_dbg(mdwc->dev, "unknown dwc3 event\n");
+ break;
+ }
+}
+
static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)
{
struct dwc3_msm *mdwc = container_of(xceiv, struct dwc3_msm, ext_xceiv);
@@ -1447,9 +1513,6 @@
return;
usleep_range(10000, 12000);
-
- /* Reinitialize QSCRATCH registers after block reset */
- dwc3_msm_qscratch_reg_init(mdwc);
}
/* Reset the DBM */
@@ -1687,6 +1750,7 @@
bool dcp;
bool host_bus_suspend;
bool host_ss_active;
+ bool host_ss_suspend;
dev_dbg(mdwc->dev, "%s: entering lpm\n", __func__);
@@ -1713,6 +1777,7 @@
(mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER) ||
(mdwc->charger.chg_type == DWC3_FLOATED_CHARGER));
host_bus_suspend = mdwc->host_mode == 1;
+ host_ss_suspend = host_bus_suspend && host_ss_active;
if (!dcp && !host_bus_suspend)
dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
@@ -1724,13 +1789,17 @@
* 3. Set TEST_POWERED_DOWN in SS_PHY_CTRL_REG to enable PHY retention
* 4. Disable SSPHY ref clk
*/
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8), 0x0);
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28), 0x0);
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+ if (!host_ss_suspend) {
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+ 0x0);
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+ 0x0);
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
(1 << 26));
-
+ }
usleep_range(1000, 1200);
- clk_disable_unprepare(mdwc->ref_clk);
+ if (!host_ss_suspend)
+ clk_disable_unprepare(mdwc->ref_clk);
if (host_bus_suspend) {
/* Sequence for host bus suspend case:
@@ -1775,9 +1844,9 @@
if (!host_bus_suspend)
dwc3_msm_config_gdsc(mdwc, 0);
- if (!host_bus_suspend || !host_ss_active) {
+ if (!host_ss_suspend) {
clk_disable_unprepare(mdwc->core_clk);
- mdwc->lpm_flags |= MDWC3_CORECLK_OFF;
+ mdwc->lpm_flags |= MDWC3_PHY_REF_AND_CORECLK_OFF;
}
clk_disable_unprepare(mdwc->iface_clk);
@@ -1825,6 +1894,7 @@
int ret;
bool dcp;
bool host_bus_suspend;
+ bool resume_from_core_clk_off = false;
dev_dbg(mdwc->dev, "%s: exiting lpm\n", __func__);
@@ -1835,6 +1905,9 @@
pm_stay_awake(mdwc->dev);
+ if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
+ resume_from_core_clk_off = true;
+
if (mdwc->bus_perf_client) {
ret = msm_bus_scale_client_update_request(
mdwc->bus_perf_client, 1);
@@ -1873,13 +1946,14 @@
if (!host_bus_suspend && !dcp)
dwc3_hsusb_config_vddcx(mdwc, 1);
- clk_prepare_enable(mdwc->ref_clk);
+ if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF)
+ clk_prepare_enable(mdwc->ref_clk);
usleep_range(1000, 1200);
clk_prepare_enable(mdwc->iface_clk);
- if (mdwc->lpm_flags & MDWC3_CORECLK_OFF) {
+ if (mdwc->lpm_flags & MDWC3_PHY_REF_AND_CORECLK_OFF) {
clk_prepare_enable(mdwc->core_clk);
- mdwc->lpm_flags &= ~MDWC3_CORECLK_OFF;
+ mdwc->lpm_flags &= ~MDWC3_PHY_REF_AND_CORECLK_OFF;
}
if (host_bus_suspend) {
@@ -1892,10 +1966,6 @@
/* Disable DP and DM HV interrupt */
dwc3_msm_write_reg(mdwc->base, ALT_INTERRUPT_EN_REG, 0x000);
-
- /* Clear suspend bit in GUSB2PHYCONFIG register */
- dwc3_msm_write_readback(mdwc->base, DWC3_GUSB2PHYCFG(0),
- 0x40, 0x0);
} else {
/* Disable HV interrupt */
if (mdwc->otg_xceiv && (!mdwc->ext_xceiv.otg_capability))
@@ -1919,23 +1989,27 @@
}
- /* Assert SS PHY RESET */
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+ if (resume_from_core_clk_off) {
+ /* Assert SS PHY RESET */
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
(1 << 7));
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 28),
(1 << 28));
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 8),
(1 << 8));
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26), 0x0);
- /* 10usec delay required before de-asserting SS PHY RESET */
- udelay(10);
- dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7), 0x0);
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 26),
+ 0x0);
+ /* 10usec delay required before de-asserting SS PHY RESET */
+ udelay(10);
+ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, (1 << 7),
+ 0x0);
- /*
- * Reinitilize SSPHY parameters as SS_PHY RESET will reset
- * the internal registers to default values.
- */
- dwc3_msm_ss_phy_reg_init(mdwc);
+ /*
+ * Reinitilize SSPHY parameters as SS_PHY RESET will reset
+ * the internal registers to default values.
+ */
+ dwc3_msm_ss_phy_reg_init(mdwc);
+ }
atomic_set(&mdwc->in_lpm, 0);
/* match disable_irq call from isr */
@@ -2072,7 +2146,7 @@
static struct dentry *dwc3_debugfs_root;
-static void dwc3_debugfs_init(struct dwc3_msm *mdwc)
+static void dwc3_msm_debugfs_init(struct dwc3_msm *mdwc)
{
dwc3_debugfs_root = debugfs_create_dir("msm_dwc3", NULL);
@@ -2871,8 +2945,6 @@
else if (!mdwc->hsphy_init_seq)
dev_warn(&pdev->dev, "incorrect hsphyinitseq.Using PORvalue\n");
- dwc3_msm_qscratch_reg_init(mdwc);
-
pm_runtime_set_active(mdwc->dev);
pm_runtime_enable(mdwc->dev);
@@ -2891,7 +2963,7 @@
ret = -ENODEV;
goto disable_hs_ldo;
}
-
+ dwc3_set_notifier(&dwc3_msm_notify_event);
/* usb_psy required only for vbus_notifications or charging support */
if (mdwc->ext_xceiv.otg_capability ||
!mdwc->charger.charging_disabled) {
@@ -2990,7 +3062,7 @@
device_init_wakeup(mdwc->dev, 1);
pm_stay_awake(mdwc->dev);
- dwc3_debugfs_init(mdwc);
+ dwc3_msm_debugfs_init(mdwc);
return 0;
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index d0d9d34..e912e86 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -56,6 +56,19 @@
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_HOST);
+ /*
+ * Allow ITP generated off of ref clk based counter instead
+ * of UTMI/ULPI clk based counter, when superspeed only is
+ * active so that UTMI/ULPI can be suspened.
+ */
+ reg |= DWC3_GCTL_SOFITPSYNC;
+ /*
+ * Set this bit so that device attempts three more times at SS,
+ * even if it failed previously to operate in SS mode.
+ */
+ reg |= DWC3_GCTL_U2RSTECN;
+ reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(2);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
}
@@ -126,6 +139,14 @@
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+ /*
+ * Set this bit so that device attempts three more times at SS,
+ * even if it failed previously to operate in SS mode.
+ */
+ reg |= DWC3_GCTL_U2RSTECN;
+ reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
+ reg |= DWC3_GCTL_PWRDNSCALE(2);
+ reg &= ~(DWC3_GCTL_SOFITPSYNC);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
}
@@ -847,7 +868,8 @@
* OCFG[1] - HNPCap = 0
* OCFG[0] - SRPCap = 0
*/
- dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_writel(dotg->regs, DWC3_OCFG, 0x4);
/*
* OCTL[6] - PeriMode = 1
@@ -859,7 +881,8 @@
* OCTL[0] - HstSetHNPEn = 0
*/
if (!once) {
- dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
+ if (ext_xceiv && !ext_xceiv->otg_capability)
+ dwc3_writel(dotg->regs, DWC3_OCTL, 0x40);
once++;
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index acda980..8cf8a6d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -63,6 +63,9 @@
MODULE_PARM_DESC(tx_fifo_resize_enable,
"Enable allocating Tx fifo for endpoints");
+static void dwc3_gadget_usb2_phy_suspend(struct dwc3 *dwc, int suspend);
+static void dwc3_gadget_usb3_phy_suspend(struct dwc3 *dwc, int suspend);
+
/**
* dwc3_gadget_set_test_mode - Enables USB2 Test Modes
* @dwc: pointer to our context structure
@@ -322,6 +325,16 @@
{
u32 timeout = 500;
u32 reg;
+ bool hsphy_suspend_enabled;
+ int ret;
+
+ /* Commands to controller will work only if PHY is not suspended */
+ hsphy_suspend_enabled = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+ DWC3_GUSB2PHYCFG_SUSPHY);
+
+ /* Disable suspend of the USB2 PHY */
+ if (hsphy_suspend_enabled)
+ dwc3_gadget_usb2_phy_suspend(dwc, false);
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
@@ -331,7 +344,8 @@
if (!(reg & DWC3_DGCMD_CMDACT)) {
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
DWC3_DGCMD_STATUS(reg));
- return 0;
+ ret = 0;
+ break;
}
/*
@@ -339,10 +353,18 @@
* interrupt context.
*/
timeout--;
- if (!timeout)
- return -ETIMEDOUT;
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ break;
+ }
udelay(1);
} while (1);
+
+ /* Enable suspend of the USB2 PHY */
+ if (hsphy_suspend_enabled)
+ dwc3_gadget_usb2_phy_suspend(dwc, true);
+
+ return ret;
}
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
@@ -351,12 +373,22 @@
struct dwc3_ep *dep = dwc->eps[ep];
u32 timeout = 500;
u32 reg;
+ bool hsphy_suspend_enabled;
+ int ret;
dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
dep->name,
dwc3_gadget_ep_cmd_string(cmd), params->param0,
params->param1, params->param2);
+ /* Commands to controller will work only if PHY is not suspended */
+ hsphy_suspend_enabled = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
+ DWC3_GUSB2PHYCFG_SUSPHY);
+
+ /* Disable suspend of the USB2 PHY */
+ if (hsphy_suspend_enabled)
+ dwc3_gadget_usb2_phy_suspend(dwc, false);
+
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
@@ -374,9 +406,10 @@
* event. Hence return error in this case.
*/
if (reg & 0x2000)
- return -EAGAIN;
+ ret = -EAGAIN;
else
- return 0;
+ ret = 0;
+ break;
}
/*
@@ -384,11 +417,19 @@
* interrupt context.
*/
timeout--;
- if (!timeout)
- return -ETIMEDOUT;
+ if (!timeout) {
+ ret = -ETIMEDOUT;
+ break;
+ }
udelay(1);
} while (1);
+
+ /* Enable suspend of the USB2 PHY */
+ if (hsphy_suspend_enabled)
+ dwc3_gadget_usb2_phy_suspend(dwc, true);
+
+ return ret;
}
dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
@@ -1677,6 +1718,9 @@
reg |= DWC3_DCTL_HIRD_THRES(28);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ dwc3_gadget_usb2_phy_suspend(dwc, true);
+ dwc3_gadget_usb3_phy_suspend(dwc, true);
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
@@ -2572,6 +2616,35 @@
dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
}
+static void dwc3_dump_reg_info(struct dwc3 *dwc)
+{
+ dbg_event(0xFF, "REGDUMP", 0);
+
+ dbg_print_reg("GUSB3PIPCTL", dwc3_readl(dwc->regs,
+ DWC3_GUSB3PIPECTL(0)));
+ dbg_print_reg("GUSB2PHYCONFIG", dwc3_readl(dwc->regs,
+ DWC3_GUSB2PHYCFG(0)));
+ dbg_print_reg("GCTL", dwc3_readl(dwc->regs, DWC3_GCTL));
+ dbg_print_reg("GUCTL", dwc3_readl(dwc->regs, DWC3_GUCTL));
+ dbg_print_reg("GDBGLTSSM", dwc3_readl(dwc->regs, DWC3_GDBGLTSSM));
+ dbg_print_reg("DCFG", dwc3_readl(dwc->regs, DWC3_DCFG));
+ dbg_print_reg("DCTL", dwc3_readl(dwc->regs, DWC3_DCTL));
+ dbg_print_reg("DEVTEN", dwc3_readl(dwc->regs, DWC3_DEVTEN));
+ dbg_print_reg("DSTS", dwc3_readl(dwc->regs, DWC3_DSTS));
+ dbg_print_reg("DALPENA", dwc3_readl(dwc->regs, DWC3_DALEPENA));
+ dbg_print_reg("DGCMD", dwc3_readl(dwc->regs, DWC3_DGCMD));
+
+ dbg_print_reg("OCFG", dwc3_readl(dwc->regs, DWC3_OCFG));
+ dbg_print_reg("OCTL", dwc3_readl(dwc->regs, DWC3_OCTL));
+ dbg_print_reg("OEVT", dwc3_readl(dwc->regs, DWC3_OEVT));
+ dbg_print_reg("OSTS", dwc3_readl(dwc->regs, DWC3_OSTS));
+
+ dwc3_notify_event(dwc, DWC3_CONTROLLER_ERROR_EVENT);
+
+ panic("DWC3 Erratic error\n");
+
+}
+
static void dwc3_gadget_interrupt(struct dwc3 *dwc,
const struct dwc3_event_devt *event)
{
@@ -2600,6 +2673,7 @@
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
dbg_event(0xFF, "ERROR", 0);
dev_vdbg(dwc->dev, "Erratic Error\n");
+ dwc3_dump_reg_info(dwc);
break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
dev_vdbg(dwc->dev, "Command Complete\n");
@@ -2824,8 +2898,8 @@
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
- dwc3_gadget_usb2_phy_suspend(dwc, false);
- dwc3_gadget_usb3_phy_suspend(dwc, false);
+ dwc3_gadget_usb2_phy_suspend(dwc, true);
+ dwc3_gadget_usb3_phy_suspend(dwc, true);
}
ret = device_register(&dwc->gadget.dev);
diff --git a/drivers/usb/gadget/f_qdss.c b/drivers/usb/gadget/f_qdss.c
index f90967f..3b94dd5 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -441,6 +441,10 @@
pr_debug("usb_qdss_disconnect_work\n");
+ status = uninit_data(qdss->data);
+ if (status)
+ pr_err("%s: uninit_data error\n", __func__);
+
/* notify qdss to cancell all active transfers*/
if (qdss->ch.notify) {
qdss->ch.notify(qdss->ch.priv, USB_QDSS_DISCONNECT, NULL,
@@ -458,22 +462,22 @@
{
struct f_qdss *qdss = func_to_qdss(f);
unsigned long flags;
- int status;
pr_debug("qdss_disable\n");
spin_lock_irqsave(&qdss->lock, flags);
+ if (!qdss->usb_connected) {
+ spin_unlock_irqrestore(&qdss->lock, flags);
+ return;
+ }
+
qdss->usb_connected = 0;
spin_unlock_irqrestore(&qdss->lock, flags);
/*cancell all active xfers*/
qdss_eps_disable(f);
- status = uninit_data(qdss->data);
- if (status)
- pr_err("%s: uninit_data error\n", __func__);
-
- schedule_work(&qdss->disconnect_w);
+ queue_work(qdss->wq, &qdss->disconnect_w);
}
static void usb_qdss_connect_work(struct work_struct *work)
@@ -521,6 +525,7 @@
if (gadget->speed != USB_SPEED_SUPER &&
gadget->speed != USB_SPEED_HIGH) {
pr_err("qdss_st_alt: qdss supportes HS or SS only\n");
+ ret = -EINVAL;
goto fail;
}
@@ -562,7 +567,7 @@
qdss->usb_connected = 1;
if (qdss->usb_connected && ch->app_conn)
- schedule_work(&qdss->connect_w);
+ queue_work(qdss->wq, &qdss->connect_w);
return 0;
fail:
@@ -610,7 +615,13 @@
spin_unlock_irqrestore(&d_lock, flags);
return -ENOMEM;
}
-
+ spin_unlock_irqrestore(&d_lock, flags);
+ qdss->wq = create_singlethread_workqueue(name);
+ if (!qdss->wq) {
+ kfree(qdss);
+ return -ENOMEM;
+ }
+ spin_lock_irqsave(&d_lock, flags);
ch = &qdss->ch;
ch->name = name;
list_add_tail(&ch->list, &usb_qdss_ch_list);
@@ -765,6 +776,13 @@
spin_unlock_irqrestore(&d_lock, flags);
return ERR_PTR(-ENOMEM);
}
+ spin_unlock_irqrestore(&d_lock, flags);
+ qdss->wq = create_singlethread_workqueue(name);
+ if (!qdss->wq) {
+ kfree(qdss);
+ return ERR_PTR(-ENOMEM);
+ }
+ spin_lock_irqsave(&d_lock, flags);
ch = &qdss->ch;
list_add_tail(&ch->list, &usb_qdss_ch_list);
} else {
@@ -781,7 +799,7 @@
/* the case USB cabel was connected befor qdss called qdss_open*/
if (qdss->usb_connected == 1)
- schedule_work(&qdss->connect_w);
+ queue_work(qdss->wq, &qdss->connect_w);
return ch;
}
@@ -819,7 +837,7 @@
_ch = list_entry(act, struct usb_qdss_ch, list);
qdss = container_of(_ch, struct f_qdss, ch);
spin_lock_irqsave(&d_lock, flags);
-
+ destroy_workqueue(qdss->wq);
if (!_ch->priv) {
list_del(&_ch->list);
kfree(qdss);
diff --git a/drivers/usb/gadget/f_qdss.h b/drivers/usb/gadget/f_qdss.h
index 93b5b1f..dcc80b7 100644
--- a/drivers/usb/gadget/f_qdss.h
+++ b/drivers/usb/gadget/f_qdss.h
@@ -1,5 +1,5 @@
/*
- * 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
@@ -38,6 +38,7 @@
unsigned int data_enabled:1;
unsigned int ctrl_in_enabled:1;
unsigned int ctrl_out_enabled:1;
+ struct workqueue_struct *wq;
};
#endif
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index 641730b..b1a4293 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -658,6 +658,7 @@
const char *pdest;
u32 tmp;
int rc;
+ bool cont_splash_enabled = false;
pdest = of_get_property(pdev->dev.of_node,
"qcom,mdss-pan-dest", NULL);
@@ -679,6 +680,17 @@
"qcom,mdss-pan-underflow-clr", &tmp);
panel_data->panel_info.lcdc.underflow_clr = (!rc ? tmp : 0xff);
+ cont_splash_enabled = of_property_read_bool(pdev->dev.of_node,
+ "qcom,cont-splash-enabled");
+ if (!cont_splash_enabled) {
+ pr_debug("%s:%d Continuous splash flag not found.\n",
+ __func__, __LINE__);
+ panel_data->panel_info.cont_splash_enabled = 0;
+ } else {
+ pr_debug("%s:%d Continuous splash flag enabled.\n",
+ __func__, __LINE__);
+ panel_data->panel_info.cont_splash_enabled = 1;
+ }
return rc;
}
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 6293220..0a0c272 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -88,20 +88,11 @@
return bufq->count;
}
-static void mdp3_dispatch_vsync(struct work_struct *work)
-{
- struct mdp3_session_data *mdp3_session;
- mdp3_session = container_of(work, struct mdp3_session_data, vsync_work);
- if (mdp3_session && mdp3_session->mfd)
- sysfs_notify(&mdp3_session->mfd->fbi->dev->kobj, NULL,
- "vsync_event");
-}
-
void vsync_notify_handler(void *arg)
{
struct mdp3_session_data *session = (struct mdp3_session_data *)arg;
session->vsync_time = ktime_get();
- schedule_work(&session->vsync_work);
+ sysfs_notify_dirent(session->vsync_event_sd);
}
static int mdp3_ctrl_vsync_enable(struct msm_fb_data_type *mfd, int enable)
@@ -793,6 +784,64 @@
return ret;
}
+int mdp3_validate_start_req(struct mdp_histogram_start_req *req)
+{
+ if (req->frame_cnt >= MDP_HISTOGRAM_FRAME_COUNT_MAX) {
+ pr_err("%s invalid req frame_cnt\n", __func__);
+ return -EINVAL;
+ }
+ if (req->bit_mask >= MDP_HISTOGRAM_BIT_MASK_MAX) {
+ pr_err("%s invalid req bit mask\n", __func__);
+ return -EINVAL;
+ }
+ if (req->block != MDP_BLOCK_DMA_P ||
+ req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
+ pr_err("mdp3_histogram_start invalid request\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int mdp3_validate_scale_config(struct mdp_bl_scale_data *data)
+{
+ if (data->scale > MDP_HISTOGRAM_BL_SCALE_MAX) {
+ pr_err("%s invalid bl_scale\n", __func__);
+ return -EINVAL;
+ }
+ if (data->min_lvl > MDP_HISTOGRAM_BL_LEVEL_MAX) {
+ pr_err("%s invalid bl_min_lvl\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int mdp3_validate_csc_data(struct mdp_csc_cfg_data *data)
+{
+ int i;
+ for (i = 0; i < 9; i++) {
+ if (data->csc_data.csc_mv[i] >=
+ MDP_HISTOGRAM_CSC_MATRIX_MAX)
+ return -EINVAL;
+ }
+ for (i = 0; i < 3; i++) {
+ if (data->csc_data.csc_pre_bv[i] >=
+ MDP_HISTOGRAM_CSC_VECTOR_MAX)
+ return -EINVAL;
+ if (data->csc_data.csc_post_bv[i] >=
+ MDP_HISTOGRAM_CSC_VECTOR_MAX)
+ return -EINVAL;
+ }
+ for (i = 0; i < 6; i++) {
+ if (data->csc_data.csc_pre_lv[i] >=
+ MDP_HISTOGRAM_CSC_VECTOR_MAX)
+ return -EINVAL;
+ if (data->csc_data.csc_post_lv[i] >=
+ MDP_HISTOGRAM_CSC_VECTOR_MAX)
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int mdp3_histogram_start(struct mdp3_session_data *session,
struct mdp_histogram_start_req *req)
{
@@ -800,11 +849,10 @@
struct mdp3_dma_histogram_config histo_config;
pr_debug("mdp3_histogram_start\n");
- if (req->block != MDP_BLOCK_DMA_P ||
- req->num_bins != MDP_HISTOGRAM_BIN_NUM) {
- pr_err("mdp3_histogram_start invalid request\n");
- return -EINVAL;
- }
+
+ ret = mdp3_validate_start_req(req);
+ if (ret)
+ return ret;
if (!session->dma->histo_op ||
!session->dma->config_histo) {
@@ -1004,10 +1052,20 @@
switch (mdp_pp.op) {
case mdp_bl_scale_cfg:
+ ret = mdp3_validate_scale_config(&mdp_pp.data.bl_scale_data);
+ if (ret) {
+ pr_err("%s: invalid scale config\n", __func__);
+ break;
+ }
ret = mdp3_bl_scale_config(mfd, (struct mdp_bl_scale_data *)
&mdp_pp.data.bl_scale_data);
break;
case mdp_op_csc_cfg:
+ ret = mdp3_validate_csc_data(&(mdp_pp.data.csc_cfg_data));
+ if (ret) {
+ pr_err("%s: invalid csc data\n", __func__);
+ break;
+ }
ret = mdp3_csc_config(mdp3_session,
&(mdp_pp.data.csc_cfg_data));
break;
@@ -1239,7 +1297,6 @@
}
memset(mdp3_session, 0, sizeof(struct mdp3_session_data));
mutex_init(&mdp3_session->lock);
- INIT_WORK(&mdp3_session->vsync_work, mdp3_dispatch_vsync);
mutex_init(&mdp3_session->histo_lock);
mdp3_session->dma = mdp3_get_dma_pipe(MDP3_DMA_CAP_ALL);
if (!mdp3_session->dma) {
@@ -1265,6 +1322,7 @@
goto init_done;
}
+ mdp3_session->dma->output_config.out_sel = intf_type;
mdp3_session->mfd = mfd;
mdp3_session->panel = dev_get_platdata(&mfd->pdev->dev);
mdp3_session->status = 0;
@@ -1286,6 +1344,14 @@
goto init_done;
}
+ mdp3_session->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL,
+ "vsync_event");
+ if (!mdp3_session->vsync_event_sd) {
+ pr_err("vsync_event sysfs lookup failed\n");
+ rc = -ENODEV;
+ goto init_done;
+ }
+
kobject_uevent(&dev->kobj, KOBJ_ADD);
pr_debug("vsync kobject_uevent(KOBJ_ADD)\n");
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 9ea1c91..eb32797 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -43,10 +43,10 @@
ktime_t vsync_time;
struct timer_list vsync_timer;
int vsync_period;
+ struct sysfs_dirent *vsync_event_sd;
struct mdp_overlay overlay;
struct mdp3_buffer_queue bufq_in;
struct mdp3_buffer_queue bufq_out;
- struct work_struct vsync_work;
int histo_status;
struct mutex histo_lock;
int lut_sel;
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index cab8d11..f4421f2 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -503,7 +503,7 @@
struct mdp3_dma_histogram_config *histo_config)
{
unsigned long flag;
- u32 histo_bit_mask, histo_control;
+ u32 histo_bit_mask = 0, histo_control = 0;
u32 histo_isr_mask = MDP3_DMA_P_HIST_INTR_HIST_DONE_BIT |
MDP3_DMA_P_HIST_INTR_RESET_DONE_BIT;
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 732e740..6983e55 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -16,6 +16,12 @@
#include <linux/sched.h>
+#define MDP_HISTOGRAM_BL_SCALE_MAX 1024
+#define MDP_HISTOGRAM_BL_LEVEL_MAX 255
+#define MDP_HISTOGRAM_FRAME_COUNT_MAX 0x20
+#define MDP_HISTOGRAM_BIT_MASK_MAX 0x4
+#define MDP_HISTOGRAM_CSC_MATRIX_MAX 0x2000
+#define MDP_HISTOGRAM_CSC_VECTOR_MAX 0x200
#define MDP_HISTOGRAM_BIN_NUM 32
#define MDP_LUT_SIZE 256
diff --git a/drivers/video/msm/mdss/mdp3_ppp.c b/drivers/video/msm/mdss/mdp3_ppp.c
index 924ec5a..8e1dd66 100644
--- a/drivers/video/msm/mdss/mdp3_ppp.c
+++ b/drivers/video/msm/mdss/mdp3_ppp.c
@@ -344,7 +344,7 @@
int mdp3_ppp_turnon(struct msm_fb_data_type *mfd, int on_off)
{
struct mdss_panel_info *panel_info = mfd->panel_info;
- int ab = 0, ib = 0;
+ uint64_t ab = 0, ib = 0;
int rate = 0;
if (on_off) {
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 717241d..91257f2 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -39,6 +39,7 @@
#define MAX_DOWNSCALE_RATIO 4
#define MAX_UPSCALE_RATIO 20
#define MAX_DECIMATION 4
+#define MDP_MIN_VBP 4
#define C3_ALPHA 3 /* alpha */
#define C2_R_Cr 2 /* R/Cr */
@@ -364,6 +365,7 @@
struct mdss_overlay_private {
int vsync_pending;
ktime_t vsync_time;
+ struct sysfs_dirent *vsync_event_sd;
int borderfill_enable;
int overlay_play_enable;
int hw_refresh;
@@ -376,7 +378,6 @@
struct list_head overlay_list;
struct list_head pipes_used;
struct list_head pipes_cleanup;
- struct work_struct vsync_work;
bool mixer_swap;
};
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index edd4c19..4a426cf 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -242,6 +242,7 @@
u32 *clk_rate)
{
struct mdss_mdp_pipe *pipe;
+ struct mdss_panel_info *pinfo = NULL;
int fps = DEFAULT_FRAME_RATE;
u32 v_total;
int i;
@@ -252,22 +253,21 @@
*clk_rate = 0;
if (!mixer->rotator_mode) {
- int is_writeback = false;
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
- struct mdss_panel_info *pinfo;
pinfo = &mixer->ctl->panel_data->panel_info;
fps = mdss_panel_get_framerate(pinfo);
v_total = mdss_panel_get_vtotal(pinfo);
if (pinfo->type == WRITEBACK_PANEL)
- is_writeback = true;
+ pinfo = NULL;
} else {
v_total = mixer->height;
-
- is_writeback = true;
}
*clk_rate = mixer->width * v_total * fps;
- if (is_writeback) {
+ if (pinfo && pinfo->lcdc.v_back_porch < MDP_MIN_VBP)
+ *clk_rate = MDSS_MDP_CLK_FUDGE_FACTOR(*clk_rate);
+
+ if (!pinfo) {
/* perf for bus writeback */
*bus_ab_quota = fps * mixer->width * mixer->height * 3;
*bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 6252e17..938cb1f 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -1351,15 +1351,6 @@
mutex_unlock(&mdp5_data->ov_lock);
}
-static void mdss_mdp_overlay_dispatch_vsync(struct work_struct *work)
-{
- struct mdss_overlay_private *mdp5_data;
- mdp5_data = container_of(work, struct mdss_overlay_private, vsync_work);
- if (mdp5_data->ctl && mdp5_data->ctl->mfd)
- sysfs_notify(&mdp5_data->ctl->mfd->fbi->dev->kobj, NULL,
- "vsync_event");
-}
-
/* function is called in irq context should have minimum processing */
static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl,
ktime_t t)
@@ -1376,7 +1367,7 @@
pr_debug("vsync on fb%d play_cnt=%d\n", mfd->index, ctl->play_cnt);
mdp5_data->vsync_time = t;
- schedule_work(&mdp5_data->vsync_work);
+ sysfs_notify_dirent(mdp5_data->vsync_event_sd);
}
int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
@@ -2130,7 +2121,6 @@
INIT_LIST_HEAD(&mdp5_data->pipes_used);
INIT_LIST_HEAD(&mdp5_data->pipes_cleanup);
- INIT_WORK(&mdp5_data->vsync_work, mdss_mdp_overlay_dispatch_vsync);
mutex_init(&mdp5_data->ov_lock);
mdp5_data->hw_refresh = true;
mdp5_data->overlay_play_enable = true;
@@ -2153,6 +2143,14 @@
goto init_fail;
}
+ mdp5_data->vsync_event_sd = sysfs_get_dirent(dev->kobj.sd, NULL,
+ "vsync_event");
+ if (!mdp5_data->vsync_event_sd) {
+ pr_err("vsync_event sysfs lookup failed\n");
+ rc = -ENODEV;
+ goto init_fail;
+ }
+
pm_runtime_set_suspended(&mfd->pdev->dev);
pm_runtime_enable(&mfd->pdev->dev);
diff --git a/drivers/video/msm/mdss/mhl_sii8334.c b/drivers/video/msm/mdss/mhl_sii8334.c
index c66d50d..a759e86 100644
--- a/drivers/video/msm/mdss/mhl_sii8334.c
+++ b/drivers/video/msm/mdss/mhl_sii8334.c
@@ -357,14 +357,20 @@
static int mhl_sii_wait_for_rgnd(struct mhl_tx_ctrl *mhl_ctrl)
{
int timeout;
- /* let isr handle RGND interrupt */
+
pr_debug("%s:%u\n", __func__, __LINE__);
INIT_COMPLETION(mhl_ctrl->rgnd_done);
+ /*
+ * after toggling reset line and enabling disc
+ * tx can take a while to generate intr
+ */
timeout = wait_for_completion_interruptible_timeout
- (&mhl_ctrl->rgnd_done, HZ);
+ (&mhl_ctrl->rgnd_done, HZ * 3);
if (!timeout) {
- /* most likely nothing plugged in USB */
- /* USB HOST connected or already in USB mode */
+ /*
+ * most likely nothing plugged in USB
+ * USB HOST connected or already in USB mode
+ */
pr_warn("%s:%u timedout\n", __func__, __LINE__);
return -ENODEV;
}
@@ -380,9 +386,25 @@
struct i2c_client *client = mhl_ctrl->i2c_handle;
unsigned long flags;
- enable_irq(client->irq);
+ if (!mhl_ctrl->irq_req_done) {
+ rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
+ &mhl_tx_isr,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ client->dev.driver->name, mhl_ctrl);
+ if (rc) {
+ pr_err("request_threaded_irq failed, status: %d\n",
+ rc);
+ return -EINVAL;
+ } else {
+ pr_debug("request_threaded_irq succeeded\n");
+ mhl_ctrl->irq_req_done = true;
+ }
+ } else {
+ enable_irq(client->irq);
+ }
+
/* wait for i2c interrupt line to be activated */
- msleep(300);
+ msleep(100);
if (id) {
/* When MHL cable is disconnected we get a sii8334
@@ -413,8 +435,10 @@
/* chipset PR recommends waiting for at least 100 ms
* the chipset needs longer to come out of D3 state.
*/
- msleep(300);
+ msleep(100);
mhl_init_reg_settings(mhl_ctrl, true);
+ /* allow tx to enable dev disc after D3 state */
+ msleep(100);
rc = mhl_sii_wait_for_rgnd(mhl_ctrl);
} else {
if (mhl_ctrl->cur_state == POWER_STATE_D3) {
@@ -493,6 +517,10 @@
uint8_t i;
struct i2c_client *client = mhl_ctrl->i2c_handle;
+ /* Read the chip rev ID */
+ mhl_ctrl->chip_rev_id = MHL_SII_PAGE0_RD(0x04);
+ pr_debug("MHL: chip rev ID read=[%x]\n", mhl_ctrl->chip_rev_id);
+
/*
* REG_SRST
*/
@@ -1428,40 +1456,6 @@
return IRQ_HANDLED;
}
-static int mhl_tx_chip_init(struct mhl_tx_ctrl *mhl_ctrl)
-{
- uint8_t chip_rev_id = 0x00;
- struct i2c_client *client = mhl_ctrl->i2c_handle;
- unsigned long flags;
-
-
- spin_lock_irqsave(&mhl_ctrl->lock, flags);
- mhl_ctrl->dwnstream_hpd = 0;
- mhl_ctrl->tx_powered_off = false;
- spin_unlock_irqrestore(&mhl_ctrl->lock, flags);
-
- /* Reset the TX chip */
- mhl_sii_reset_pin(mhl_ctrl, 0);
- msleep(20);
- mhl_sii_reset_pin(mhl_ctrl, 1);
- /* TX PR-guide requires a 100 ms wait here */
- msleep(100);
-
- /* Read the chip rev ID */
- chip_rev_id = MHL_SII_PAGE0_RD(0x04);
- pr_debug("MHL: chip rev ID read=[%x]\n", chip_rev_id);
- mhl_ctrl->chip_rev_id = chip_rev_id;
-
- /*
- * Need to disable MHL discovery if
- * MHL-USB handshake is implemented
- */
- mhl_init_reg_settings(mhl_ctrl, true);
- switch_mode(mhl_ctrl, POWER_STATE_D3, true);
- pr_debug("%s:%u: power_down\n", __func__, __LINE__);
- mhl_tx_down(mhl_ctrl);
- return 0;
-}
static int mhl_sii_reg_config(struct i2c_client *client, bool enable)
{
@@ -1791,30 +1785,12 @@
}
}
- rc = mhl_tx_chip_init(mhl_ctrl);
- if (rc) {
- pr_err("%s: tx chip init failed [%d]\n",
- __func__, rc);
- goto failed_probe;
- }
+ mhl_ctrl->dwnstream_hpd = 0;
+ mhl_ctrl->tx_powered_off = false;
+
init_completion(&mhl_ctrl->rgnd_done);
- pr_debug("%s: IRQ from GPIO INTR = %d\n",
- __func__, mhl_ctrl->i2c_handle->irq);
- pr_debug("%s: Driver name = [%s]\n", __func__,
- client->dev.driver->name);
- rc = request_threaded_irq(mhl_ctrl->i2c_handle->irq, NULL,
- &mhl_tx_isr,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- client->dev.driver->name, mhl_ctrl);
- if (rc) {
- pr_err("request_threaded_irq failed, status: %d\n",
- rc);
- goto failed_probe;
- } else {
- pr_debug("request_threaded_irq succeeded\n");
- }
mhl_ctrl->mhl_psy.name = "ext-vbus";
mhl_ctrl->mhl_psy.type = POWER_SUPPLY_TYPE_USB_DCP;
@@ -1940,15 +1916,21 @@
#if defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP)
static int mhl_i2c_suspend_sub(struct i2c_client *client)
{
- enable_irq_wake(client->irq);
- disable_irq(client->irq);
+ struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+
+ if (mhl_ctrl->irq_req_done) {
+ enable_irq_wake(client->irq);
+ disable_irq(client->irq);
+ }
return 0;
}
static int mhl_i2c_resume_sub(struct i2c_client *client)
{
- disable_irq_wake(client->irq);
- enable_irq(client->irq);
+ struct mhl_tx_ctrl *mhl_ctrl = i2c_get_clientdata(client);
+
+ if (mhl_ctrl->irq_req_done)
+ disable_irq_wake(client->irq);
return 0;
}
#endif /* defined(CONFIG_PM) || defined(CONFIG_PM_SLEEP) */
diff --git a/include/linux/mhl_8334.h b/include/linux/mhl_8334.h
index d1ee11c..71dec42 100644
--- a/include/linux/mhl_8334.h
+++ b/include/linux/mhl_8334.h
@@ -165,6 +165,7 @@
bool tx_powered_off;
uint8_t dwnstream_hpd;
bool mhl_det_discon;
+ bool irq_req_done;
};
int mhl_i2c_reg_read(struct i2c_client *client,
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index 2c1fa11..2ca9900 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -23,6 +23,8 @@
uint32_t freq_control_mask;
int32_t core_limit_temp_degC;
int32_t core_temp_hysteresis_degC;
+ int32_t hotplug_temp_degC;
+ int32_t hotplug_temp_hysteresis_degC;
uint32_t core_control_mask;
int32_t vdd_rstr_temp_degC;
int32_t vdd_rstr_temp_hyst_degC;
diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h
index 4f39eaa..9a49c5e 100644
--- a/include/linux/qpnp/qpnp-adc.h
+++ b/include/linux/qpnp/qpnp-adc.h
@@ -218,6 +218,8 @@
* Uses a mapping table with 150K pullup.
* %SCALE_QRD_BATT_THERM: Conversion to temperature(decidegC) based on
* btm parameters.
+ * %SCALE_QRD_SKUAA_BATT_THERM: Conversion to temperature(decidegC) based on
+ * btm parametersi for SKUAA.
* %SCALE_NONE: Do not use this scaling type.
*/
enum qpnp_adc_scale_fn_type {
@@ -228,6 +230,7 @@
SCALE_XOTHERM,
SCALE_THERM_150K_PULLUP,
SCALE_QRD_BATT_THERM,
+ SCALE_QRD_SKUAA_BATT_THERM,
SCALE_NONE,
};
@@ -1121,6 +1124,23 @@
const struct qpnp_vadc_chan_properties *chan_prop,
struct qpnp_vadc_result *chan_rslt);
/**
+ * qpnp_adc_scale_qrd_skuaa_batt_therm() - Scales the pre-calibrated digital output
+ * of an ADC to the ADC reference and compensates for the
+ * gain and offset. Returns the temperature in decidegC.
+ * @dev: Structure device for qpnp vadc
+ * @adc_code: pre-calibrated digital ouput of the ADC.
+ * @adc_prop: adc properties of the pm8xxx adc such as bit resolution,
+ * reference voltage.
+ * @chan_prop: individual channel properties to compensate the i/p scaling,
+ * slope and offset.
+ * @chan_rslt: physical result to be stored.
+ */
+int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(struct qpnp_vadc_chip *dev,
+ int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt);
+/**
* qpnp_adc_scale_batt_id() - Scales the pre-calibrated digital output
* of an ADC to the ADC reference and compensates for the
* gain and offset.
@@ -1366,7 +1386,13 @@
struct qpnp_vadc_chip *vadc, int32_t adc_code,
const struct qpnp_adc_properties *adc_prop,
const struct qpnp_vadc_chan_properties *chan_prop,
- struct qpnp_vadc_result *chan_rslt);
+ struct qpnp_vadc_result *chan_rslt)
+{ return -ENXIO; }
+static inline int32_t qpnp_adc_scale_qrd_skuaa_batt_therm(
+ struct qpnp_vadc_chip *vadc, int32_t adc_code,
+ const struct qpnp_adc_properties *adc_prop,
+ const struct qpnp_vadc_chan_properties *chan_prop,
+ struct qpnp_vadc_result *chan_rslt)
{ return -ENXIO; }
static inline int32_t qpnp_adc_scale_batt_id(struct qpnp_vadc_chip *vadc,
int32_t adc_code,
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f740640..1bb3b06 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -97,6 +97,27 @@
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
+struct sensor_threshold {
+ int temp;
+ enum thermal_trip_type trip;
+ int (*notify)(enum thermal_trip_type type, int temp, void *data);
+ void *data;
+ struct list_head list;
+};
+
+struct sensor_info {
+ uint32_t sensor_id;
+ struct thermal_zone_device *tz;
+ int threshold_min;
+ int threshold_max;
+ int max_idx;
+ int min_idx;
+ struct list_head sensor_list;
+ struct list_head threshold_list;
+ struct mutex lock;
+ struct work_struct work;
+};
+
struct thermal_zone_device {
int id;
char type[THERMAL_NAME_LENGTH];
@@ -116,6 +137,8 @@
struct mutex lock; /* protect cooling devices list */
struct list_head node;
struct delayed_work poll_queue;
+ struct sensor_threshold tz_threshold[2];
+ struct sensor_info sensor;
};
/* Adding event notification support elements */
#define THERMAL_GENL_FAMILY_NAME "thermal_event"
@@ -163,6 +186,12 @@
const struct thermal_cooling_device_ops *);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+int sensor_get_id(char *name);
+int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
+int thermal_sensor_trip(struct thermal_zone_device *tz,
+ enum thermal_trip_type trip, unsigned long temp);
+
#ifdef CONFIG_NET
extern int thermal_generate_netlink_event(u32 orig, enum events event);
#else
diff --git a/kernel/exit.c b/kernel/exit.c
index f01ca74..6096e80 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -880,7 +880,6 @@
static DEFINE_SPINLOCK(low_water_lock);
static int lowest_to_date = THREAD_SIZE;
unsigned long free;
- int islower = false;
free = stack_not_used(current);
@@ -889,16 +888,12 @@
spin_lock(&low_water_lock);
if (free < lowest_to_date) {
- lowest_to_date = free;
- islower = true;
- }
- spin_unlock(&low_water_lock);
-
- if (islower) {
printk(KERN_WARNING "%s used greatest stack depth: %lu bytes "
"left\n",
current->comm, free);
+ lowest_to_date = free;
}
+ spin_unlock(&low_water_lock);
}
#else
static inline void check_stack_usage(void) {}
diff --git a/sound/soc/codecs/wcd9306.c b/sound/soc/codecs/wcd9306.c
index af2c53e..fcc264c 100644
--- a/sound/soc/codecs/wcd9306.c
+++ b/sound/soc/codecs/wcd9306.c
@@ -24,6 +24,7 @@
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9xxx/wcd9306_registers.h>
#include <linux/mfd/wcd9xxx/pdata.h>
+#include <linux/regulator/consumer.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
@@ -189,6 +190,12 @@
0, /* AIF1_CAP */
};
+enum {
+ CP_REG_BUCK = 0,
+ CP_REG_BHELPER,
+ CP_REG_MAX,
+};
+
struct tapan_priv {
struct snd_soc_codec *codec;
u32 adc_count;
@@ -224,6 +231,9 @@
/* class h specific data */
struct wcd9xxx_clsh_cdc_data clsh_d;
+
+ /* pointers to regulators required for chargepump */
+ struct regulator *cp_regulators[CP_REG_MAX];
};
static const u32 comp_shift[] = {
@@ -758,6 +768,9 @@
int i;
for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
+ if (pdata->regulator[i].name == NULL)
+ continue;
+
if (!strncmp(pdata->regulator[i].name,
WCD9XXX_SUPPLY_BUCK_NAME,
sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
@@ -768,8 +781,13 @@
buck_volt = pdata->regulator[i].min_uV;
break;
}
+ dev_err(codec->dev,
+ "%s: Failed to find regulator for %s\n",
+ __func__, WCD9XXX_SUPPLY_BUCK_NAME);
}
- pr_debug("%s: S4 voltage requested is %d\n", __func__, buck_volt);
+ dev_dbg(codec->dev,
+ "%s: S4 voltage requested is %d\n",
+ __func__, buck_volt);
return buck_volt;
}
@@ -2563,6 +2581,8 @@
{"EAR PA", NULL, "EAR_PA_MIXER"},
{"EAR_PA_MIXER", NULL, "DAC1"},
{"DAC1", NULL, "RX_BIAS"},
+ {"DAC1", NULL, "CDC_CP_VDD"},
+
{"ANC EAR", NULL, "ANC EAR PA"},
{"ANC EAR PA", NULL, "EAR_PA_MIXER"},
@@ -2576,10 +2596,12 @@
{"HPHL", NULL, "HPHL_PA_MIXER"},
{"HPHL_PA_MIXER", NULL, "HPHL DAC"},
{"HPHL DAC", NULL, "RX_BIAS"},
+ {"HPHL DAC", NULL, "CDC_CP_VDD"},
{"HPHR", NULL, "HPHR_PA_MIXER"},
{"HPHR_PA_MIXER", NULL, "HPHR DAC"},
{"HPHR DAC", NULL, "RX_BIAS"},
+ {"HPHR DAC", NULL, "CDC_CP_VDD"},
{"ANC HEADPHONE", NULL, "ANC HPHL"},
{"ANC HEADPHONE", NULL, "ANC HPHR"},
@@ -2641,6 +2663,8 @@
{"LINEOUT1 DAC", NULL, "RX_BIAS"},
{"LINEOUT2 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT1 DAC", NULL, "CDC_CP_VDD"},
+ {"LINEOUT2 DAC", NULL, "CDC_CP_VDD"},
{"RX1 MIX1", NULL, "COMP1_CLK"},
{"RX2 MIX1", NULL, "COMP1_CLK"},
@@ -3766,6 +3790,59 @@
return ret;
}
+static int tapan_codec_chargepump_vdd_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
+ int ret = 0, i;
+
+ pr_info("%s: event = %d\n", __func__, event);
+
+
+ if (!priv->cp_regulators[CP_REG_BUCK]
+ && !priv->cp_regulators[CP_REG_BHELPER]) {
+ pr_err("%s: No power supply defined for ChargePump\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ for (i = 0; i < CP_REG_MAX ; i++) {
+ if (!priv->cp_regulators[i])
+ continue;
+
+ ret = regulator_enable(priv->cp_regulators[i]);
+ if (ret) {
+ pr_err("%s: CP Regulator enable failed, index = %d\n",
+ __func__, i);
+ continue;
+ } else {
+ pr_debug("%s: Enabled CP regulator, index %d\n",
+ __func__, i);
+ }
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ for (i = 0; i < CP_REG_MAX; i++) {
+ if (!priv->cp_regulators[i])
+ continue;
+
+ ret = regulator_disable(priv->cp_regulators[i]);
+ if (ret) {
+ pr_err("%s: CP Regulator disable failed, index = %d\n",
+ __func__, i);
+ return ret;
+ } else {
+ pr_debug("%s: Disabled CP regulator %d\n",
+ __func__, i);
+ }
+ }
+ break;
+ }
+ return 0;
+}
/* Todo: Have seperate dapm widgets for I2S and Slimbus.
* Might Need to have callbacks registered only for slimbus
@@ -3882,6 +3959,11 @@
tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
+ /* CDC_CP_VDD */
+ SND_SOC_DAPM_SUPPLY("CDC_CP_VDD", SND_SOC_NOPM, 0, 0,
+ tapan_codec_chargepump_vdd_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
/*EAR */
SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
@@ -4710,6 +4792,21 @@
return 0;
}
+static struct regulator *tapan_codec_find_regulator(
+ struct snd_soc_codec *codec,
+ const char *name)
+{
+ int i;
+ struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
+
+ for (i = 0; i < core->num_of_supplies; i++) {
+ if (core->supplies[i].supply &&
+ !strcmp(core->supplies[i].supply, name))
+ return core->supplies[i].consumer;
+ }
+ return NULL;
+}
+
static int tapan_codec_probe(struct snd_soc_codec *codec)
{
struct wcd9xxx *control;
@@ -4752,6 +4849,11 @@
return ret;
}
+ tapan->cp_regulators[CP_REG_BUCK] = tapan_codec_find_regulator(codec,
+ WCD9XXX_SUPPLY_BUCK_NAME);
+ tapan->cp_regulators[CP_REG_BHELPER] = tapan_codec_find_regulator(codec,
+ "cdc-vdd-buckhelper");
+
tapan->clsh_d.buck_mv = tapan_codec_get_buck_mv(codec);
/*
* If 1.8 volts is requested on the vdd_cp line, then
@@ -4860,6 +4962,7 @@
static int tapan_codec_remove(struct snd_soc_codec *codec)
{
struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
+ int index = 0;
WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
atomic_set(&kp_tapan_priv, 0);
@@ -4876,6 +4979,9 @@
/* cleanup resmgr */
wcd9xxx_resmgr_deinit(&tapan->resmgr);
+ for (index = 0; index < CP_REG_MAX; index++)
+ tapan->cp_regulators[index] = NULL;
+
kfree(tapan);
return 0;
}
diff --git a/sound/soc/msm/msm8x10.c b/sound/soc/msm/msm8x10.c
index b49b1e3..e1f1efc 100644
--- a/sound/soc/msm/msm8x10.c
+++ b/sound/soc/msm/msm8x10.c
@@ -52,6 +52,9 @@
static void __iomem *pcbcr;
static void __iomem *prcgr;
+static int msm_sec_mi2s_rx_ch = 1;
+static int msm_pri_mi2s_tx_ch = 1;
+
/*
* There is limitation for the clock root selection from
* either MI2S or DIG_CODEC.
@@ -182,10 +185,43 @@
return 0;
}
+static int msm_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s(): channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_sec_mi2s_rx_ch;
+
+ return 0;
+}
+
+static int msm_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ pr_debug("%s(), channel:%d\n", __func__, msm_pri_mi2s_tx_ch);
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = msm_pri_mi2s_tx_ch;
+
+ return 0;
+}
+
+
static const char *const btsco_rate_text[] = {"8000", "16000"};
static const struct soc_enum msm_btsco_enum[] = {
SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
};
+static const char *const sec_mi2s_rx_ch_text[] = {"One", "Two"};
+static const char *const pri_mi2s_tx_ch_text[] = {"One", "Two"};
static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -215,6 +251,43 @@
return 0;
}
+static int msm_sec_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_sec_mi2s_rx_ch = %d\n", __func__,
+ msm_sec_mi2s_rx_ch);
+ ucontrol->value.integer.value[0] = msm_sec_mi2s_rx_ch - 1;
+ return 0;
+}
+
+static int msm_sec_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_sec_mi2s_rx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_sec_mi2s_rx_ch = %d\n", __func__,
+ msm_sec_mi2s_rx_ch);
+ return 1;
+}
+
+static int msm_pri_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ pr_debug("%s: msm_pri_mi2s_tx_ch = %d\n", __func__,
+ msm_pri_mi2s_tx_ch);
+ ucontrol->value.integer.value[0] = msm_pri_mi2s_tx_ch - 1;
+ return 0;
+}
+
+static int msm_pri_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ msm_pri_mi2s_tx_ch = ucontrol->value.integer.value[0] + 1;
+
+ pr_debug("%s: msm_pri_mi2s_tx_ch = %d\n", __func__, msm_pri_mi2s_tx_ch);
+ return 1;
+}
+
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -353,9 +426,18 @@
return ret;
}
+static const struct soc_enum msm_snd_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, sec_mi2s_rx_ch_text),
+ SOC_ENUM_SINGLE_EXT(2, pri_mi2s_tx_ch_text),
+};
+
static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
msm_btsco_rate_get, msm_btsco_rate_put),
+ SOC_ENUM_EXT("MI2S_RX Channels", msm_snd_enum[0],
+ msm_sec_mi2s_rx_ch_get, msm_sec_mi2s_rx_ch_put),
+ SOC_ENUM_EXT("MI2S_TX Channels", msm_snd_enum[1],
+ msm_pri_mi2s_tx_ch_get, msm_pri_mi2s_tx_ch_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -637,7 +719,7 @@
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX,
.init = &msm_audrx_init,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_rx_be_hw_params_fixup,
.ops = &msm8x10_mi2s_be_ops,
.ignore_suspend = 1,
},
@@ -650,7 +732,7 @@
.codec_dai_name = "msm8x10_wcd_i2s_tx1",
.no_pcm = 1,
.be_id = MSM_BACKEND_DAI_PRI_MI2S_TX,
- .be_hw_params_fixup = msm_be_hw_params_fixup,
+ .be_hw_params_fixup = msm_tx_be_hw_params_fixup,
.ops = &msm8x10_mi2s_be_ops,
.ignore_suspend = 1,
},