Merge "msm8974: mhl_sii8334: init chip on discovery"
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/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/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.dts
index f3470c2..5e533ee 100644
--- a/arch/arm/boot/dts/msm8610-cdp.dts
+++ b/arch/arm/boot/dts/msm8610-cdp.dts
@@ -52,7 +52,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 +60,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 +143,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-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 2041bf6..98a99a7 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -16,6 +16,8 @@
reg = <0xfc326000 0x1000>,
<0xfc37c000 0x3000>;
reg-names = "tmc-base", "bam-base";
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
qcom,memory-reservation-type = "EBI1";
qcom,memory-reservation-size = <0x100000>; /* 1M EBI1 buffer */
diff --git a/arch/arm/boot/dts/msm8610-mtp.dts b/arch/arm/boot/dts/msm8610-mtp.dts
index 0d4c174..a70f8dc 100644
--- a/arch/arm/boot/dts/msm8610-mtp.dts
+++ b/arch/arm/boot/dts/msm8610-mtp.dts
@@ -52,7 +52,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 +60,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 +181,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..b1ec4fe 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -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-skuaa.dts b/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
index aeaf8ca..e220e6f 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
+++ b/arch/arm/boot/dts/msm8610-qrd-skuaa.dts
@@ -45,3 +45,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-qrd-skuab.dts
index 947a312..2948dec 100644
--- a/arch/arm/boot/dts/msm8610-qrd-skuab.dts
+++ b/arch/arm/boot/dts/msm8610-qrd-skuab.dts
@@ -80,7 +80,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-qrd.dtsi b/arch/arm/boot/dts/msm8610-qrd.dtsi
index bd1705f..d1bf471 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8610-qrd.dtsi
@@ -344,3 +344,10 @@
mpp@a300 { /* MPP 4 */
};
};
+
+&pm8110_vadc {
+ chan@30 {
+ label = "batt_therm";
+ qcom,scale-function = <6>;
+ };
+};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index c6104bf..b943932 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -929,10 +929,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 b9d37b8..b8dc0d7b 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -69,10 +69,9 @@
CONFIG_MSM_OCMEM_NONSECURE=y
CONFIG_MSM_OCMEM_POWER_DISABLE=y
CONFIG_SENSORS_ADSP=y
-CONFIG_MSM_RTB=y
-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/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/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/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/diagchar.h b/drivers/char/diag/diagchar.h
index 7ef1d80..c341ef5 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -412,5 +412,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/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index c501700..d500c0a 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -1451,14 +1451,17 @@
if (!drvdata->byte_cntr_present) {
dev_info(&pdev->dev, "Byte Counter feature absent\n");
- return 0;
+ goto out;
}
drvdata->byte_cntr_irq = platform_get_irq_byname(pdev,
"byte-cntr-irq");
if (drvdata->byte_cntr_irq < 0) {
+ /* Even though this is an error condition, we do not fail
+ * the probe as the byte counter feature is optional
+ */
dev_err(&pdev->dev, "Byte-cntr-irq not specified\n");
- return 0;
+ goto err;
}
ret = devm_request_irq(&pdev->dev, drvdata->byte_cntr_irq,
tmc_etr_byte_cntr_irq,
@@ -1466,7 +1469,7 @@
node_name, drvdata);
if (ret) {
dev_err(&pdev->dev, "Request irq failed\n");
- return ret;
+ goto err;
}
init_waitqueue_head(&drvdata->wq);
node_size += strlen(node_name);
@@ -1477,10 +1480,14 @@
ret = tmc_etr_byte_cntr_dev_register(drvdata);
if (ret) {
dev_err(&pdev->dev, "Byte cntr node not registered\n");
- return ret;
+ goto err;
}
dev_info(&pdev->dev, "Byte Counter feature enabled\n");
return 0;
+err:
+ drvdata->byte_cntr_present = false;
+out:
+ return ret;
}
static void tmc_etr_byte_cntr_exit(struct tmc_drvdata *drvdata)
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/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index fdd19e9..2781a34 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -2771,7 +2771,7 @@
} kgsl_ioctl_funcs[] = {
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
kgsl_ioctl_device_getproperty,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
kgsl_ioctl_device_waittimestamp,
KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -2789,13 +2789,13 @@
KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,
kgsl_ioctl_cmdstream_freememontimestamp,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
kgsl_ioctl_cmdstream_freememontimestamp_ctxtid,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
kgsl_ioctl_drawctxt_create,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
kgsl_ioctl_drawctxt_destroy,
KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
@@ -2815,10 +2815,10 @@
kgsl_ioctl_cff_user_event, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
kgsl_ioctl_timestamp_event,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
kgsl_ioctl_device_setproperty,
- KGSL_IOCTL_LOCK | KGSL_IOCTL_WAKE),
+ KGSL_IOCTL_LOCK),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
kgsl_ioctl_gpumem_alloc_id, 0),
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
diff --git a/drivers/gpu/msm/kgsl_events.c b/drivers/gpu/msm/kgsl_events.c
index e4f502a..9e8f6d0 100644
--- a/drivers/gpu/msm/kgsl_events.c
+++ b/drivers/gpu/msm/kgsl_events.c
@@ -252,7 +252,7 @@
* Increase the active count on the device to avoid going into power
* saving modes while events are pending
*/
- ret = kgsl_active_count_get_light(device);
+ ret = kgsl_active_count_get(device);
if (ret < 0) {
kgsl_context_put(context);
kfree(event);
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/q6_hfi.c b/drivers/media/platform/msm/vidc/q6_hfi.c
index bc3b93d..44c9613 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.c
+++ b/drivers/media/platform/msm/vidc/q6_hfi.c
@@ -381,7 +381,7 @@
}
static inline void q6_hfi_add_apr_hdr(struct q6_hfi_device *dev,
- struct apr_hdr *hdr, u32 pkt_size, u32 opcode)
+ struct apr_hdr *hdr, u32 pkt_size)
{
hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
APR_HDR_LEN(sizeof(struct apr_hdr)),
@@ -394,7 +394,7 @@
hdr->dest_port = 0;
hdr->pkt_size = pkt_size;
hdr->token = 0;
- hdr->opcode = opcode;
+ hdr->opcode = VIDEO_HFI_CMD_ID;
}
static int q6_hfi_apr_callback(struct apr_client_data *data, void *priv)
@@ -496,7 +496,7 @@
goto err_core_init;
}
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), HFI_CMD_SYS_INIT);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_sys_init(&apr.pkt, HFI_VIDEO_ARCH_OX);
if (rc) {
@@ -529,22 +529,6 @@
return 0;
}
-static int q6_hfi_core_pc_prep(void *device)
-{
- (void) device;
-
- /* Q6 does not support core_pc_prep*/
- return 0;
-}
-
-static int q6_hfi_core_ping(void *device)
-{
- (void) device;
-
- /* Q6 does not support cmd_sys_ping */
- return 0;
-}
-
static void *q6_hfi_session_init(void *device, u32 session_id,
enum hal_domain session_type, enum hal_video_codec codec_type)
{
@@ -567,8 +551,7 @@
new_session->is_decoder = 1;
new_session->device = dev;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SYS_SESSION_INIT);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
if (create_pkt_cmd_sys_session_init(&apr.pkt, (u32)new_session,
session_type, codec_type)) {
@@ -605,7 +588,7 @@
}
dev = session->device;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr), pkt_type);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_cmd(&apr.pkt, pkt_type, (u32)session);
if (rc) {
@@ -670,8 +653,7 @@
return 0;
apr = (struct q6_apr_cmd_session_set_buffers_packet *)packet;
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
- HFI_CMD_SESSION_SET_BUFFERS);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
rc = create_pkt_cmd_session_set_buffers(&apr->pkt,
(u32)session, buffer_info);
@@ -713,8 +695,7 @@
apr = (struct q6_apr_cmd_session_release_buffer_packet *) packet;
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
- HFI_CMD_SESSION_RELEASE_BUFFERS);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
rc = create_pkt_cmd_session_release_buffers(&apr->pkt,
(u32)session, buffer_info);
@@ -788,8 +769,7 @@
if (session->is_decoder) {
struct q6_apr_cmd_session_empty_buffer_compressed_packet apr;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_EMPTY_BUFFER);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_etb_decoder(&apr.pkt,
(u32)session, input_frame);
@@ -811,8 +791,7 @@
} else {
struct
q6_apr_cmd_session_empty_buffer_uncompressed_plane0_packet apr;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_EMPTY_BUFFER);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_etb_encoder(&apr.pkt,
(u32)session, input_frame);
@@ -848,8 +827,7 @@
}
dev = session->device;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_FILL_BUFFER);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_ftb(&apr.pkt, (u32)session, output_frame);
if (rc) {
@@ -886,8 +864,7 @@
apr = (struct q6_apr_cmd_session_parse_sequence_header_packet *) packet;
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE,
- HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
rc = create_pkt_cmd_session_parse_seq_header(&apr->pkt,
(u32)session, seq_hdr);
@@ -925,8 +902,7 @@
apr = (struct q6_apr_cmd_session_get_sequence_header_packet *) packet;
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE,
- HFI_CMD_SESSION_GET_SEQUENCE_HEADER);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_SMALL_PKT_SIZE);
rc = create_pkt_cmd_session_get_seq_hdr(&apr->pkt, (u32)session,
seq_hdr);
@@ -960,8 +936,7 @@
}
dev = session->device;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_GET_PROPERTY);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_get_buf_req(&apr.pkt, (u32)session);
if (rc) {
@@ -993,8 +968,7 @@
}
dev = session->device;
- q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr),
- HFI_CMD_SESSION_FLUSH);
+ q6_hfi_add_apr_hdr(dev, &apr.hdr, sizeof(apr));
rc = create_pkt_cmd_session_flush(&apr.pkt, (u32)session, flush_mode);
if (rc) {
@@ -1031,8 +1005,7 @@
dev = session->device;
dprintk(VIDC_DBG, "in set_prop,with prop id: 0x%x", ptype);
- q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE,
- HFI_CMD_SESSION_SET_PROPERTY);
+ q6_hfi_add_apr_hdr(dev, &apr->hdr, VIDC_IFACEQ_VAR_LARGE_PKT_SIZE);
rc = create_pkt_cmd_session_set_property(&apr->pkt,
(u32)session, ptype, pdata);
@@ -1177,28 +1150,6 @@
return 0;
}
-static int q6_hfi_scale_clocks(void *dev, int load)
-{
- (void)dev;
- (void)load;
-
- /* Q6 does not support clocks scaling */
- return 0;
-}
-
-static int q6_hfi_scale_bus(void *dev, int load,
- enum session_type type, enum mem_type mtype)
-{
- (void)dev;
- (void)load;
- (void)type;
- (void)mtype;
-
- /* Q6 does not support bus scaling */
- return 0;
-
-}
-
static int q6_hfi_unset_ocmem(void *dev)
{
(void)dev;
@@ -1207,23 +1158,6 @@
return -EINVAL;
}
-static int q6_hfi_alloc_ocmem(void *dev, unsigned long size)
-{
- (void)dev;
- (void)size;
-
- /* Q6 does not support ocmem */
- return 0;
-}
-
-static int q6_hfi_free_ocmem(void *dev)
-{
- (void)dev;
-
- /* Q6 does not support ocmem */
- return 0;
-}
-
static int q6_hfi_iommu_get_domain_partition(void *dev, u32 flags,
u32 buffer_type, int *domain, int *partition)
{
@@ -1373,14 +1307,6 @@
}
}
-static int q6_hfi_get_fw_info(void *dev, enum fw_info info)
-{
- (void)dev;
- (void)info;
-
- return 0;
-}
-
static int q6_hfi_get_stride_scanline(int color_fmt,
int width, int height, int *stride, int *scanlines) {
*stride = VENUS_Y_STRIDE(color_fmt, width);
@@ -1392,8 +1318,6 @@
{
hdev->core_init = q6_hfi_core_init;
hdev->core_release = q6_hfi_core_release;
- hdev->core_pc_prep = q6_hfi_core_pc_prep;
- hdev->core_ping = q6_hfi_core_ping;
hdev->session_init = q6_hfi_session_init;
hdev->session_end = q6_hfi_session_end;
hdev->session_abort = q6_hfi_session_abort;
@@ -1414,15 +1338,10 @@
hdev->session_flush = q6_hfi_session_flush;
hdev->session_set_property = q6_hfi_session_set_property;
hdev->session_get_property = q6_hfi_session_get_property;
- hdev->scale_clocks = q6_hfi_scale_clocks;
- hdev->scale_bus = q6_hfi_scale_bus;
hdev->unset_ocmem = q6_hfi_unset_ocmem;
- hdev->alloc_ocmem = q6_hfi_alloc_ocmem;
- hdev->free_ocmem = q6_hfi_free_ocmem;
hdev->iommu_get_domain_partition = q6_hfi_iommu_get_domain_partition;
hdev->load_fw = q6_hfi_load_fw;
hdev->unload_fw = q6_hfi_unload_fw;
- hdev->get_fw_info = q6_hfi_get_fw_info;
hdev->get_stride_scanline = q6_hfi_get_stride_scanline;
}
diff --git a/drivers/media/platform/msm/vidc/q6_hfi.h b/drivers/media/platform/msm/vidc/q6_hfi.h
index 3dc4607..67aed5a 100644
--- a/drivers/media/platform/msm/vidc/q6_hfi.h
+++ b/drivers/media/platform/msm/vidc/q6_hfi.h
@@ -20,6 +20,15 @@
#define Q6_IFACEQ_QUEUE_SIZE (8 * 1024)
+/* client to Q6 communication path : forward path */
+#define VIDEO_HFI_CMD_ID 0x00012ECC
+
+/* Q6 to client ACK msg: reverse path*/
+#define VIDEO_HFI_MSG_ID 0x00012ECD
+
+/* Q6 to client event notifications */
+#define VIDEO_HFI_EVT_ID 0x00012ECE
+
struct q6_resources {
struct msm_vidc_fw fw;
};
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/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/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..44dd3c5 100644
--- a/drivers/usb/gadget/f_qdss.c
+++ b/drivers/usb/gadget/f_qdss.c
@@ -463,6 +463,11 @@
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);
@@ -521,6 +526,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;
}
diff --git a/drivers/video/msm/mdss/dsi_host_v2.c b/drivers/video/msm/mdss/dsi_host_v2.c
index f2de17d..7f731d2 100644
--- a/drivers/video/msm/mdss/dsi_host_v2.c
+++ b/drivers/video/msm/mdss/dsi_host_v2.c
@@ -320,7 +320,7 @@
wmb();
}
-void msm_dsi_set_tx_power_mode(int mode)
+void dsi_set_tx_power_mode(int mode)
{
u32 data;
unsigned char *ctrl_base = dsi_host_private->dsi_base;
diff --git a/drivers/video/msm/mdss/dsi_panel_v2.c b/drivers/video/msm/mdss/dsi_panel_v2.c
index 022d911..b1a4293 100644
--- a/drivers/video/msm/mdss/dsi_panel_v2.c
+++ b/drivers/video/msm/mdss/dsi_panel_v2.c
@@ -143,6 +143,29 @@
return 0;
}
+static char led_pwm1[2] = {0x51, 0x0}; /* DTYPE_DCS_WRITE1 */
+static struct dsi_cmd_desc backlight_cmd = {
+ DTYPE_DCS_WRITE1, 1, 0, 0, 1, sizeof(led_pwm1), led_pwm1};
+
+static void dsi_panel_bklt_dcs(struct mdss_panel_data *pdata, int level)
+{
+ struct mipi_panel_info *mipi;
+
+ mipi = &pdata->panel_info.mipi;
+
+ pr_debug("%s: dcs level=%d\n", __func__, level);
+
+ led_pwm1[1] = (unsigned char)level;
+
+ if (DSI_VIDEO_MODE == mipi->mode) {
+ dsi_set_tx_power_mode(0);
+ dsi_cmds_tx_v2(pdata, &panel_private->dsi_panel_tx_buf,
+ &backlight_cmd,
+ 1);
+ dsi_set_tx_power_mode(1);
+ }
+}
+
void dsi_panel_reset(struct mdss_panel_data *pdata, int enable)
{
if (pdata == NULL) {
@@ -166,13 +189,21 @@
if (enable == 2) {
dsi_panel_power(1);
gpio_request(panel_private->rst_gpio, "panel_reset");
+ gpio_set_value(panel_private->rst_gpio, 1);
if (gpio_is_valid(panel_private->disp_en_gpio)) {
gpio_request(panel_private->disp_en_gpio,
"panel_enable");
+ gpio_set_value(panel_private->disp_en_gpio, 1);
}
if (gpio_is_valid(panel_private->video_mode_gpio)) {
gpio_request(panel_private->video_mode_gpio,
"panel_video_mdoe");
+ if (pdata->panel_info.mipi.mode == DSI_VIDEO_MODE)
+ gpio_set_value(panel_private->video_mode_gpio,
+ 1);
+ else
+ gpio_set_value(panel_private->video_mode_gpio,
+ 0);
}
if (gpio_is_valid(panel_private->te_gpio))
gpio_request(panel_private->te_gpio, "panel_te");
@@ -233,6 +264,10 @@
led_trigger_event(bl_led_trigger, bl_level);
break;
+ case BL_DCS_CMD:
+ dsi_panel_bklt_dcs(pdata, bl_level);
+ break;
+
default:
pr_err("%s: Unknown bl_ctrl configuration\n",
__func__);
@@ -605,8 +640,11 @@
led_trigger_register_simple("bkl-trigger", &bl_led_trigger);
pr_debug("%s: SUCCESS-> WLED TRIGGER register\n", __func__);
*bl_ctrl = BL_WLED;
+ } else if ((bl_ctrl_type) && (!strncmp(bl_ctrl_type,
+ "bl_ctrl_dcs", 11))) {
+ pr_debug("%s: SUCCESS-> DCS COMMAND register\n", __func__);
+ *bl_ctrl = BL_DCS_CMD;
}
-
rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,mdss-pan-bl-levels", res, 2);
panel_data->panel_info.bl_min = (!rc ? res[0] : 0);
@@ -620,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);
@@ -641,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/dsi_v2.h b/drivers/video/msm/mdss/dsi_v2.h
index 96dd390..73df790 100644
--- a/drivers/video/msm/mdss/dsi_v2.h
+++ b/drivers/video/msm/mdss/dsi_v2.h
@@ -235,4 +235,6 @@
int dsi_long_read_resp(struct dsi_buf *rp);
+void dsi_set_tx_power_mode(int mode);
+
#endif /* MDSS_DSI_H */
diff --git a/drivers/video/msm/mdss/mdp3.c b/drivers/video/msm/mdss/mdp3.c
index f6f722e..e899fa3 100644
--- a/drivers/video/msm/mdss/mdp3.c
+++ b/drivers/video/msm/mdss/mdp3.c
@@ -1173,6 +1173,11 @@
size_t size;
int rc;
+ if (pdata->panel_info.type != MIPI_VIDEO_PANEL) {
+ pr_debug("cmd mode panel, no need to copy splash image\n");
+ return 0;
+ }
+
rgb_size = MDP3_REG_READ(MDP3_REG_DMA_P_SIZE);
stride = MDP3_REG_READ(MDP3_REG_DMA_P_IBUF_Y_STRIDE);
stride = stride & 0x3FFF;
@@ -1210,8 +1215,8 @@
status = MDP3_REG_READ(MDP3_REG_DSI_VIDEO_EN);
rc = status & 0x1;
} else {
- status = MDP3_REG_READ(MDP3_REG_DMA_P_START);
- rc = status & 01;
+ status = MDP3_REG_READ(MDP3_REG_DMA_P_CONFIG);
+ rc = status & 0x80000;
}
mdp3_clk_update(MDP3_CLK_AHB, 0);
@@ -1285,7 +1290,13 @@
return 0;
}
rc = mdp3_continuous_splash_on(pdata);
+ } else {
+ if (mdp3_is_display_on(pdata)) {
+ pr_err("lk continuous splash, but kerenl not\n");
+ rc = mdp3_continuous_splash_on(pdata);
+ }
}
+
return rc;
}
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index f77a2b3..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)
@@ -370,6 +361,14 @@
struct mdp3_dma_output_config outputConfig;
struct mdp3_dma_source sourceConfig;
int frame_rate = mfd->panel_info->mipi.frame_rate;
+ int vbp, vfp, vspw;
+ int vtotal, vporch;
+
+ vbp = panel_info->lcdc.v_back_porch;
+ vfp = panel_info->lcdc.v_front_porch;
+ vspw = panel_info->lcdc.v_pulse_width;
+ vporch = vbp + vfp + vspw;
+ vtotal = vporch + panel_info->yres;
fix = &fbi->fix;
var = &fbi->var;
@@ -381,8 +380,9 @@
sourceConfig.y = 0;
sourceConfig.stride = fix->line_length;
sourceConfig.buf = (void *)mfd->iova;
+ sourceConfig.vporch = vporch;
sourceConfig.vsync_count =
- MDP_VSYNC_CLK_RATE / (frame_rate * sourceConfig.width);
+ MDP_VSYNC_CLK_RATE / (frame_rate * vtotal);
outputConfig.dither_en = 0;
outputConfig.out_sel = mdp3_ctrl_get_intf_type(mfd);
@@ -475,9 +475,6 @@
mdp3_fbmem_clear();
- if (panel->set_backlight)
- panel->set_backlight(panel, panel->panel_info.bl_max);
-
pr_debug("mdp3_ctrl_on dma start\n");
if (mfd->fbi->screen_base) {
rc = mdp3_session->dma->start(mdp3_session->dma,
@@ -520,18 +517,16 @@
mdp3_histogram_stop(mdp3_session, MDP_BLOCK_DMA_P);
- pr_debug("mdp3_ctrl_off turn panel off\n");
- if (panel->set_backlight)
- panel->set_backlight(panel, 0);
+ rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
+ if (rc)
+ pr_debug("fail to stop the MDP3 dma\n");
if (panel->event_handler)
rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, NULL);
if (rc)
pr_err("fail to turn off the panel\n");
- rc = mdp3_session->dma->stop(mdp3_session->dma, mdp3_session->intf);
- if (rc)
- pr_err("fail to stop the MDP3 dma\n");
+
mdp3_irq_deregister();
@@ -789,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)
{
@@ -796,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) {
@@ -1000,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;
@@ -1235,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) {
@@ -1261,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;
@@ -1282,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 88eedb9..f4421f2 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -247,16 +247,22 @@
pr_debug("mdp3_dma_sync_config\n");
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
- sync_config = (source_config->height - 1) << 21;
+ int porch = source_config->vporch;
+ int height = source_config->height;
+ int vtotal = height + porch;
+ sync_config = vtotal << 21;
sync_config |= source_config->vsync_count;
sync_config |= BIT(19);
sync_config |= BIT(20);
MDP3_REG_WRITE(MDP3_REG_SYNC_CONFIG_0 + dma_sel, sync_config);
MDP3_REG_WRITE(MDP3_REG_VSYNC_SEL, 0x024);
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel, 0);
- MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, 0x00100000);
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, 0x0);
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_VSYNC_INIT_VAL + dma_sel,
+ height);
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x5);
+ MDP3_REG_WRITE(MDP3_REG_SYNC_THRESH_0 + dma_sel, (4 << 16 | 2));
+ MDP3_REG_WRITE(MDP3_REG_PRIMARY_START_P0S + dma_sel, porch);
+ MDP3_REG_WRITE(MDP3_REG_TEAR_CHECK_EN, 0x1);
}
return 0;
}
@@ -291,7 +297,7 @@
* the default 16 for MDP hang issue workaround
*/
MDP3_REG_WRITE(MDP3_REG_DMA_P_FETCH_CFG, 0x20);
- MDP3_REG_WRITE(MDP3_REG_PRIMARY_RD_PTR_IRQ, 0x10);
+
dma->source_config = *source_config;
dma->output_config = *output_config;
@@ -497,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;
@@ -530,7 +536,7 @@
pr_debug("mdp3_dmap_update\n");
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
- cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+ cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
if (intf->active)
wait_for_completion_killable(&dma->dma_comp);
}
@@ -553,7 +559,8 @@
mdp3_dma_callback_enable(dma, cb_type);
pr_debug("mdp3_dmap_update wait for vsync_comp in\n");
- wait_for_completion_killable(&dma->vsync_comp);
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+ wait_for_completion_killable(&dma->vsync_comp);
pr_debug("mdp3_dmap_update wait for vsync_comp out\n");
return 0;
}
@@ -565,7 +572,7 @@
int cb_type = MDP3_DMA_CALLBACK_TYPE_VSYNC;
if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD) {
- cb_type |= MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
+ cb_type = MDP3_DMA_CALLBACK_TYPE_DMA_DONE;
if (intf->active)
wait_for_completion_killable(&dma->dma_comp);
}
@@ -586,7 +593,8 @@
spin_unlock_irqrestore(&dma->dma_lock, flag);
mdp3_dma_callback_enable(dma, cb_type);
- wait_for_completion_killable(&dma->vsync_comp);
+ if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_VIDEO)
+ wait_for_completion_killable(&dma->vsync_comp);
return 0;
}
@@ -631,7 +639,7 @@
return ret;
if (dma->histo_state != MDP3_DMA_HISTO_STATE_READY) {
- pr_err("mdp3_dmap_histo_get after dma shut down\n");
+ pr_debug("mdp3_dmap_histo_get after dma shut down\n");
return -EPERM;
}
@@ -694,9 +702,6 @@
unsigned long flag;
int ret;
- if (dma->histo_state == MDP3_DMA_HISTO_STATE_START)
- return -EINVAL;
-
spin_lock_irqsave(&dma->histo_lock, flag);
init_completion(&dma->histo_comp);
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index e4a28dc..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
@@ -145,6 +151,7 @@
void *buf;
int stride;
int vsync_count;
+ int vporch;
};
struct mdp3_dma_output_config {
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..9c4e43a 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -364,6 +364,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 +377,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_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/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/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 170dbe7..66b0094 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -126,6 +126,16 @@
ON_DEMAND_SUPPLIES_MAX,
};
+/*
+ * The delay list is per codec HW specification.
+ * Please add delay in the list in the future instead
+ * of magic number
+ */
+enum {
+ CODEC_DELAY_1_MS = 1000,
+ CODEC_DELAY_1_1_MS = 1100,
+};
+
struct hpf_work {
struct msm8x10_wcd_priv *msm8x10_wcd;
u32 decimator;
@@ -1148,13 +1158,8 @@
"ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
};
-static const char * const anc_mux_text[] = {
- "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
- "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
-};
-
-static const char * const anc1_fb_mux_text[] = {
- "ZERO", "EAR_HPH_L", "EAR_LINE_1",
+static const char * const adc2_mux_text[] = {
+ "ZERO", "INP2", "INP3"
};
static const char * const iir1_inp1_text[] = {
@@ -1212,6 +1217,9 @@
SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
rx_rdac4_text);
+static const struct soc_enum adc2_enum =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
+
static const struct snd_kcontrol_new rx_mix1_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
@@ -1242,6 +1250,9 @@
static const struct snd_kcontrol_new rx_dac4_mux =
SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
+static const struct snd_kcontrol_new tx_adc2_mux =
+ SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
+
static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -1370,7 +1381,8 @@
if (w->reg == MSM8X10_WCD_A_TX_1_EN)
init_bit_shift = 7;
- else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
+ else if ((w->reg == MSM8X10_WCD_A_TX_2_EN) ||
+ (w->reg == MSM8X10_WCD_A_TX_3_EN))
init_bit_shift = 6;
else {
dev_err(codec->dev, "%s: Error, invalid adc register\n",
@@ -1383,9 +1395,11 @@
msm8x10_wcd_codec_enable_adc_block(codec, 1);
snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1 << init_bit_shift);
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
break;
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
+ usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
break;
case SND_SOC_DAPM_POST_PMD:
msm8x10_wcd_codec_enable_adc_block(codec, 0);
@@ -1930,9 +1944,14 @@
{"DEC2 MUX", "ADC2", "ADC2"},
{"DEC2 MUX", NULL, "CDC_CONN"},
+ {"ADC2", NULL, "ADC2 MUX"},
+ {"ADC2 MUX", "INP2", "ADC2_INP2"},
+ {"ADC2 MUX", "INP3", "ADC2_INP3"},
+
/* ADC Connections */
{"ADC1", NULL, "AMIC1"},
- {"ADC2", NULL, "AMIC2"},
+ {"ADC2_INP2", NULL, "AMIC2"},
+ {"ADC2_INP3", NULL, "AMIC3"},
{"IIR1", NULL, "IIR1 INP1 MUX"},
{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
@@ -2406,9 +2425,17 @@
SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
+ SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, MSM8X10_WCD_A_TX_3_EN, 7, 0,
+ msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
+ &tx_adc2_mux),
SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
7, 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,
},