Merge "arm/dt: msm8610: Adjust Y-clipping data for Atmel touch Controller"
diff --git a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
index 6ac80f1..b6fc45a 100644
--- a/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
+++ b/Documentation/devicetree/bindings/arm/msm/core_sleep_status.txt
@@ -6,11 +6,6 @@
devices require that the offlined core is power collapsed before turning off
the resources that are used by the offlined core.
-This device is dependent on the pm-8x60 device, which configures the low power
-mode of respective cores. The sleep status is only valid when the core enters
-a low power mode. The device is a child node to pm-8x60 node which is documented
-in Documentation/devicetree/bindings/arm/msm/pm-8x60.txt
-
The required properties of sleep status device are:
- compatible: qcom,cpu-sleep-status
diff --git a/Documentation/devicetree/bindings/dma/sps/sps.txt b/Documentation/devicetree/bindings/dma/sps/sps.txt
index 094acb1..a979c56 100644
--- a/Documentation/devicetree/bindings/dma/sps/sps.txt
+++ b/Documentation/devicetree/bindings/dma/sps/sps.txt
@@ -14,6 +14,9 @@
1 - With BAM DMA and without pipe memory
2 - With BAM DMA and with pipe memory
3 - Without BAM DMA and without pipe memory
+ - qcom,pipe-attr-ee: BAM pipes are attributed to a specific EE, with
+ which we can know the pipes belong to apps side and can have the
+ error interrupts at the pipe level.
Example:
@@ -24,4 +27,5 @@
<0xfe803000 0x4800>;
interrupts = <0 94 0>;
qcom,device-type = <2>;
+ qcom,pipe-attr-ee;
};
diff --git a/Documentation/devicetree/bindings/power/qpnp-bms.txt b/Documentation/devicetree/bindings/power/qpnp-bms.txt
index b350e24..3cac311 100644
--- a/Documentation/devicetree/bindings/power/qpnp-bms.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-bms.txt
@@ -67,6 +67,16 @@
- qcom,tm-temp-margin: if the pmic die temperature changes by more than this
value, recalibrate the ADCs. The unit of this property
is in millidegrees celsius.
+- qcom,min-fcc-learning-soc: An interger value which defines the minimum SOC
+ to start FCC learning. This is applicable only if
+ FCC learning is enabled.
+- qcom,min-fcc-ocv-pc: An interger value which defines the minimum PC-lookup(OCV)
+ to start FCC learning. This is applicable only if
+ FCC learning is enabled.
+- qcom,min-fcc-learning-samples: An interger value which defines the minimum
+ number of the FCC measurement cycles required to
+ generate an FCC update. This is applicable only
+ if the FCC learning is enabled.
Parent node optional properties:
- qcom,ignore-shutdown-soc: A boolean that controls whether BMS will
@@ -81,6 +91,8 @@
RDS of the batfet.
- qcom,use-ocv-thresholds : A boolean that controls whether BMS will take
new OCVs only between the defined thresholds.
+- qcom,enable-fcc-learning: A boolean that defines if FCC learning is enabled.
+
All sub node required properties:
- reg : offset and length of the PMIC peripheral register map.
diff --git a/Documentation/devicetree/bindings/spi/spi_qsd.txt b/Documentation/devicetree/bindings/spi/spi_qsd.txt
index 4b912f3..f16bcbc 100644
--- a/Documentation/devicetree/bindings/spi/spi_qsd.txt
+++ b/Documentation/devicetree/bindings/spi/spi_qsd.txt
@@ -23,6 +23,12 @@
- qcom,infinite-mode: When missing or set to zero, QUP uses infinite-mode. When
value is non-zero, the value is the number of words in maximum transfer
length.
+ - qcom,active-only : Vote for core clock when the application processor goes
+ to active state and remove that vote when it goes to idle state. This flag may
+ improve service time of first spi request at the expense of power consumption.
+ When this entry is not present, voting is done by the runtime-pm callbacks.
+ - qcom,master-id : Master endpoint number used for voting on clocks using the
+ bus-scaling driver.
Optional properties which are required for support of BAM-mode:
- qcom,ver-reg-exists : Boolean. When present, allows driver to verify if HW
@@ -81,4 +87,5 @@
qcom,bam-consumer-pipe-index = <12>;
qcom,bam-producer-pipe-index = <13>;
qcom,ver-reg-exists;
+ qcom,master-id = <86>;
};
diff --git a/Documentation/devicetree/bindings/usb/msm-hsusb.txt b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
index fbe2d25..e3a6721 100644
--- a/Documentation/devicetree/bindings/usb/msm-hsusb.txt
+++ b/Documentation/devicetree/bindings/usb/msm-hsusb.txt
@@ -135,6 +135,21 @@
qcom,usb2-power-budget = <500>;
};
+MSM HSUSB controller
+
+Required properties :
+- compatible : should be "qcom,ci13xxx_msm"
+
+Optional properties :
+- qcom,itc-level: value of 2^itc-level will be used for as the interrupt threshold
+ (ITC), when itc-level is between 0 to 6.
+
+Example MSM HSUSB controller device node :
+ msm_hsusb: qcom,ci13xxx_msm {
+ compatible = "qcom,ci13xxx_msm";
+ qcom,itc-level = <4>;
+};
+
ANDROID USB:
Required properties:
diff --git a/arch/arm/boot/dts/apq8074-dragonboard.dtsi b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
index 6b4d1d3..a8b3065 100644
--- a/arch/arm/boot/dts/apq8074-dragonboard.dtsi
+++ b/arch/arm/boot/dts/apq8074-dragonboard.dtsi
@@ -21,6 +21,7 @@
qcom,mdss_dsi_sharp_qhd_video {
status = "ok";
+ qcom,cont-splash-enabled;
};
qcom,hdmi_tx@fd922100 {
diff --git a/arch/arm/boot/dts/apq8084.dtsi b/arch/arm/boot/dts/apq8084.dtsi
index d4adb2a..b39f569 100644
--- a/arch/arm/boot/dts/apq8084.dtsi
+++ b/arch/arm/boot/dts/apq8084.dtsi
@@ -117,6 +117,14 @@
status = "disabled";
};
+ qcom,sps@f9980000 {
+ compatible = "qcom,msm_sps";
+ reg = <0xf9984000 0x15000>,
+ <0xf9999000 0xb000>;
+ interrupts = <0 94 0>;
+ qcom,pipe-attr-ee;
+ };
+
spmi_bus: qcom,spmi@fc4c0000 {
cell-index = <0>;
compatible = "qcom,spmi-pmic-arb";
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dts b/arch/arm/boot/dts/mpq8092-rumi.dts
new file mode 100644
index 0000000..1abaf55
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-rumi.dts
@@ -0,0 +1,28 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+/include/ "mpq8092.dtsi"
+/include/ "mpq8092-rumi.dtsi"
+
+/ {
+ model = "Qualcomm MPQ8092 RUMI";
+ compatible = "qcom,mpq8092-rumi", "qcom,mpq8092", "qcom,rumi";
+ qcom,msm-id = <146 16 0>;
+};
+
+&soc {
+ serial@f9922000 {
+ status = "ok";
+ };
+};
diff --git a/arch/arm/boot/dts/mpq8092-rumi.dtsi b/arch/arm/boot/dts/mpq8092-rumi.dtsi
new file mode 100644
index 0000000..2016998
--- /dev/null
+++ b/arch/arm/boot/dts/mpq8092-rumi.dtsi
@@ -0,0 +1,134 @@
+/* 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 {
+ timer {
+ clock-frequency = <5000000>;
+ };
+
+ timer@f9020000 {
+ clock-frequency = <5000000>;
+ };
+
+ usb@f9a55000 {
+ status = "disable";
+ };
+
+ qcom,sdcc@f9824000 {
+ status = "disabled";
+ qcom,clk-rates = <400000 19200000>;
+ };
+
+ qcom,sdcc@f98a4000 {
+ status = "disabled";
+ qcom,clk-rates = <400000 19200000>;
+ };
+
+ qcom,sps@f998000 {
+ status = "disable";
+ };
+
+ spi@f9924000 {
+ status = "disable";
+ };
+
+ spi@f9923000 {
+ compatible = "qcom,spi-qup-v2";
+ reg = <0xf9923000 0x1000>;
+ interrupts = <0 95 0>;
+ spi-max-frequency = <24000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gpios = <&msmgpio 3 0>, /* CLK */
+ <&msmgpio 1 0>, /* MISO */
+ <&msmgpio 0 0>; /* MOSI */
+ cs-gpios = <&msmgpio 9 0>;
+
+ ethernet-switch@2 {
+ compatible = "simtec,ks8851";
+ reg = <2>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <90 0>;
+ spi-max-frequency = <5000000>;
+ };
+ };
+
+ i2c@f9966000 {
+ status = "disable";
+ };
+
+ i2c@f9967000 {
+ status = "disable";
+ cell-index = <0>;
+ compatible = "qcom,i2c-qup";
+ reg = <0Xf9967000 0x1000>;
+ reg-names = "qup_phys_addr";
+ interrupts = <0 105 0>;
+ interrupt-names = "qup_err_intr";
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <19200000>;
+ gpios = <&msmgpio 83 0>,/* DAT */
+ <&msmgpio 84 0>;/* CLK */
+ };
+
+ slim@fe12f000 {
+ status = "disable";
+ };
+
+ qcom,mdss_dsi@fd922800 {
+ status = "disable";
+ };
+
+ qcom,spmi@fc4c0000 {
+ status = "disable";
+ };
+
+ qcom,ssusb@F9200000 {
+ status = "disable";
+ };
+
+ qcom,lpass@fe200000 {
+ status = "disable";
+ };
+
+ qcom,pronto@fb21b000 {
+ status = "disable";
+ };
+
+ qcom,mss@fc880000 {
+ status = "disable";
+ };
+
+ qcom,kgsl-3d0@fdb00000 {
+ status = "disabled";
+ };
+};
+
+&gdsc_venus {
+ status = "disabled";
+};
+
+&gdsc_jpeg {
+ status = "disabled";
+};
+
+&gdsc_oxili_gx {
+ status = "disabled";
+};
+
+&gdsc_oxili_cx {
+ status = "disabled";
+};
+
+&gdsc_usb_hsic {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/mpq8092.dtsi b/arch/arm/boot/dts/mpq8092.dtsi
index cc19cce..e8674a0 100644
--- a/arch/arm/boot/dts/mpq8092.dtsi
+++ b/arch/arm/boot/dts/mpq8092.dtsi
@@ -55,6 +55,65 @@
clock-frequency = <19200000>;
};
+ timer@f9020000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "arm,armv7-timer-mem";
+ reg = <0xf9020000 0x1000>;
+ clock-frequency = <19200000>;
+
+ frame@f9021000 {
+ frame-number = <0>;
+ interrupts = <0 8 0x4>,
+ <0 7 0x4>;
+ reg = <0xf9021000 0x1000>,
+ <0xf9022000 0x1000>;
+ };
+
+ frame@f9023000 {
+ frame-number = <1>;
+ interrupts = <0 9 0x4>;
+ reg = <0xf9023000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@f9024000 {
+ frame-number = <2>;
+ interrupts = <0 10 0x4>;
+ reg = <0xf9024000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@f9025000 {
+ frame-number = <3>;
+ interrupts = <0 11 0x4>;
+ reg = <0xf9025000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@f9026000 {
+ frame-number = <4>;
+ interrupts = <0 12 0x4>;
+ reg = <0xf9026000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@f9027000 {
+ frame-number = <5>;
+ interrupts = <0 13 0x4>;
+ reg = <0xf9027000 0x1000>;
+ status = "disabled";
+ };
+
+ frame@f9028000 {
+ frame-number = <6>;
+ interrupts = <0 14 0x4>;
+ reg = <0xf9028000 0x1000>;
+ status = "disabled";
+ };
+ };
+
serial@f991f000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf991f000 0x1000>;
@@ -62,6 +121,13 @@
status = "disabled";
};
+ serial@f9922000 {
+ compatible = "qcom,msm-lsuart-v14";
+ reg = <0xf9922000 0x1000>;
+ interrupts = <0 112 0>;
+ status = "disabled";
+ };
+
serial@f995e000 {
compatible = "qcom,msm-lsuart-v14";
reg = <0xf995e000 0x1000>;
diff --git a/arch/arm/boot/dts/msm-iommu-v0.dtsi b/arch/arm/boot/dts/msm-iommu-v0.dtsi
index 65075e5..2cfc5cf 100644
--- a/arch/arm/boot/dts/msm-iommu-v0.dtsi
+++ b/arch/arm/boot/dts/msm-iommu-v0.dtsi
@@ -326,16 +326,8 @@
compatible = "qcom,msm-smmu-v0-ctx";
reg = <0xfd890000 0x1000>;
interrupts = <0 65 0>;
- qcom,iommu-ctx-mids = <0>;
+ qcom,iommu-ctx-mids = <0 1 2 3 4 5 6 7 8 9>;
label = "vfe0";
};
-
- qcom,iommu-ctx@fd891000 {
- compatible = "qcom,msm-smmu-v0-ctx";
- reg = <0xfd891000 0x1000>;
- interrupts = <0 65 0>;
- qcom,iommu-ctx-mids = <1>;
- label = "vfe1";
- };
};
};
diff --git a/arch/arm/boot/dts/msm-pm8110.dtsi b/arch/arm/boot/dts/msm-pm8110.dtsi
index 1877f40..0e446e2 100644
--- a/arch/arm/boot/dts/msm-pm8110.dtsi
+++ b/arch/arm/boot/dts/msm-pm8110.dtsi
@@ -22,6 +22,11 @@
#address-cells = <1>;
#size-cells = <1>;
+ qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
+
qcom,power-on@800 {
compatible = "qcom,qpnp-power-on";
reg = <0x800 0x100>;
diff --git a/arch/arm/boot/dts/msm-pm8226.dtsi b/arch/arm/boot/dts/msm-pm8226.dtsi
index d429f72..2008e1e 100644
--- a/arch/arm/boot/dts/msm-pm8226.dtsi
+++ b/arch/arm/boot/dts/msm-pm8226.dtsi
@@ -22,6 +22,11 @@
#address-cells = <1>;
#size-cells = <1>;
+ qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
+
qcom,power-on@800 {
compatible = "qcom,qpnp-power-on";
reg = <0x800 0x100>;
diff --git a/arch/arm/boot/dts/msm8226-cdp.dtsi b/arch/arm/boot/dts/msm8226-cdp.dtsi
index e489dbb..2f3fae2 100644
--- a/arch/arm/boot/dts/msm8226-cdp.dtsi
+++ b/arch/arm/boot/dts/msm8226-cdp.dtsi
@@ -167,8 +167,6 @@
qcom,vdd-current-level = <9000 800000>;
vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -204,8 +202,6 @@
qcom,vdd-current-level = <9000 800000>;
vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -258,13 +254,15 @@
qcom,max-current = <40>;
qcom,current-setting = <5>;
qcom,id = <6>;
- qcom,mode = "lpg";
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
qcom,source-sel = <8>;
qcom,mode-ctrl = <0x60>;
qcom,pwm-channel = <0>;
qcom,start-idx = <1>;
qcom,duty-pcts = [00 00 00 00 64
64 00 00 00 00];
+ qcom,use-blink;
};
};
@@ -278,13 +276,15 @@
qcom,max-current = <40>;
qcom,current-setting = <5>;
qcom,id = <6>;
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
qcom,mode-ctrl = <0x60>;
qcom,source-sel = <10>;
- qcom,mode = "lpg";
qcom,pwm-channel = <5>;
qcom,start-idx = <1>;
qcom,duty-pcts = [00 00 00 00 64
64 00 00 00 00];
+ qcom,use-blink;
};
};
};
diff --git a/arch/arm/boot/dts/msm8226-mtp.dtsi b/arch/arm/boot/dts/msm8226-mtp.dtsi
index ae57797..acab5e4 100644
--- a/arch/arm/boot/dts/msm8226-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8226-mtp.dtsi
@@ -173,8 +173,6 @@
qcom,vdd-current-level = <9000 800000>;
vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -207,8 +205,6 @@
qcom,vdd-current-level = <9000 800000>;
vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -261,13 +257,15 @@
qcom,max-current = <40>;
qcom,current-setting = <5>;
qcom,id = <6>;
- qcom,mode = "lpg";
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
qcom,source-sel = <8>;
qcom,mode-ctrl = <0x60>;
qcom,pwm-channel = <0>;
qcom,start-idx = <1>;
qcom,duty-pcts = [00 00 00 00 64
64 00 00 00 00];
+ qcom,use-blink;
};
};
@@ -281,13 +279,15 @@
qcom,max-current = <40>;
qcom,current-setting = <5>;
qcom,id = <6>;
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
qcom,mode-ctrl = <0x60>;
qcom,source-sel = <10>;
- qcom,mode = "lpg";
qcom,pwm-channel = <5>;
qcom,start-idx = <1>;
qcom,duty-pcts = [00 00 00 00 64
64 00 00 00 00];
+ qcom,use-blink;
};
};
};
diff --git a/arch/arm/boot/dts/msm8226-pm.dtsi b/arch/arm/boot/dts/msm8226-pm.dtsi
index 3240efb..703ba4b 100644
--- a/arch/arm/boot/dts/msm8226-pm.dtsi
+++ b/arch/arm/boot/dts/msm8226-pm.dtsi
@@ -10,8 +10,6 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-
&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
diff --git a/arch/arm/boot/dts/msm8226-qrd.dtsi b/arch/arm/boot/dts/msm8226-qrd.dtsi
index a60ff26..7018c6a 100644
--- a/arch/arm/boot/dts/msm8226-qrd.dtsi
+++ b/arch/arm/boot/dts/msm8226-qrd.dtsi
@@ -159,8 +159,6 @@
qcom,vdd-current-level = <9000 800000>;
vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -196,8 +194,6 @@
qcom,vdd-current-level = <9000 800000>;
vdd-io-supply = <&pm8226_l21>;
- qcom,vdd-io-always-on;
- qcom,vdd-io-lpm-sup;
qcom,vdd-io-voltage-level = <1800000 2950000>;
qcom,vdd-io-current-level = <6 22000>;
@@ -250,13 +246,15 @@
qcom,max-current = <40>;
qcom,current-setting = <5>;
qcom,id = <6>;
- qcom,mode = "lpg";
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
qcom,source-sel = <8>;
qcom,mode-ctrl = <0x60>;
qcom,pwm-channel = <0>;
qcom,start-idx = <1>;
qcom,duty-pcts = [00 00 00 00 64
64 00 00 00 00];
+ qcom,use-blink;
};
};
@@ -270,13 +268,15 @@
qcom,max-current = <40>;
qcom,current-setting = <5>;
qcom,id = <6>;
+ qcom,mode = "pwm";
+ qcom,pwm-us = <1000>;
qcom,mode-ctrl = <0x60>;
qcom,source-sel = <10>;
- qcom,mode = "lpg";
qcom,pwm-channel = <5>;
qcom,start-idx = <1>;
qcom,duty-pcts = [00 00 00 00 64
64 00 00 00 00];
+ qcom,use-blink;
};
};
};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 3254d17..e1a0f0b 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -51,17 +51,19 @@
qcom,cpr-ref-clk = <19200>;
qcom,cpr-timer-delay = <5000>;
- qcom,cpr-timer-cons-up = <1>;
+ qcom,cpr-timer-cons-up = <0>;
qcom,cpr-timer-cons-down = <2>;
qcom,cpr-irq-line = <0>;
qcom,cpr-step-quotient = <15>;
- qcom,cpr-up-threshold = <1>;
- qcom,cpr-down-threshold = <2>;
- qcom,cpr-idle-clocks = <5>;
+ qcom,cpr-up-threshold = <0>;
+ qcom,cpr-down-threshold = <10>;
+ qcom,cpr-idle-clocks = <0>;
qcom,cpr-gcnt-time = <1>;
qcom,vdd-apc-step-up-limit = <1>;
qcom,vdd-apc-step-down-limit = <1>;
qcom,cpr-apc-volt-step = <5000>;
+
+ qcom,cpr-enable;
};
};
diff --git a/arch/arm/boot/dts/msm8610-pm.dtsi b/arch/arm/boot/dts/msm8610-pm.dtsi
index 938b2aa..faa7a41 100644
--- a/arch/arm/boot/dts/msm8610-pm.dtsi
+++ b/arch/arm/boot/dts/msm8610-pm.dtsi
@@ -10,8 +10,6 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-
&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
diff --git a/arch/arm/boot/dts/msm8610-qrd.dts b/arch/arm/boot/dts/msm8610-qrd.dts
index 5f9365a..4d7a38a 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -157,6 +157,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x61>;
+ qcom,mode = "manual";
};
};
@@ -171,6 +172,7 @@
qcom,id = <6>;
qcom,source-sel = <1>;
qcom,mode-ctrl = <0x10>;
+ qcom,mode = "manual";
};
};
};
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index f5a19fe..a62df58 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -412,6 +412,10 @@
rpm-standalone;
};
+ qcom,bcl {
+ compatible = "qcom,bcl";
+ };
+
qcom,msm-mem-hole {
compatible = "qcom,msm-mem-hole";
qcom,memblock-remove = <0x07B00000 0x6400000>; /* Address and Size of Hole */
diff --git a/arch/arm/boot/dts/msm8974-camera.dtsi b/arch/arm/boot/dts/msm8974-camera.dtsi
index 786e9e3..456b079 100644
--- a/arch/arm/boot/dts/msm8974-camera.dtsi
+++ b/arch/arm/boot/dts/msm8974-camera.dtsi
@@ -11,8 +11,6 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-
&soc {
qcom,msm-cam@fd8C0000 {
compatible = "qcom,msm-cam";
diff --git a/arch/arm/boot/dts/msm8974-regulator.dtsi b/arch/arm/boot/dts/msm8974-regulator.dtsi
index 2114686..7c191fc 100644
--- a/arch/arm/boot/dts/msm8974-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8974-regulator.dtsi
@@ -380,7 +380,7 @@
status = "okay";
pm8941_l19: regulator-l19 {
regulator-min-microvolt = <2900000>;
- regulator-max-microvolt = <2900000>;
+ regulator-max-microvolt = <3300000>;
qcom,init-voltage = <2900000>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/msm8974-v1-pm.dtsi b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
index cebc99a..288a703 100644
--- a/arch/arm/boot/dts/msm8974-v1-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v1-pm.dtsi
@@ -10,8 +10,6 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-
&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
@@ -427,13 +425,13 @@
reg = <0xfe805664 0x40>;
qcom,pc-mode = "tz_l2_int";
qcom,use-sync-timer;
+ };
- qcom,cpu-sleep-status@f9088008 {
- compatible = "qcom,cpu-sleep-status";
- reg = <0xf9088008 0x4>;
- qcom,cpu-alias-addr = <0x10000>;
- qcom,sleep-status-mask= <0x80000>;
- };
+ qcom,cpu-sleep-status@f9088008 {
+ compatible = "qcom,cpu-sleep-status";
+ reg = <0xf9088008 0x4>;
+ qcom,cpu-alias-addr = <0x10000>;
+ qcom,sleep-status-mask= <0x80000>;
};
qcom,rpm-log@fc19dc00 {
diff --git a/arch/arm/boot/dts/msm8974-v2-pm.dtsi b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
index d3a0bc8..178a1ee 100644
--- a/arch/arm/boot/dts/msm8974-v2-pm.dtsi
+++ b/arch/arm/boot/dts/msm8974-v2-pm.dtsi
@@ -10,8 +10,6 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-
&soc {
qcom,spm@f9089000 {
compatible = "qcom,spm-v2";
@@ -125,9 +123,9 @@
qcom,vctl-port = <0x0>;
qcom,phase-port = <0x1>;
qcom,pfm-port = <0x2>;
- qcom,saw2-spm-cmd-ret = [1f 00 20 03 22 00 0f];
- qcom,saw2-spm-cmd-gdhs = [00 20 32 42 07 44 22 50 02 32 50 0f];
- qcom,saw2-spm-cmd-pc = [00 10 32 b0 11 42 07 01 b0 12 44
+ 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 32 b0 11 42 07 01 b0 44
50 02 32 50 0f];
};
@@ -423,13 +421,13 @@
<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,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 {
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 054c460..fc0636e 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -589,6 +589,7 @@
<&msmgpio 54 0>, /* MISO */
<&msmgpio 53 0>; /* MOSI */
cs-gpios = <&msmgpio 55 0>;
+ qcom,master-id = <84>;
};
tspp: msm_tspp@f99d8000 {
@@ -822,6 +823,7 @@
<&msmgpio 1 0>, /* MISO */
<&msmgpio 0 0>; /* MOSI */
cs-gpios = <&msmgpio 9 0>;
+ qcom,master-id = <86>;
};
qcom,acpuclk@f9000000 {
diff --git a/arch/arm/boot/dts/msm9625-pm.dtsi b/arch/arm/boot/dts/msm9625-pm.dtsi
index 673b640..8eb1119 100644
--- a/arch/arm/boot/dts/msm9625-pm.dtsi
+++ b/arch/arm/boot/dts/msm9625-pm.dtsi
@@ -10,8 +10,6 @@
* GNU General Public License for more details.
*/
-/include/ "skeleton.dtsi"
-
&soc {
qcom,spm@f9009000 {
compatible = "qcom,spm-v2";
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index f654545..f184a00 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -175,6 +175,11 @@
<87 512 40000 640000>;
};
+ msm_hsusb: qcom,ci13xxx_msm {
+ compatible = "qcom,ci13xxx_msm";
+ qcom,itc-level = <4>;
+ };
+
hsic_host: hsic@f9a15000 {
compatible = "qcom,hsic-host";
reg = <0xf9a15000 0x400>;
@@ -244,9 +249,9 @@
qcom,dst-bam-physical-address = <0xf9a44000>;
qcom,dst-bam-pipe-index = <2>;
qcom,data-fifo-offset = <0x4100>;
- qcom,data-fifo-size = <0x400>;
+ qcom,data-fifo-size = <0x700>;
qcom,descriptor-fifo-offset = <0x4000>;
- qcom,descriptor-fifo-size = <0x400>;
+ qcom,descriptor-fifo-size = <0x100>;
};
qcom,pipe3 {
label = "hsic-ipa-in-0";
@@ -516,6 +521,25 @@
qcom,calib-mode = "fuse_map1";
};
+ qcom,msm-thermal {
+ compatible = "qcom,msm-thermal";
+ qcom,sensor-id = <0>;
+ qcom,poll-ms = <250>;
+ qcom,limit-temp = <60>;
+ qcom,temp-hysteresis = <10>;
+ qcom,freq-step = <2>;
+ qcom,freq-control-mask = <0x0>;
+ qcom,vdd-restriction-temp = <5>;
+ qcom,vdd-restriction-temp-hysteresis = <10>;
+ vdd_dig-supply = <&pm8019_l10_corner>;
+
+ qcom,vdd-dig-rstr{
+ qcom,vdd-rstr-reg = "vdd_dig";
+ qcom,levels = <5 7 7>; /* Nominal, Super Turbo, Super Turbo */
+ qcom,min-level = <1>; /* No Request */
+ };
+ };
+
qcom,msm-rng@f9bff000 {
compatible = "qcom,msm-rng";
reg = <0xf9bff000 0x200>;
diff --git a/arch/arm/boot/dts/msmkrypton-sim.dts b/arch/arm/boot/dts/msmkrypton-sim.dts
index 1872a36..29f0df4 100644
--- a/arch/arm/boot/dts/msmkrypton-sim.dts
+++ b/arch/arm/boot/dts/msmkrypton-sim.dts
@@ -23,3 +23,13 @@
&uartdm3{
status = "ok";
};
+
+&spi_6 {
+ ethernet-switch@0 {
+ compatible = "simtec,ks8851";
+ reg = <0>;
+ interrupt-parent = <&msmgpio>;
+ spi-max-frequency = <19200000>;
+ interrupts = <75 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/msmkrypton.dtsi b/arch/arm/boot/dts/msmkrypton.dtsi
index 4b032d8..7bbd528 100644
--- a/arch/arm/boot/dts/msmkrypton.dtsi
+++ b/arch/arm/boot/dts/msmkrypton.dtsi
@@ -117,4 +117,19 @@
interrupts = <0 109 0>;
status = "disabled";
};
+
+ spi_6: spi@f9928000 { /* BLSP1 QUP6 */
+ cell-index = <0>;
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xf9928000 0x1000>;
+ interrupts = <0 100 0>;
+ spi-max-frequency = <19200000>;
+
+ gpios = <&msmgpio 23 0>, /* CLK */
+ <&msmgpio 21 0>, /* MISO */
+ <&msmgpio 20 0>; /* MOSI */
+ cs-gpios = <&msmgpio 22 0>;
+ };
};
diff --git a/arch/arm/configs/apq8084_defconfig b/arch/arm/configs/apq8084_defconfig
index a004835..33e1923 100644
--- a/arch/arm/configs/apq8084_defconfig
+++ b/arch/arm/configs/apq8084_defconfig
@@ -22,7 +22,6 @@
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_PANIC_TIMEOUT=5
CONFIG_KALLSYMS_ALL=y
-CONFIG_ASHMEM=y
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_KPROBES=y
@@ -50,7 +49,6 @@
CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y
CONFIG_MSM_IPC_ROUTER_SECURITY=y
CONFIG_MSM_QMI_INTERFACE=y
-# CONFIG_MSM_HW3D is not set
CONFIG_MSM_RPM_REGULATOR_SMD=y
CONFIG_MSM_SUBSYSTEM_RESTART=y
CONFIG_MSM_SYSMON_COMM=y
@@ -88,7 +86,6 @@
CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
-CONFIG_VMALLOC_RESERVE=0x19000000
CONFIG_CC_STACKPROTECTOR=y
CONFIG_CP_ACCESS=y
CONFIG_USE_OF=y
@@ -101,7 +98,6 @@
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_WAKELOCK=y
CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
@@ -210,8 +206,6 @@
CONFIG_RFKILL=y
CONFIG_GENLOCK=y
CONFIG_GENLOCK_MISCDEVICE=y
-CONFIG_SYNC=y
-CONFIG_SW_SYNC=y
CONFIG_CMA=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
@@ -249,6 +243,7 @@
CONFIG_INPUT_UINPUT=y
CONFIG_SERIAL_MSM_HSL=y
CONFIG_SERIAL_MSM_HSL_CONSOLE=y
+CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_MSM=y
CONFIG_I2C=y
@@ -315,6 +310,9 @@
CONFIG_USB_STORAGE_KARMA=y
CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_STORAGE_ENE_UB6250=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_G_ANDROID=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
CONFIG_MMC_UNSAFE_RESUME=y
@@ -328,10 +326,6 @@
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
CONFIG_MMC_SDHCI_MSM=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_DWC3_MSM=y
-CONFIG_USB_G_ANDROID=y
-CONFIG_DIAG_CHAR=y
CONFIG_LEDS_QPNP=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
@@ -343,6 +337,7 @@
CONFIG_STAGING=y
CONFIG_ANDROID=y
CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_ASHMEM=y
CONFIG_ANDROID_LOGGER=y
CONFIG_ANDROID_TIMED_GPIO=y
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
diff --git a/arch/arm/configs/fsm9xxx-perf_defconfig b/arch/arm/configs/fsm9xxx-perf_defconfig
index 10414e1..37c9554 100644
--- a/arch/arm/configs/fsm9xxx-perf_defconfig
+++ b/arch/arm/configs/fsm9xxx-perf_defconfig
@@ -152,13 +152,6 @@
CONFIG_RTC_CLASS=y
CONFIG_RTC_DEBUG=y
CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ASHMEM=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/fsm9xxx_defconfig b/arch/arm/configs/fsm9xxx_defconfig
index aa3befa..f9295b2 100644
--- a/arch/arm/configs/fsm9xxx_defconfig
+++ b/arch/arm/configs/fsm9xxx_defconfig
@@ -151,13 +151,6 @@
CONFIG_RTC_CLASS=y
CONFIG_RTC_DEBUG=y
CONFIG_STAGING=y
-CONFIG_ANDROID=y
-CONFIG_ANDROID_BINDER_IPC=y
-CONFIG_ASHMEM=y
-CONFIG_ANDROID_LOGGER=y
-CONFIG_ANDROID_RAM_CONSOLE=y
-CONFIG_ANDROID_TIMED_GPIO=y
-CONFIG_ANDROID_LOW_MEMORY_KILLER=y
CONFIG_MSM_SSBI=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index d58f7fb..ae26f96 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -212,6 +212,12 @@
CONFIG_DUMMY=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
@@ -237,6 +243,7 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -303,7 +310,6 @@
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
-CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_MON=y
@@ -311,18 +317,6 @@
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_CSVT=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
@@ -339,6 +333,7 @@
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=m
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
@@ -364,16 +359,8 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V1=y
-CONFIG_CORESIGHT=y
-CONFIG_CORESIGHT_TMC=y
-CONFIG_CORESIGHT_TPIU=y
-CONFIG_CORESIGHT_FUNNEL=y
-CONFIG_CORESIGHT_REPLICATOR=y
-CONFIG_CORESIGHT_STM=y
-CONFIG_CORESIGHT_HWEVENT=y
-CONFIG_CORESIGHT_ETM=y
-CONFIG_CORESIGHT_EVENT=m
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
@@ -413,12 +400,3 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_CRC_CCITT=y
-CONFIG_PPP=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_PPPOE=y
-CONFIG_N_HDLC=y
-CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 07378b2..f8fbdb7 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -213,6 +213,12 @@
CONFIG_TUN=y
# CONFIG_MSM_RMNET is not set
CONFIG_MSM_RMNET_BAM=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPPOE=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
CONFIG_USB_USBNET=y
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
@@ -238,6 +244,7 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -328,7 +335,6 @@
CONFIG_UHID=y
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
-CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_MON=y
@@ -336,18 +342,6 @@
CONFIG_USB_EHCI_EHSET=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_ISD200=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_STORAGE_CYPRESS_ATACB=y
CONFIG_USB_SERIAL=y
CONFIG_USB_SERIAL_CSVT=y
CONFIG_USB_EHSET_TEST_FIXTURE=y
@@ -364,6 +358,7 @@
CONFIG_MMC_PARANOID_SD_INIT=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=m
+CONFIG_MMC_BLOCK_TEST=m
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_MSM=y
@@ -389,6 +384,7 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V1=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_TMC=y
@@ -438,12 +434,3 @@
CONFIG_CRYPTO_DEV_QCRYPTO=m
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCEDEV=m
-CONFIG_CRC_CCITT=y
-CONFIG_PPP=y
-CONFIG_PPP_ASYNC=y
-CONFIG_PPP_SYNC_TTY=y
-CONFIG_PPP_DEFLATE=y
-CONFIG_PPP_BSDCOMP=y
-CONFIG_PPPOE=y
-CONFIG_N_HDLC=y
-CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 3bbff5c..5cad31e 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -224,6 +224,7 @@
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_FT5X06=y
CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
@@ -239,6 +240,7 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -276,7 +278,6 @@
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
CONFIG_MSM_ISPIF=y
-# CONFIG_MSM_ISPIF_V1 is not set
CONFIG_MSMB_CAMERA=y
CONFIG_OV9724=y
CONFIG_MSMB_JPEG=y
@@ -347,6 +348,7 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V0=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index d11773f..95b4f0c 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -222,6 +222,7 @@
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_FT5X06=y
CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4=y
CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV=y
@@ -237,6 +238,7 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -268,15 +270,13 @@
# CONFIG_MSM_CAMERA is not set
CONFIG_OV8825=y
CONFIG_MSM_CAMERA_SENSOR=y
-# CONFIG_MSM_CPP is not set
CONFIG_MSM_CCI=y
-CONFIG_MSM_CSI22_HEADER=y
CONFIG_MSM_CSI20_HEADER=y
CONFIG_MSM_CSIPHY=y
CONFIG_MSM_CSID=y
CONFIG_MSM_ISPIF=y
-# CONFIG_MSM_ISPIF_V1 is not set
CONFIG_MSMB_CAMERA=y
+CONFIG_MSM_CSI22_HEADER=y
CONFIG_OV9724=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_VIDC_V4L2=y
@@ -367,6 +367,7 @@
CONFIG_QPNP_PWM=y
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_VIBRATOR=y
+CONFIG_QPNP_REVID=y
CONFIG_MSM_IOMMU_V0=y
CONFIG_CORESIGHT=y
CONFIG_CORESIGHT_TMC=y
diff --git a/arch/arm/configs/msm8660-perf_defconfig b/arch/arm/configs/msm8660-perf_defconfig
index 1b465af..da4de08 100644
--- a/arch/arm/configs/msm8660-perf_defconfig
+++ b/arch/arm/configs/msm8660-perf_defconfig
@@ -278,6 +278,7 @@
# CONFIG_I2C_MSM is not set
CONFIG_I2C_QUP=y
CONFIG_I2C_SSBI=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8660_defconfig b/arch/arm/configs/msm8660_defconfig
index 40fde84..e30c7d8 100644
--- a/arch/arm/configs/msm8660_defconfig
+++ b/arch/arm/configs/msm8660_defconfig
@@ -278,6 +278,7 @@
# CONFIG_I2C_MSM is not set
CONFIG_I2C_QUP=y
CONFIG_I2C_SSBI=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8960-perf_defconfig b/arch/arm/configs/msm8960-perf_defconfig
index aefc7c9..4610597 100644
--- a/arch/arm/configs/msm8960-perf_defconfig
+++ b/arch/arm/configs/msm8960-perf_defconfig
@@ -319,6 +319,7 @@
CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_MSM is not set
CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8960_defconfig b/arch/arm/configs/msm8960_defconfig
index fbad97a..9b55c3b 100644
--- a/arch/arm/configs/msm8960_defconfig
+++ b/arch/arm/configs/msm8960_defconfig
@@ -83,6 +83,7 @@
CONFIG_MSM_RPM_RBCPR_STATS_LOG=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
CONFIG_MSM_WATCHDOG=y
CONFIG_MSM_DLOAD_MODE=y
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 6c12216..4d124f0 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -290,6 +290,7 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 967f62d..1ffa7d2 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -63,6 +63,7 @@
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_EVENT_TIMER=y
CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
diff --git a/arch/arm/configs/msm9615_defconfig b/arch/arm/configs/msm9615_defconfig
index 3b84f8f..9e8e6ac 100644
--- a/arch/arm/configs/msm9615_defconfig
+++ b/arch/arm/configs/msm9615_defconfig
@@ -53,6 +53,7 @@
CONFIG_MSM_RPM_STATS_LOG=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_MSM_BUS_RPM_MULTI_TIER_ENABLED=y
CONFIG_MSM_WATCHDOG=y
CONFIG_MSM_DLOAD_MODE=y
diff --git a/arch/arm/configs/msm9625-perf_defconfig b/arch/arm/configs/msm9625-perf_defconfig
index 3f15a68..d02f5da 100644
--- a/arch/arm/configs/msm9625-perf_defconfig
+++ b/arch/arm/configs/msm9625-perf_defconfig
@@ -55,7 +55,6 @@
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
CONFIG_MSM_ADSP_LOADER=m
-CONFIG_MSM_RTB=y
CONFIG_MSM_ENABLE_WDOG_DEBUG_CONTROL=y
CONFIG_MSM_UARTDM_Core_v14=y
CONFIG_MSM_BOOT_STATS=y
@@ -210,6 +209,7 @@
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_QUP=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_SPI=y
CONFIG_SPI_QUP=y
CONFIG_SPI_SPIDEV=m
@@ -225,8 +225,8 @@
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
-CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/msm9625_defconfig b/arch/arm/configs/msm9625_defconfig
index c771bc4..64c8535 100644
--- a/arch/arm/configs/msm9625_defconfig
+++ b/arch/arm/configs/msm9625_defconfig
@@ -50,6 +50,7 @@
CONFIG_MSM_PIL_MSS_QDSP6V5=y
CONFIG_MSM_DIRECT_SCLK_ACCESS=y
CONFIG_MSM_BUS_SCALING=y
+CONFIG_MSM_BUSPM_DEV=m
CONFIG_MSM_WATCHDOG_V2=y
CONFIG_MSM_MEMORY_DUMP=y
CONFIG_MSM_DLOAD_MODE=y
@@ -228,8 +229,8 @@
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
CONFIG_THERMAL_TSENS8974=y
-CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_THERMAL_MONITOR=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_WCD9320_CODEC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/msmkrypton_defconfig b/arch/arm/configs/msmkrypton_defconfig
index 69bc36e..f073d2b 100644
--- a/arch/arm/configs/msmkrypton_defconfig
+++ b/arch/arm/configs/msmkrypton_defconfig
@@ -65,9 +65,28 @@
CONFIG_MTD_BLOCK=y
# CONFIG_MTD_MSM_NAND is not set
CONFIG_MTD_MSM_QPIC_NAND=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IPV6=y
+# CONFIG_WIRELESS is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
# CONFIG_ANDROID_PMEM is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+CONFIG_KS8851=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_MSM_RMNET is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_WLAN is not set
# CONFIG_INPUT_MOUSEDEV is not set
CONFIG_INPUT_EVDEV=y
# CONFIG_INPUT_KEYBOARD is not set
diff --git a/arch/arm/mach-msm/Kconfig b/arch/arm/mach-msm/Kconfig
index 7824502..85fa764 100644
--- a/arch/arm/mach-msm/Kconfig
+++ b/arch/arm/mach-msm/Kconfig
@@ -2324,8 +2324,8 @@
config MSM_BUSPM_DEV
tristate "MSM Bus Performance Monitor Kernel Module"
- depends on (ARCH_MSM8X60 || ARCH_MSM8960 || ARCH_MSM8974)
- default m
+ depends on MSM_BUS_SCALING
+ default n
help
This kernel module is used to mmap() hardware registers for the
performance monitors, counters, etc. The module can also be used to
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 9a34d87..1c07dc1 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -277,7 +277,7 @@
obj-$(CONFIG_MACH_MSM8930_FLUID) += board-8930-all.o board-8930-regulator-pm8038.o board-8930-regulator-pm8917.o
obj-$(CONFIG_PM8921_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
obj-$(CONFIG_QPNP_BMS) += bms-batterydata.o bms-batterydata-desay.o batterydata-lib.o
-obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o bms-batterydata-qrd-4v35-2000mah.o
+obj-$(CONFIG_QPNP_BMS) += bms-batterydata-oem.o bms-batterydata-qrd-4v35-2000mah.o bms-batterydata-qrd-4v2-1300mah.o
obj-$(CONFIG_MACH_APQ8064_CDP) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_MTP) += board-8064-all.o board-8064-regulator.o
obj-$(CONFIG_MACH_APQ8064_LIQUID) += board-8064-all.o board-8064-regulator.o
diff --git a/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c b/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c
new file mode 100644
index 0000000..a2c6391
--- /dev/null
+++ b/arch/arm/mach-msm/bms-batterydata-qrd-4v2-1300mah.c
@@ -0,0 +1,112 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mfd/pm8xxx/batterydata-lib.h>
+
+static struct single_row_lut fcc_temp = {
+ .x = {-20, 0, 25, 40, 60},
+ .y = {1343, 1353, 1408, 1345, 1342},
+ .cols = 5
+};
+
+static struct single_row_lut fcc_sf = {
+ .x = {0},
+ .y = {100},
+ .cols = 1
+};
+
+static struct sf_lut rbatt_sf = {
+ .rows = 29,
+ .cols = 5,
+ .row_entries = {-20, 0, 25, 40, 60},
+ .percent = {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},
+ .sf = {
+ {604, 192, 100, 79, 71},
+ {605, 192, 100, 79, 71},
+ {641, 205, 103, 81, 72},
+ {641, 221, 108, 84, 75},
+ {622, 238, 115, 87, 77},
+ {612, 254, 123, 92, 79},
+ {605, 252, 137, 96, 83},
+ {607, 219, 154, 104, 87},
+ {613, 202, 135, 109, 89},
+ {626, 200, 106, 90, 77},
+ {656, 201, 101, 82, 75},
+ {684, 204, 100, 84, 77},
+ {710, 211, 100, 85, 79},
+ {747, 224, 106, 89, 82},
+ {806, 241, 116, 90, 80},
+ {905, 260, 119, 87, 77},
+ {1046, 291, 113, 87, 77},
+ {1309, 329, 116, 90, 79},
+ {1476, 300, 126, 97, 83},
+ {1598, 311, 127, 98, 84},
+ {1771, 323, 130, 99, 85},
+ {1984, 342, 136, 101, 86},
+ {2438, 368, 140, 101, 86},
+ {3381, 388, 137, 100, 84},
+ {4913, 414, 141, 99, 86},
+ {6979, 468, 155, 104, 90},
+ {9968, 565, 192, 113, 98},
+ {16163, 833, 350, 140, 120},
+ {36511, 6483, 4872, 472, 1095}
+ }
+};
+
+static struct pc_temp_ocv_lut pc_temp_ocv = {
+ .rows = 29,
+ .cols = 5,
+ .temp = {-20, 0, 25, 40, 60},
+ .percent = {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},
+ .ocv = {
+ {4177, 4174, 4199, 4167, 4162},
+ {4107, 4112, 4141, 4109, 4106},
+ {4058, 4064, 4091, 4061, 4059},
+ {3996, 4015, 4044, 4017, 4015},
+ {3947, 3975, 4001, 3978, 3976},
+ {3909, 3939, 3962, 3943, 3940},
+ {3874, 3901, 3926, 3911, 3907},
+ {3845, 3858, 3892, 3882, 3878},
+ {3821, 3826, 3851, 3849, 3846},
+ {3801, 3804, 3815, 3810, 3808},
+ {3788, 3789, 3793, 3789, 3787},
+ {3778, 3780, 3778, 3776, 3773},
+ {3769, 3776, 3770, 3767, 3764},
+ {3757, 3772, 3766, 3762, 3757},
+ {3740, 3765, 3762, 3754, 3744},
+ {3714, 3747, 3750, 3739, 3724},
+ {3668, 3706, 3717, 3710, 3697},
+ {3602, 3644, 3662, 3662, 3654},
+ {3533, 3571, 3601, 3607, 3605},
+ {3518, 3557, 3583, 3592, 3590},
+ {3500, 3543, 3565, 3576, 3574},
+ {3478, 3528, 3546, 3559, 3557},
+ {3451, 3506, 3521, 3538, 3534},
+ {3417, 3473, 3481, 3505, 3496},
+ {3377, 3423, 3424, 3454, 3444},
+ {3327, 3361, 3351, 3391, 3380},
+ {3261, 3279, 3258, 3310, 3297},
+ {3165, 3165, 3138, 3198, 3182},
+ {3000, 3000, 3000, 3000, 3000}
+ }
+};
+
+struct bms_battery_data qrd_4v2_1300mah_data = {
+ .fcc = 1300,
+ .fcc_temp_lut = &fcc_temp,
+ .fcc_sf_lut = &fcc_sf,
+ .pc_temp_ocv_lut = &pc_temp_ocv,
+ .rbatt_sf_lut = &rbatt_sf,
+ .default_rbatt_mohm = 172
+};
diff --git a/arch/arm/mach-msm/board-8092.c b/arch/arm/mach-msm/board-8092.c
index 7b81c11..56826c7 100644
--- a/arch/arm/mach-msm/board-8092.c
+++ b/arch/arm/mach-msm/board-8092.c
@@ -75,6 +75,8 @@
static struct of_dev_auxdata mpq8092_auxdata_lookup[] __initdata = {
OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF991F000, \
"msm_serial_hsl.0", NULL),
+ OF_DEV_AUXDATA("qcom,msm-lsuart-v14", 0xF9922000, \
+ "msm_serial_hsl.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF9824000, \
"msm_sdcc.1", NULL),
OF_DEV_AUXDATA("qcom,msm-sdcc", 0xF98A4000, \
@@ -96,6 +98,8 @@
static const char *mpq8092_dt_match[] __initconst = {
"qcom,mpq8092-sim",
+ "qcom,mpq8092-rumi",
+ "qcom,mpq8092",
NULL
};
diff --git a/arch/arm/mach-msm/board-8226.c b/arch/arm/mach-msm/board-8226.c
index 4645d34..39efcd8 100644
--- a/arch/arm/mach-msm/board-8226.c
+++ b/arch/arm/mach-msm/board-8226.c
@@ -49,6 +49,7 @@
#include "clock.h"
#include "platsmp.h"
#include "spm.h"
+#include "pm.h"
#include "lpm_resources.h"
#include "modem_notifier.h"
@@ -111,6 +112,7 @@
msm_rpm_driver_init();
msm_lpmrs_module_init();
msm_spm_device_init();
+ msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
qpnp_regulator_init();
if (of_board_is_rumi())
diff --git a/arch/arm/mach-msm/board-8610-gpiomux.c b/arch/arm/mach-msm/board-8610-gpiomux.c
index 7096f3f..b261ce4 100644
--- a/arch/arm/mach-msm/board-8610-gpiomux.c
+++ b/arch/arm/mach-msm/board-8610-gpiomux.c
@@ -84,6 +84,20 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting lcd_te_act_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
+static struct gpiomux_setting lcd_te_sus_config = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ .dir = GPIOMUX_IN,
+};
+
static struct gpiomux_setting gpio_keys_active = {
.func = GPIOMUX_FUNC_GPIO,
.drv = GPIOMUX_DRV_2MA,
@@ -111,6 +125,13 @@
[GPIOMUX_SUSPENDED] = &lcd_en_sus_cfg,
},
},
+ {
+ .gpio = 12,
+ .settings = {
+ [GPIOMUX_ACTIVE] = &lcd_te_act_config,
+ [GPIOMUX_SUSPENDED] = &lcd_te_sus_config,
+ },
+ },
};
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
@@ -231,6 +252,125 @@
},
};
+static struct gpiomux_setting gpio_suspend_config[] = {
+ {
+ .func = GPIOMUX_FUNC_GPIO, /* IN-NP */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+ {
+ .func = GPIOMUX_FUNC_GPIO, /* O-LOW */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ .dir = GPIOMUX_OUT_LOW,
+ },
+};
+
+static struct gpiomux_setting cam_settings[] = {
+ {
+ .func = GPIOMUX_FUNC_1, /*active 1*/ /* 0 */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*suspend*/ /* 1 */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_1, /*i2c suspend*/ /* 2 */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_KEEPER,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*active 0*/ /* 3 */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+ },
+
+ {
+ .func = GPIOMUX_FUNC_GPIO, /*suspend 0*/ /* 4 */
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+ },
+};
+
+static struct msm_gpiomux_config msm_sensor_configs[] __initdata = {
+ {
+ .gpio = 13, /* CAM_MCLK0 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 14, /* CAM_MCLK1 */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &cam_settings[1],
+ },
+ },
+ {
+ .gpio = 16, /* CCI_I2C_SDA */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
+ },
+ },
+ {
+ .gpio = 17, /* CCI_I2C_SCL */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[0],
+ },
+ },
+ {
+ .gpio = 18, /* FLASH_LED_EN */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 19, /* FLASH_LED_NOW */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[0],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 8, /* CAM1_STANDBY_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 15, /* CAM1_RST_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 20, /* WEBCAM1_STANDBY */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+ {
+ .gpio = 21, /* WEBCAM2_RESET_N */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &cam_settings[3],
+ [GPIOMUX_SUSPENDED] = &gpio_suspend_config[1],
+ },
+ },
+};
+
static struct msm_gpiomux_config msm_keypad_configs[] __initdata = {
{
.gpio = 72,
@@ -298,4 +438,5 @@
msm_gpiomux_install(msm_keypad_configs,
ARRAY_SIZE(msm_keypad_configs));
msm_gpiomux_install(sd_card_det, ARRAY_SIZE(sd_card_det));
+ msm_gpiomux_install(msm_sensor_configs, ARRAY_SIZE(msm_sensor_configs));
}
diff --git a/arch/arm/mach-msm/board-8610.c b/arch/arm/mach-msm/board-8610.c
index 962ed65..b4d77f1 100644
--- a/arch/arm/mach-msm/board-8610.c
+++ b/arch/arm/mach-msm/board-8610.c
@@ -50,6 +50,7 @@
#include "clock.h"
#include "platsmp.h"
#include "spm.h"
+#include "pm.h"
#include "lpm_resources.h"
#include "modem_notifier.h"
@@ -106,6 +107,7 @@
msm_rpm_driver_init();
msm_lpmrs_module_init();
msm_spm_device_init();
+ msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
qpnp_regulator_init();
tsens_tm_init_driver();
diff --git a/arch/arm/mach-msm/board-8974.c b/arch/arm/mach-msm/board-8974.c
index 35e46fc..771359c 100644
--- a/arch/arm/mach-msm/board-8974.c
+++ b/arch/arm/mach-msm/board-8974.c
@@ -95,6 +95,7 @@
msm_smd_init();
msm_rpm_driver_init();
msm_lpmrs_module_init();
+ msm_pm_sleep_status_init();
rpm_regulator_smd_driver_init();
msm_spm_device_init();
krait_power_init();
diff --git a/arch/arm/mach-msm/board-9625.c b/arch/arm/mach-msm/board-9625.c
index 6bb5655..56246dd 100644
--- a/arch/arm/mach-msm/board-9625.c
+++ b/arch/arm/mach-msm/board-9625.c
@@ -22,6 +22,7 @@
#include <linux/of_irq.h>
#include <linux/memory.h>
#include <linux/msm_tsens.h>
+#include <linux/msm_thermal.h>
#include <asm/mach/map.h>
#include <asm/hardware/gic.h>
#include <asm/mach/arch.h>
@@ -239,6 +240,7 @@
msm_clock_init(&msm9625_clock_init_data);
msm9625_init_buses();
tsens_tm_init_driver();
+ msm_thermal_device_init();
}
void __init msm9625_init(void)
diff --git a/arch/arm/mach-msm/board-krypton-gpiomux.c b/arch/arm/mach-msm/board-krypton-gpiomux.c
index 3d86ba7..ee38e5f 100644
--- a/arch/arm/mach-msm/board-krypton-gpiomux.c
+++ b/arch/arm/mach-msm/board-krypton-gpiomux.c
@@ -17,12 +17,37 @@
#include <mach/gpio.h>
#include <mach/gpiomux.h>
+#define KS8851_IRQ_GPIO 75
+
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+static struct gpiomux_setting gpio_eth_config = {
+ .pull = GPIOMUX_PULL_UP,
+ .drv = GPIOMUX_DRV_2MA,
+ .func = GPIOMUX_FUNC_GPIO,
+};
+
+static struct msm_gpiomux_config msm_eth_config[] = {
+ {
+ .gpio = KS8851_IRQ_GPIO,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_eth_config,
+ }
+ },
+};
+#endif
+
static struct gpiomux_setting gpio_uart_config = {
.func = GPIOMUX_FUNC_1,
.drv = GPIOMUX_DRV_8MA,
.pull = GPIOMUX_PULL_NONE,
};
+static struct gpiomux_setting gpio_spi_config = {
+ .func = GPIOMUX_FUNC_2,
+ .drv = GPIOMUX_DRV_6MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
{
.gpio = 8, /* BLSP1 UART TX */
@@ -36,6 +61,30 @@
[GPIOMUX_SUSPENDED] = &gpio_uart_config,
},
},
+ {
+ .gpio = 20, /* BLSP1 QUP6 SPI_DATA_MOSI */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 21, /* BLSP1 QUP6 SPI_DATA_MISO */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 23, /* BLSP1 QUP6 SPI_CLK */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
+ {
+ .gpio = 22, /* BLSP1 QUP6 SPI_CS */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_spi_config,
+ },
+ },
};
void __init msmkrypton_init_gpiomux(void)
@@ -49,4 +98,7 @@
}
msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
+#if defined(CONFIG_KS8851) || defined(CONFIG_KS8851_MODULE)
+ msm_gpiomux_install(msm_eth_config, ARRAY_SIZE(msm_eth_config));
+#endif
}
diff --git a/arch/arm/mach-msm/board-krypton.c b/arch/arm/mach-msm/board-krypton.c
index ff7c8e0..b40fcfa 100644
--- a/arch/arm/mach-msm/board-krypton.c
+++ b/arch/arm/mach-msm/board-krypton.c
@@ -34,6 +34,9 @@
static struct clk_lookup msm_clocks_dummy[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "f991f000.serial", OFF),
+ CLK_DUMMY("core_clk", SPI_CLK, "f9928000.spi", OFF),
+ CLK_DUMMY("iface_clk", SPI_P_CLK, "f9928000.spi", OFF),
+
};
static struct clock_init_data msm_dummy_clock_init_data __initdata = {
diff --git a/arch/arm/mach-msm/clock-8092.c b/arch/arm/mach-msm/clock-8092.c
index a8520e6..9de97ea 100644
--- a/arch/arm/mach-msm/clock-8092.c
+++ b/arch/arm/mach-msm/clock-8092.c
@@ -38,6 +38,8 @@
static struct clk_lookup msm_clocks_8092[] = {
CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "msm_serial_hsl.0", OFF),
+ CLK_DUMMY("core_clk", BLSP1_UART_CLK, "msm_serial_hsl.1", OFF),
+ CLK_DUMMY("iface_clk", BLSP1_UART_CLK, "msm_serial_hsl.1", OFF),
CLK_DUMMY("core_clk", SDC1_CLK, "msm_sdcc.1", OFF),
CLK_DUMMY("iface_clk", SDC1_P_CLK, "msm_sdcc.1", OFF),
CLK_DUMMY("core_clk", SDC2_CLK, "msm_sdcc.2", OFF),
@@ -246,7 +248,9 @@
CLK_DUMMY("", mmss_mmssnoc_ahb_clk.c, "", OFF),
CLK_DUMMY("", mmss_mmssnoc_axi_clk.c, "", OFF),
CLK_DUMMY("", mmss_s0_axi_clk.c, "", OFF),
- CLK_DUMMY("", ocmemcx_ocmemnoc_clk.c, "", OFF),
+ CLK_DUMMY("core_clk", ocmemgx_core_clk.c, "fdd00000.qcom,ocmem", OFF),
+ CLK_DUMMY("iface_clk", ocmemcx_ocmemnoc_clk.c, "fdd00000.qcom.ocmem",
+ OFF),
CLK_DUMMY("", oxili_ocmemgx_clk.c, "", OFF),
CLK_DUMMY("", oxili_gfx3d_clk.c, "", OFF),
CLK_DUMMY("", oxilicx_ahb_clk.c, "", OFF),
diff --git a/arch/arm/mach-msm/clock-8226.c b/arch/arm/mach-msm/clock-8226.c
index f1df505..fd3ba14 100644
--- a/arch/arm/mach-msm/clock-8226.c
+++ b/arch/arm/mach-msm/clock-8226.c
@@ -1891,7 +1891,7 @@
.c = {
.dbg_name = "vcodec0_clk_src",
.ops = &clk_ops_rcg_mnd,
- VDD_DIG_FMAX_MAP3(LOW, 66670000, NOMINAL, 133330000, HIGH,
+ VDD_DIG_FMAX_MAP3(LOW, 66700000, NOMINAL, 133330000, HIGH,
160000000),
CLK_INIT(vcodec0_clk_src.c),
},
@@ -2868,6 +2868,7 @@
static DEFINE_CLK_VOTER(qseecom_ce1_clk_src, &ce1_clk_src.c, 100000000);
static DEFINE_CLK_VOTER(scm_ce1_clk_src, &ce1_clk_src.c, 100000000);
+static DEFINE_CLK_VOTER(gud_ce1_clk_src, &ce1_clk_src.c, 100000000);
static DEFINE_CLK_BRANCH_VOTER(cxo_otg_clk, &xo.c);
static DEFINE_CLK_BRANCH_VOTER(cxo_pil_lpass_clk, &xo.c);
@@ -3236,6 +3237,11 @@
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "qseecom"),
CLK_LOOKUP("core_clk_src", qseecom_ce1_clk_src.c, "qseecom"),
+ CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "mcd"),
+ CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "mcd"),
+ CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "mcd"),
+ CLK_LOOKUP("core_clk_src", gud_ce1_clk_src.c, "mcd"),
+
CLK_LOOKUP("core_clk", gcc_ce1_clk.c, "scm"),
CLK_LOOKUP("iface_clk", gcc_ce1_ahb_clk.c, "scm"),
CLK_LOOKUP("bus_clk", gcc_ce1_axi_clk.c, "scm"),
diff --git a/arch/arm/mach-msm/clock-8610.c b/arch/arm/mach-msm/clock-8610.c
index 9a66b78..58c5745 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -1828,6 +1828,7 @@
};
static struct clk_freq_tbl ftbl_mclk0_1_clk[] = {
+ F_MM(24000000, gpll0, 5, 1, 5),
F_MM(66670000, gpll0, 9, 0, 0),
F_END,
};
@@ -2997,6 +2998,77 @@
"fd010000.qcom,iommu"),
CLK_LOOKUP("core_clk", pnoc_iommu_clk.c, "fd010000.qcom,iommu"),
+ /* MM sensor clocks */
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006f"),
+ CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "6-006d"),
+ CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006f"),
+ CLK_LOOKUP("cam_clk", mclk0_clk.c, "6-006d"),
+
+
+ /* CSIPHY clocks */
+ CLK_LOOKUP("csiphy_timer_src_clk", csi0phytimer_clk_src.c,
+ "fda00c00.qcom,csiphy"),
+ CLK_LOOKUP("csiphy_timer_clk", csi0phytimer_clk.c,
+ "fda00c00.qcom,csiphy"),
+ CLK_LOOKUP("csiphy_timer_src_clk", csi1phytimer_clk_src.c,
+ "fda01000.qcom,csiphy"),
+ CLK_LOOKUP("csiphy_timer_clk", csi1phytimer_clk.c,
+ "fda01000.qcom,csiphy"),
+
+ /* CSID clocks */
+
+ CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda00000.qcom,csid"),
+ CLK_LOOKUP("csi_src_clk", csi0_clk_src.c, "fda00000.qcom,csid"),
+ CLK_LOOKUP("csi_clk", csi0_clk.c, "fda00000.qcom,csid"),
+ CLK_LOOKUP("csi_phy_clk", csi0phy_clk.c, "fda00000.qcom,csid"),
+ CLK_LOOKUP("csi_pix_clk", csi0pix_clk.c, "fda00000.qcom,csid"),
+ CLK_LOOKUP("csi_rdi_clk", csi0rdi_clk.c, "fda00000.qcom,csid"),
+
+ /*CLK_LOOKUP("csi0_phy_mux_sel", csi0phy_mux_clk.c,
+ "fda00000.qcom,csid"),
+ CLK_LOOKUP("csi0_pix_mux_sel", csi0pix_mux_clk.c,
+ "fda00000.qcom,csid"),
+ CLK_LOOKUP("csi0_rdi_mux_sel", rdi0_mux_clk.c,
+ "fda00000.qcom,csid"),*/
+
+ CLK_LOOKUP("csi_ahb_clk", csi_ahb_clk.c, "fda00400.qcom,csid"),
+ CLK_LOOKUP("csi_src_clk", csi1_clk_src.c, "fda00400.qcom,csid"),
+ CLK_LOOKUP("csi_clk", csi1_clk.c, "fda00400.qcom,csid"),
+ CLK_LOOKUP("csi_phy_clk", csi1phy_clk.c, "fda00400.qcom,csid"),
+ CLK_LOOKUP("csi_pix_clk", csi1pix_clk.c, "fda00400.qcom,csid"),
+ CLK_LOOKUP("csi_rdi_clk", csi1rdi_clk.c, "fda00400.qcom,csid"),
+
+ /*CLK_LOOKUP("csi1_phy_mux_sel", csi1phy_mux_clk.c,
+ "fda00400.qcom,csid"),
+ CLK_LOOKUP("csi1_pix_mux_sel", csi0pix_mux_clk.c,
+ "fda00400.qcom,csid"),
+ CLK_LOOKUP("csi1_rdi_mux_sel", rdi1_mux_clk.c,
+ "fda00400.qcom,csid"),*/
+
+ /* ISPIF clocks */
+ CLK_LOOKUP("csi_src_clk", csi0_clk_src.c, "fda00800.qcom,ispif"),
+ CLK_LOOKUP("csi_src_clk", csi1_clk_src.c, "fda00800.qcom,ispif"),
+
+ CLK_LOOKUP("csi_pix_clk", csi0pix_clk.c,
+ "fda00800.qcom,ispif"),
+ CLK_LOOKUP("csi_rdi_clk", csi0rdi_clk.c,
+ "fda00800.qcom,ispif"),
+ CLK_LOOKUP("csi_pix1_clk", csi1pix_clk.c,
+ "fda00800.qcom,ispif"),
+ CLK_LOOKUP("csi_rdi1_clk", csi1rdi_clk.c,
+ "fda00800.qcom,ispif"),
+ CLK_LOOKUP("csi_rdi2_clk", csi1rdi_clk.c,
+ "fda00800.qcom,ispif"),
+
+ CLK_LOOKUP("vfe_clk_src", vfe_clk_src.c, "fde00000.qcom,vfe"),
+ CLK_LOOKUP("vfe_clk", vfe_clk.c, "fde00000.qcom,vfe"),
+
+ CLK_LOOKUP("csi_vfe_clk", csi_vfe_clk.c, "fde00000.qcom,vfe"),
+ CLK_LOOKUP("vfe_ahb_clk", vfe_ahb_clk.c, "fde00000.qcom,vfe"),
+
+ CLK_LOOKUP("bus_clk", vfe_axi_clk.c, "fde00000.qcom,vfe"),
+
+
CLK_LOOKUP("core_clk", q6ss_xo_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("bus_clk", gcc_lpass_q6_axi_clk.c, "fe200000.qcom,lpass"),
CLK_LOOKUP("iface_clk", q6ss_ahb_lfabif_clk.c, "fe200000.qcom,lpass"),
diff --git a/arch/arm/mach-msm/clock-9625.c b/arch/arm/mach-msm/clock-9625.c
index adb1101..facd6ba 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -1574,6 +1574,10 @@
};
struct measure_mux_entry measure_mux_common[] __initdata = {
+ {&snoc_clk.c, GCC_BASE, 0x0000},
+ {&cnoc_clk.c, GCC_BASE, 0x0008},
+ {&pnoc_clk.c, GCC_BASE, 0x0010},
+ {&bimc_clk.c, GCC_BASE, 0x0155},
{&gcc_pdm_ahb_clk.c, GCC_BASE, 0x00d0},
{&gcc_usb_hsic_io_cal_sleep_clk.c, GCC_BASE, 0x005c},
{&gcc_usb_hsic_xcvr_fs_clk.c, GCC_BASE, 0x005d},
diff --git a/arch/arm/mach-msm/cpr-regulator.c b/arch/arm/mach-msm/cpr-regulator.c
index e647d1d..5550282 100644
--- a/arch/arm/mach-msm/cpr-regulator.c
+++ b/arch/arm/mach-msm/cpr-regulator.c
@@ -682,10 +682,20 @@
}
rc = regulator_enable(cpr_vreg->vdd_apc);
- if (!rc)
- cpr_vreg->vreg_enabled = true;
- else
+ if (rc) {
pr_err("regulator_enable: vdd_apc: rc=%d\n", rc);
+ return rc;
+ }
+
+ cpr_vreg->vreg_enabled = true;
+
+ mutex_lock(&cpr_vreg->cpr_mutex);
+ if (cpr_is_allowed(cpr_vreg) && cpr_vreg->corner) {
+ cpr_irq_clr(cpr_vreg);
+ cpr_corner_switch(cpr_vreg, cpr_vreg->corner);
+ cpr_ctl_enable(cpr_vreg);
+ }
+ mutex_unlock(&cpr_vreg->cpr_mutex);
return rc;
}
@@ -700,10 +710,17 @@
if (cpr_vreg->vdd_mx)
rc = regulator_disable(cpr_vreg->vdd_mx);
- if (rc)
+ if (rc) {
pr_err("regulator_disable: vdd_mx: rc=%d\n", rc);
- else
- cpr_vreg->vreg_enabled = false;
+ return rc;
+ }
+
+ cpr_vreg->vreg_enabled = false;
+
+ mutex_lock(&cpr_vreg->cpr_mutex);
+ if (cpr_is_allowed(cpr_vreg))
+ cpr_ctl_disable(cpr_vreg);
+ mutex_unlock(&cpr_vreg->cpr_mutex);
} else {
pr_err("regulator_disable: vdd_apc: rc=%d\n", rc);
}
@@ -739,7 +756,7 @@
if (rc)
goto _exit;
- if (cpr_is_allowed(cpr_vreg)) {
+ if (cpr_is_allowed(cpr_vreg) && cpr_vreg->vreg_enabled) {
cpr_irq_clr(cpr_vreg);
cpr_corner_switch(cpr_vreg, corner);
cpr_ctl_enable(cpr_vreg);
diff --git a/arch/arm/mach-msm/hotplug.c b/arch/arm/mach-msm/hotplug.c
index e9a4af0..20e3c3b 100644
--- a/arch/arm/mach-msm/hotplug.c
+++ b/arch/arm/mach-msm/hotplug.c
@@ -24,16 +24,9 @@
extern volatile int pen_release;
-struct msm_hotplug_device {
- struct completion cpu_killed;
- unsigned int warm_boot;
-};
-
-
static cpumask_t cpu_dying_mask;
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct msm_hotplug_device,
- msm_hotplug_devices);
+static DEFINE_PER_CPU(unsigned int, warm_boot_flag);
static inline void cpu_enter_lowpower(void)
{
@@ -95,7 +88,6 @@
__func__, smp_processor_id(), cpu);
BUG();
}
- complete(&__get_cpu_var(msm_hotplug_devices).cpu_killed);
/*
* we're ready for shutdown now, so do it
*/
@@ -161,11 +153,10 @@
int msm_platform_secondary_init(unsigned int cpu)
{
int ret;
- struct msm_hotplug_device *dev = &__get_cpu_var(msm_hotplug_devices);
+ unsigned int *warm_boot = &__get_cpu_var(warm_boot_flag);
- if (!dev->warm_boot) {
- dev->warm_boot = 1;
- init_completion(&dev->cpu_killed);
+ if (!(*warm_boot)) {
+ *warm_boot = 1;
return 0;
}
msm_jtag_restore_state();
@@ -179,9 +170,6 @@
static int __init init_hotplug(void)
{
-
- struct msm_hotplug_device *dev = &__get_cpu_var(msm_hotplug_devices);
- init_completion(&dev->cpu_killed);
return register_hotcpu_notifier(&hotplug_rtb_notifier);
}
early_initcall(init_hotplug);
diff --git a/arch/arm/mach-msm/include/mach/msm_spi.h b/arch/arm/mach-msm/include/mach/msm_spi.h
index ab5271f..608927c 100644
--- a/arch/arm/mach-msm/include/mach/msm_spi.h
+++ b/arch/arm/mach-msm/include/mach/msm_spi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2009, 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2009, 2012-2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -14,8 +14,19 @@
* SPI driver for Qualcomm MSM platforms.
*/
+/**
+ * msm_spi_platform_data: msm spi-controller's configuration data
+ *
+ * @active_only when set, votes when system active and removes the vote when
+ * system goes idle (optimises for performance). When unset, voting using
+ * runtime pm (optimizes for power).
+ * @master_id master id number of the controller's wrapper (BLSP or GSBI).
+ * When zero, clock path voting is disabled.
+ */
struct msm_spi_platform_data {
u32 max_clock_speed;
+ bool active_only;
+ u32 master_id;
int (*gpio_config)(void);
void (*gpio_release)(void);
int (*dma_config)(void);
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index 3a997be..a4021d4 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -18,13 +18,13 @@
#define QSEECOM_KEY_ID_SIZE 32
-#define QSEOS_RESULT_FAIL_LOAD_KS -48
-#define QSEOS_RESULT_FAIL_SAVE_KS -49
-#define QSEOS_RESULT_FAIL_MAX_KEYS -50
-#define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -51
-#define QSEOS_RESULT_FAIL_KEY_ID_DNE -52
-#define QSEOS_RESULT_FAIL_KS_OP -53
-#define QSEOS_RESULT_FAIL_CE_PIPE_INVALID -54
+#define QSEOS_RESULT_FAIL_LOAD_KS -57
+#define QSEOS_RESULT_FAIL_SAVE_KS -58
+#define QSEOS_RESULT_FAIL_MAX_KEYS -59
+#define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -60
+#define QSEOS_RESULT_FAIL_KEY_ID_DNE -61
+#define QSEOS_RESULT_FAIL_KS_OP -62
+#define QSEOS_RESULT_FAIL_CE_PIPE_INVALID -63
enum qseecom_command_scm_resp_type {
QSEOS_APP_ID = 0xEE01,
diff --git a/arch/arm/mach-msm/ipc_router.c b/arch/arm/mach-msm/ipc_router.c
index 841ccf3..56eaa2b 100644
--- a/arch/arm/mach-msm/ipc_router.c
+++ b/arch/arm/mach-msm/ipc_router.c
@@ -2258,6 +2258,29 @@
return ret;
}
+/**
+ * msm_ipc_router_recv_from() - Recieve messages destined to a local port.
+ * @port_ptr: Pointer to the local port
+ * @data : Pointer to the socket buffer head
+ * @src: Pointer to local port address
+ * @timeout: < 0 timeout indicates infinite wait till a message arrives.
+ * > 0 timeout indicates the wait time.
+ * 0 indicates that we do not wait.
+ * @return: = Number of bytes read(On successful read operation).
+ * = 0 (If there are no pending messages and timeout is 0).
+ * = -EINVAL (If either of the arguments, port_ptr or data is invalid)
+ * = -EFAULT (If there are no pending messages when timeout is > 0
+ * and the wait_event_interruptible_timeout has returned value > 0)
+ * = -ERESTARTSYS (If there are no pending messages when timeout
+ * is < 0 and wait_event_interruptible was interrupted by a signal)
+ *
+ * This function reads the messages that are destined for a local port. It
+ * is used by modules that exist with-in the kernel and use IPC Router for
+ * transport. The function checks if there are any messages that are already
+ * received. If yes, it reads them, else it waits as per the timeout value.
+ * On a successful read, the return value of the function indicates the number
+ * of bytes that are read.
+ */
int msm_ipc_router_recv_from(struct msm_ipc_port *port_ptr,
struct sk_buff_head **data,
struct msm_ipc_addr *src,
@@ -2291,7 +2314,7 @@
return -EFAULT;
}
if (timeout == 0)
- return -ETIMEDOUT;
+ return 0;
mutex_lock(&port_ptr->port_rx_q_lock_lhb3);
}
mutex_unlock(&port_ptr->port_rx_q_lock_lhb3);
@@ -2326,7 +2349,11 @@
struct sk_buff_head *in_skb_head;
int ret;
- ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, -1);
+ ret = msm_ipc_router_recv_from(port_ptr, &in_skb_head, src, 0);
+
+ if (ret == 0)
+ return -ENOMSG;
+
if (ret < 0) {
pr_err("%s: msm_ipc_router_recv_from failed - ret: %d\n",
__func__, ret);
diff --git a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
index 9b16944..3ff7530 100644
--- a/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
+++ b/arch/arm/mach-msm/msm_bus/msm_bus_arb.c
@@ -491,7 +491,7 @@
deffab = msm_bus_get_fabric_device(MSM_BUS_FAB_DEFAULT);
if (!deffab) {
MSM_BUS_ERR("Error finding default fabric\n");
- return -ENXIO;
+ return 0;
}
nfab = msm_bus_get_num_fab();
diff --git a/arch/arm/mach-msm/msm_qmi_interface.c b/arch/arm/mach-msm/msm_qmi_interface.c
index 4c4635a..9b3e500 100644
--- a/arch/arm/mach-msm/msm_qmi_interface.c
+++ b/arch/arm/mach-msm/msm_qmi_interface.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -450,6 +450,11 @@
/* Read the messages */
rc = msm_ipc_router_read_msg((struct msm_ipc_port *)(handle->src_port),
&src_addr, &recv_msg, &recv_msg_len);
+ if (rc == -ENOMSG) {
+ mutex_unlock(&handle->handle_lock);
+ return rc;
+ }
+
if (rc < 0) {
pr_err("%s: Read failed %d\n", __func__, rc);
mutex_unlock(&handle->handle_lock);
diff --git a/arch/arm/mach-msm/pm-8x60.c b/arch/arm/mach-msm/pm-8x60.c
index 545723c..a054077 100644
--- a/arch/arm/mach-msm/pm-8x60.c
+++ b/arch/arm/mach-msm/pm-8x60.c
@@ -1616,14 +1616,6 @@
{
int rc;
- rc = platform_driver_register(&msm_cpu_status_driver);
-
- if (rc) {
- pr_err("%s(): failed to register driver %s\n", __func__,
- msm_cpu_status_driver.driver.name);
- return rc;
- }
-
rc = platform_driver_register(&msm_cpu_pm_snoc_client_driver);
if (rc) {
@@ -1647,3 +1639,8 @@
return platform_driver_register(&msm_pm_8x60_driver);
}
device_initcall(msm_pm_8x60_init);
+
+void __init msm_pm_sleep_status_init(void)
+{
+ platform_driver_register(&msm_cpu_status_driver);
+}
diff --git a/arch/arm/mach-msm/pm.h b/arch/arm/mach-msm/pm.h
index 8a043d8..f2fc80b 100644
--- a/arch/arm/mach-msm/pm.h
+++ b/arch/arm/mach-msm/pm.h
@@ -136,10 +136,12 @@
void msm_pm_set_rpm_wakeup_irq(unsigned int irq);
void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops);
int msm_pm_wait_cpu_shutdown(unsigned int cpu);
+void __init msm_pm_sleep_status_init(void);
#else
static inline void msm_pm_set_rpm_wakeup_irq(unsigned int irq) {}
static inline void msm_pm_set_sleep_ops(struct msm_pm_sleep_ops *ops) {}
static inline int msm_pm_wait_cpu_shutdown(unsigned int cpu) { return 0; }
+static inline void msm_pm_sleep_status_init(void) {};
#endif
#ifdef CONFIG_HOTPLUG_CPU
int msm_platform_secondary_init(unsigned int cpu);
diff --git a/arch/arm/mach-msm/subsystem_restart.c b/arch/arm/mach-msm/subsystem_restart.c
index a5e04cd..7b1a4c3 100644
--- a/arch/arm/mach-msm/subsystem_restart.c
+++ b/arch/arm/mach-msm/subsystem_restart.c
@@ -952,8 +952,8 @@
static irqreturn_t subsys_err_ready_intr_handler(int irq, void *subsys)
{
struct subsys_device *subsys_dev = subsys;
- pr_info("Error ready interrupt occured for %s\n",
- subsys_dev->desc->name);
+ dev_info(subsys_dev->desc->dev,
+ "Subsystem error monitoring/handling services are up\n");
if (subsys_dev->desc->is_not_loadable)
return IRQ_HANDLED;
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 1c8a25d..4ff4b3e 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -747,16 +747,17 @@
if (PageHighMem(page)) {
if (len + offset > PAGE_SIZE)
len = PAGE_SIZE - offset;
- vaddr = kmap_high_get(page);
- if (vaddr) {
- vaddr += offset;
- op(vaddr, len, dir);
- kunmap_high(page);
- } else if (cache_is_vipt()) {
- /* unmapped pages might still be cached */
+
+ if (cache_is_vipt_nonaliasing()) {
vaddr = kmap_atomic(page);
op(vaddr + offset, len, dir);
kunmap_atomic(vaddr);
+ } else {
+ vaddr = kmap_high_get(page);
+ if (vaddr) {
+ op(vaddr + offset, len, dir);
+ kunmap_high(page);
+ }
}
} else {
vaddr = page_address(page) + offset;
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 7745854..839a18e 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -170,15 +170,18 @@
if (!PageHighMem(page)) {
__cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
} else {
- void *addr = kmap_high_get(page);
- if (addr) {
- __cpuc_flush_dcache_area(addr, PAGE_SIZE);
- kunmap_high(page);
- } else if (cache_is_vipt()) {
- /* unmapped pages might still be cached */
+ void *addr;
+
+ if (cache_is_vipt_nonaliasing()) {
addr = kmap_atomic(page);
__cpuc_flush_dcache_area(addr, PAGE_SIZE);
kunmap_atomic(addr);
+ } else {
+ addr = kmap_high_get(page);
+ if (addr) {
+ __cpuc_flush_dcache_area(addr, PAGE_SIZE);
+ kunmap_high(page);
+ }
}
}
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 26a06b8..770e1d6 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -715,12 +715,12 @@
if (error)
goto out_unregister;
+ klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
- klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
module_add_driver(drv->owner, drv);
error = driver_create_file(drv, &driver_attr_uevent);
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 5ad2394..b917248 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -123,7 +123,7 @@
#define LONG_IB_DETECT_REG_INDEX_START 1
#define LONG_IB_DETECT_REG_INDEX_END 5
-unsigned int ft_detect_regs[] = {
+unsigned int ft_detect_regs[FT_DETECT_REGS_COUNT] = {
A3XX_RBBM_STATUS,
REG_CP_RB_RPTR, /* LONG_IB_DETECT_REG_INDEX_START */
REG_CP_IB1_BASE,
@@ -138,8 +138,6 @@
0
};
-const unsigned int ft_detect_regs_count = ARRAY_SIZE(ft_detect_regs);
-
/*
* This is the master list of all GPU cores that are supported by this
* driver.
@@ -544,6 +542,8 @@
/* Reset the time-out in our idle timer */
mod_timer_pending(&device->idle_timer,
jiffies + device->pwrctrl.interval_timeout);
+ mod_timer_pending(&device->hang_timer,
+ (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
return result;
}
@@ -1799,6 +1799,9 @@
if (KGSL_STATE_DUMP_AND_FT != device->state)
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
+ mod_timer(&device->hang_timer,
+ (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+
adreno_perfcounter_start(adreno_dev);
device->reset_counter++;
@@ -1834,6 +1837,7 @@
device->ftbl->irqctrl(device, 0);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
del_timer_sync(&device->idle_timer);
+ del_timer_sync(&device->hang_timer);
adreno_ocmem_gmem_free(adreno_dev);
@@ -2714,6 +2718,9 @@
} else {
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
mod_timer(&device->idle_timer, jiffies + FIRST_TIMEOUT);
+ mod_timer(&device->hang_timer,
+ (jiffies +
+ msecs_to_jiffies(KGSL_TIMEOUT_PART)));
}
complete_all(&device->ft_gate);
}
@@ -2905,7 +2912,7 @@
unsigned int rbbm_status;
unsigned long wait_time;
unsigned long wait_time_part;
- unsigned int prev_reg_val[ft_detect_regs_count];
+ unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
memset(prev_reg_val, 0, sizeof(prev_reg_val));
@@ -3300,7 +3307,8 @@
unsigned int *prev_reg_val)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned int curr_reg_val[ft_detect_regs_count];
+ struct adreno_ringbuffer *rb = &adreno_dev->ringbuffer;
+ unsigned int curr_reg_val[FT_DETECT_REGS_COUNT];
unsigned int fast_hang_detected = 1;
unsigned int long_ib_detected = 1;
unsigned int i;
@@ -3320,7 +3328,9 @@
if (!(adreno_dev->ringbuffer.flags & KGSL_FLAGS_STARTED))
return 0;
- if (is_adreno_rbbm_status_idle(device)) {
+ if (is_adreno_rbbm_status_idle(device) &&
+ (kgsl_readtimestamp(device, NULL, KGSL_TIMESTAMP_RETIRED)
+ == rb->timestamp[KGSL_MEMSTORE_GLOBAL])) {
/*
* On A2XX if the RPTR != WPTR and the device is idle, then
@@ -3352,7 +3362,7 @@
msecs_to_jiffies(KGSL_TIMEOUT_PART-1));
/* Read the current Hang detect reg values here */
- for (i = 0; i < ft_detect_regs_count; i++) {
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
if (ft_detect_regs[i] == 0)
continue;
adreno_regread(device, ft_detect_regs[i],
@@ -3387,7 +3397,7 @@
"Fault tolerance no context found\n");
}
}
- for (i = 0; i < ft_detect_regs_count; i++) {
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++) {
if (curr_reg_val[i] != prev_reg_val[i]) {
fast_hang_detected = 0;
@@ -3463,55 +3473,11 @@
/* If hangs are not detected copy the current reg values
* to previous values and return no hang */
- for (i = 0; i < ft_detect_regs_count; i++)
+ for (i = 0; i < FT_DETECT_REGS_COUNT; i++)
prev_reg_val[i] = curr_reg_val[i];
return 0;
}
-/**
- * adreno_handle_hang - Process a hang detected in adreno_waittimestamp
- * @device - pointer to a KGSL device structure
- * @context - pointer to the active KGSL context
- * @timestamp - the timestamp that the process was waiting for
- *
- * Process a possible GPU hang and try fault tolerance from it
- * cleanly
- */
-static int adreno_handle_hang(struct kgsl_device *device,
- struct kgsl_context *context, unsigned int timestamp)
-{
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- unsigned int context_id = _get_context_id(context);
- unsigned int ts_issued;
- unsigned int rptr;
-
- /* Do one last check to see if we somehow made it through */
- if (kgsl_check_timestamp(device, context, timestamp))
- return 0;
-
- ts_issued = adreno_dev->ringbuffer.timestamp[context_id];
-
- adreno_regread(device, REG_CP_RB_RPTR, &rptr);
-
- /* Make sure timestamp check finished before triggering a hang */
- mb();
-
- KGSL_DRV_WARN(device,
- "Device hang detected while waiting for timestamp: "
- "<%d:0x%x>, last submitted timestamp: <%d:0x%x>, "
- "retired timestamp: <%d:0x%x>, wptr: 0x%x, rptr: 0x%x\n",
- context_id, timestamp, context_id, ts_issued, context_id,
- kgsl_readtimestamp(device, context,
- KGSL_TIMESTAMP_RETIRED),
- adreno_dev->ringbuffer.wptr, rptr);
-
- /* Return 0 after a successful fault tolerance */
- if (!adreno_dump_and_exec_ft(device))
- return 0;
-
- return -ETIMEDOUT;
-}
-
static int _check_pending_timestamp(struct kgsl_device *device,
struct kgsl_context *context, unsigned int timestamp)
{
@@ -3560,7 +3526,6 @@
struct adreno_context *adreno_ctx = context ? context->devctxt : NULL;
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
unsigned int context_id = _get_context_id(context);
- unsigned int prev_reg_val[ft_detect_regs_count];
unsigned int time_elapsed = 0;
unsigned int wait;
int ts_compare = 1;
@@ -3588,10 +3553,6 @@
context->wait_on_invalid_ts = false;
}
-
- /* Clear the registers used for hang detection */
- memset(prev_reg_val, 0, sizeof(prev_reg_val));
-
/*
* On the first time through the loop only wait 100ms.
* this gives enough time for the engine to start moving and oddly
@@ -3618,12 +3579,6 @@
break;
}
- /* Check to see if the GPU is hung */
- if (adreno_ft_detect(device, prev_reg_val)) {
- ret = adreno_handle_hang(device, context, timestamp);
- break;
- }
-
/*
* For proper power accounting sometimes we need to call
* io_wait_interruptible_timeout and sometimes we need to call
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 782209d..531a77c 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -247,6 +247,8 @@
unsigned int replay_for_snapshot;
};
+#define FT_DETECT_REGS_COUNT 12
+
/* Fault Tolerance policy flags */
#define KGSL_FT_DISABLE BIT(0)
#define KGSL_FT_REPLAY BIT(1)
@@ -285,7 +287,6 @@
extern const unsigned int a330_registers_count;
extern unsigned int ft_detect_regs[];
-extern const unsigned int ft_detect_regs_count;
int adreno_coresight_enable(struct coresight_device *csdev);
void adreno_coresight_disable(struct coresight_device *csdev);
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index d12853f..70223db 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -66,7 +66,7 @@
unsigned long wait_time;
unsigned long wait_timeout = msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);
unsigned long wait_time_part;
- unsigned int prev_reg_val[ft_detect_regs_count];
+ unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
memset(prev_reg_val, 0, sizeof(prev_reg_val));
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 1d2c341..becb4ef 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -39,6 +39,7 @@
#include "kgsl_device.h"
#include "kgsl_trace.h"
#include "kgsl_sync.h"
+#include "adreno.h"
#undef MODULE_PARAM_PREFIX
#define MODULE_PARAM_PREFIX "kgsl."
@@ -59,6 +60,54 @@
};
/**
+ * kgsl_hang_check() - Check for GPU hang
+ * data: KGSL device structure
+ *
+ * This function is called every KGSL_TIMEOUT_PART time when
+ * GPU is active to check for hang. If a hang is detected we
+ * trigger fault tolerance.
+ */
+void kgsl_hang_check(struct work_struct *work)
+{
+ struct kgsl_device *device = container_of(work, struct kgsl_device,
+ hang_check_ws);
+ static unsigned int prev_reg_val[FT_DETECT_REGS_COUNT];
+
+ mutex_lock(&device->mutex);
+
+ if (device->state == KGSL_STATE_ACTIVE) {
+
+ /* Check to see if the GPU is hung */
+ if (adreno_ft_detect(device, prev_reg_val))
+ adreno_dump_and_exec_ft(device);
+
+ mod_timer(&device->hang_timer,
+ (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
+ }
+
+ mutex_unlock(&device->mutex);
+}
+
+/**
+ * hang_timer() - Hang timer function
+ * data: KGSL device structure
+ *
+ * This function is called when hang timer expires, in this
+ * function we check if GPU is in active state and queue the
+ * work on device workqueue to check for the hang. We restart
+ * the timer after KGSL_TIMEOUT_PART time.
+ */
+void hang_timer(unsigned long data)
+{
+ struct kgsl_device *device = (struct kgsl_device *) data;
+
+ if (device->state == KGSL_STATE_ACTIVE) {
+ /* Have work run in a non-interrupt context. */
+ queue_work(device->work_queue, &device->hang_check_ws);
+ }
+}
+
+/**
* kgsl_trace_issueibcmds() - Call trace_issueibcmds by proxy
* device: KGSL device
* id: ID of the context submitting the command
@@ -550,6 +599,7 @@
/* Don't let the timer wake us during suspended sleep. */
del_timer_sync(&device->idle_timer);
+ del_timer_sync(&device->hang_timer);
switch (device->state) {
case KGSL_STATE_INIT:
break;
@@ -3292,6 +3342,7 @@
setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
+ setup_timer(&device->hang_timer, hang_timer, (unsigned long) device);
status = kgsl_create_device_workqueue(device);
if (status)
goto error_pwrctrl_close;
@@ -3371,9 +3422,7 @@
/* Disable the idle timer so we don't get interrupted */
del_timer_sync(&device->idle_timer);
- mutex_unlock(&device->mutex);
- flush_workqueue(device->work_queue);
- mutex_lock(&device->mutex);
+ del_timer_sync(&device->hang_timer);
/* Force on the clocks */
kgsl_pwrctrl_wake(device);
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 4a1f291..0983111 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -203,6 +203,7 @@
#define MMU_CONFIG 1
#endif
+void kgsl_hang_check(struct work_struct *work);
void kgsl_mem_entry_destroy(struct kref *kref);
int kgsl_postmortem_dump(struct kgsl_device *device, int manual);
diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h
index 6477cbd..94792a0 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -172,7 +172,9 @@
struct completion hwaccess_gate;
const struct kgsl_functable *ftbl;
struct work_struct idle_check_ws;
+ struct work_struct hang_check_ws;
struct timer_list idle_timer;
+ struct timer_list hang_timer;
struct kgsl_pwrctrl pwrctrl;
int open_count;
@@ -237,6 +239,8 @@
.ft_gate = COMPLETION_INITIALIZER((_dev).ft_gate),\
.idle_check_ws = __WORK_INITIALIZER((_dev).idle_check_ws,\
kgsl_idle_check),\
+ .hang_check_ws = __WORK_INITIALIZER((_dev).hang_check_ws,\
+ kgsl_hang_check),\
.ts_expired_ws = __WORK_INITIALIZER((_dev).ts_expired_ws,\
kgsl_process_events),\
.context_idr = IDR_INIT((_dev).context_idr),\
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index 847c59e..3a2345e 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -1242,6 +1242,7 @@
kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
return -EBUSY;
}
+ del_timer_sync(&device->hang_timer);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
@@ -1311,6 +1312,7 @@
case KGSL_STATE_NAP:
case KGSL_STATE_SLEEP:
del_timer_sync(&device->idle_timer);
+ del_timer_sync(&device->hang_timer);
/* make sure power is on to stop the device*/
kgsl_pwrctrl_enable(device);
device->ftbl->suspend_context(device);
@@ -1403,6 +1405,8 @@
/* Re-enable HW access */
mod_timer(&device->idle_timer,
jiffies + device->pwrctrl.interval_timeout);
+ mod_timer(&device->hang_timer,
+ (jiffies + msecs_to_jiffies(KGSL_TIMEOUT_PART)));
pm_qos_update_request(&device->pwrctrl.pm_qos_req_dma,
device->pwrctrl.pm_qos_latency);
case KGSL_STATE_ACTIVE:
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 29b269a..479b788 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2923,13 +2923,32 @@
goto err_free_mem;
}
+ if (gpio_is_valid(pdata->reset_gpio)) {
+ /* configure touchscreen reset out gpio */
+ error = gpio_request(pdata->reset_gpio, "mxt_reset_gpio");
+ if (error) {
+ dev_err(&client->dev, "unable to request gpio [%d]\n",
+ pdata->reset_gpio);
+ goto err_regulator_on;
+ }
+
+ error = gpio_direction_output(pdata->reset_gpio, 0);
+ if (error) {
+ dev_err(&client->dev,
+ "unable to set direction for gpio [%d]\n",
+ pdata->reset_gpio);
+ goto err_reset_gpio_req;
+ }
+ mxt_reset_delay(data);
+ }
+
if (pdata->power_on)
error = pdata->power_on(true);
else
error = mxt_power_on(data, true);
if (error) {
dev_err(&client->dev, "Failed to power on hardware\n");
- goto err_regulator_on;
+ goto err_reset_gpio_req;
}
if (gpio_is_valid(pdata->irq_gpio)) {
@@ -2954,20 +2973,12 @@
}
if (gpio_is_valid(pdata->reset_gpio)) {
- /* configure touchscreen reset out gpio */
- error = gpio_request(pdata->reset_gpio, "mxt_reset_gpio");
- if (error) {
- dev_err(&client->dev, "unable to request gpio [%d]\n",
- pdata->reset_gpio);
- goto err_irq_gpio_req;
- }
-
error = gpio_direction_output(pdata->reset_gpio, 1);
if (error) {
dev_err(&client->dev,
"unable to set direction for gpio [%d]\n",
pdata->reset_gpio);
- goto err_reset_gpio_req;
+ goto err_irq_gpio_req;
}
}
@@ -2982,7 +2993,7 @@
error = mxt_initialize(data);
if (error)
- goto err_reset_gpio_req;
+ goto err_irq_gpio_req;
error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
pdata->irqflags, client->dev.driver->name, data);
@@ -3036,9 +3047,6 @@
free_irq(client->irq, data);
err_free_object:
kfree(data->object_table);
-err_reset_gpio_req:
- if (gpio_is_valid(pdata->reset_gpio))
- gpio_free(pdata->reset_gpio);
err_irq_gpio_req:
if (gpio_is_valid(pdata->irq_gpio))
gpio_free(pdata->irq_gpio);
@@ -3047,6 +3055,9 @@
pdata->power_on(false);
else
mxt_power_on(data, false);
+err_reset_gpio_req:
+ if (gpio_is_valid(pdata->reset_gpio))
+ gpio_free(pdata->reset_gpio);
err_regulator_on:
if (pdata->init_hw)
pdata->init_hw(false);
diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c
index d43bfbe..efcace6 100644
--- a/drivers/input/touchscreen/ft5x06_ts.c
+++ b/drivers/input/touchscreen/ft5x06_ts.c
@@ -26,12 +26,18 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
+#include <linux/firmware.h>
+#include <linux/debugfs.h>
#include <linux/input/ft5x06_ts.h>
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+#include <linux/notifier.h>
+#include <linux/fb.h>
+
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
#include <linux/earlysuspend.h>
/* Early-suspend level */
-#define FT5X06_SUSPEND_LEVEL 1
+#define FT_SUSPEND_LEVEL 1
#endif
#define CFG_MAX_TOUCH_POINTS 5
@@ -52,26 +58,118 @@
#define POINT_READ_BUF (3 + FT_TOUCH_STEP * CFG_MAX_TOUCH_POINTS)
/*register address*/
-#define FT5X06_REG_ID 0xA3
-#define FT5X06_REG_PMODE 0xA5
-#define FT5X06_REG_FW_VER 0xA6
-#define FT5X06_REG_POINT_RATE 0x88
-#define FT5X06_REG_THGROUP 0x80
+#define FT_REG_DEV_MODE 0x00
+#define FT_DEV_MODE_REG_CAL 0x02
+#define FT_REG_ID 0xA3
+#define FT_REG_PMODE 0xA5
+#define FT_REG_FW_VER 0xA6
+#define FT_REG_POINT_RATE 0x88
+#define FT_REG_THGROUP 0x80
+#define FT_REG_ECC 0xCC
+#define FT_REG_RESET_FW 0x07
/* power register bits*/
-#define FT5X06_PMODE_ACTIVE 0x00
-#define FT5X06_PMODE_MONITOR 0x01
-#define FT5X06_PMODE_STANDBY 0x02
-#define FT5X06_PMODE_HIBERNATE 0x03
+#define FT_PMODE_ACTIVE 0x00
+#define FT_PMODE_MONITOR 0x01
+#define FT_PMODE_STANDBY 0x02
+#define FT_PMODE_HIBERNATE 0x03
+#define FT_FACTORYMODE_VALUE 0x40
+#define FT_WORKMODE_VALUE 0x00
+#define FT_RST_CMD_REG 0xFC
+#define FT_READ_ID_REG 0x90
+#define FT_ERASE_APP_REG 0x61
+#define FT_ERASE_PANEL_REG 0x63
+#define FT_FW_START_REG 0xBF
-#define FT5X06_VTG_MIN_UV 2600000
-#define FT5X06_VTG_MAX_UV 3300000
-#define FT5X06_I2C_VTG_MIN_UV 1800000
-#define FT5X06_I2C_VTG_MAX_UV 1800000
-#define FT5X06_COORDS_ARR_SIZE 4
+#define FT_VTG_MIN_UV 2600000
+#define FT_VTG_MAX_UV 3300000
+#define FT_I2C_VTG_MIN_UV 1800000
+#define FT_I2C_VTG_MAX_UV 1800000
+
+#define FT_COORDS_ARR_SIZE 4
#define MAX_BUTTONS 4
+#define FT_8BIT_SHIFT 8
+#define FT_4BIT_SHIFT 4
+#define FT_FW_NAME_MAX_LEN 50
+
+#define FT5316_ID 0x0A
+#define FT5306I_ID 0x55
+
+#define FT_UPGRADE_AA 0xAA
+#define FT_UPGRADE_55 0x55
+
+/*upgrade config of FT5606*/
+#define FT5606_UPGRADE_AA_DELAY 50
+#define FT5606_UPGRADE_55_DELAY 10
+#define FT5606_UPGRADE_ID_1 0x79
+#define FT5606_UPGRADE_ID_2 0x06
+#define FT5606_UPGRADE_READID_DELAY 100
+#define FT5606_UPGRADE_EARSE_DELAY 2000
+
+/*upgrade config of FT5316*/
+#define FT5316_UPGRADE_AA_DELAY 50
+#define FT5316_UPGRADE_55_DELAY 30
+#define FT5316_UPGRADE_ID_1 0x79
+#define FT5316_UPGRADE_ID_2 0x07
+#define FT5316_UPGRADE_READID_DELAY 1
+#define FT5316_UPGRADE_EARSE_DELAY 1500
+
+/*upgrade config of FT5x06(x=2,3,4)*/
+#define FT5X06_UPGRADE_AA_DELAY 50
+#define FT5X06_UPGRADE_55_DELAY 30
+#define FT5X06_UPGRADE_ID_1 0x79
+#define FT5X06_UPGRADE_ID_2 0x03
+#define FT5X06_UPGRADE_READID_DELAY 1
+#define FT5X06_UPGRADE_EARSE_DELAY 2000
+
+/*upgrade config of FT6208*/
+#define FT6208_UPGRADE_AA_DELAY 60
+#define FT6208_UPGRADE_55_DELAY 10
+#define FT6208_UPGRADE_ID_1 0x79
+#define FT6208_UPGRADE_ID_2 0x05
+#define FT6208_UPGRADE_READID_DELAY 10
+#define FT6208_UPGRADE_EARSE_DELAY 2000
+
+#define FT_UPGRADE_INFO(x, y) do { \
+ x->delay_55 = y##_UPGRADE_55_DELAY; \
+ x->delay_aa = y##_UPGRADE_AA_DELAY; \
+ x->upgrade_id_1 = y##_UPGRADE_ID_1; \
+ x->upgrade_id_2 = y##_UPGRADE_ID_2; \
+ x->delay_readid = y##_UPGRADE_READID_DELAY; \
+ x->delay_earse_flash = y##_UPGRADE_EARSE_DELAY; \
+ } while (0)
+
+#define FT_FW_MIN_SIZE 8
+#define FT_FW_MAX_SIZE 32768
+#define FT_FW_FILE_VER(x) ((x)->data[(x)->size - 2])
+#define FT_FW_CHECK(x) \
+ (((x)->data[(x)->size - 8] ^ (x)->data[(x)->size - 6]) == 0xFF \
+ && (((x)->data[(x)->size - 7] ^ (x)->data[(x)->size - 5]) == 0xFF \
+ && (((x)->data[(x)->size - 3] ^ (x)->data[(x)->size - 4]) == 0xFF)))
+
+#define FT_MAX_TRIES 5
+#define FT_RETRY_DLY 20
+
+#define FT_MAX_WR_BUF 10
+#define FT_MAX_RD_BUF 2
+#define FT_FW_PKT_LEN 128
+#define FT_FW_PKT_META_LEN 6
+#define FT_FW_PKT_DLY_MS 20
+#define FT_FW_LAST_PKT 0x6ffa
+#define FT_EARSE_DLY_MS 100
+
+#define FT_UPGRADE_LOOP 3
+#define FT_CAL_START 0x04
+#define FT_CAL_FIN 0x00
+#define FT_CAL_STORE 0x05
+#define FT_CAL_RETRY 100
+#define FT_REG_CAL 0x00
+#define FT_CAL_MASK 0x70
+
+#define FT_DEBUG_DIR_NAME "ft_debug"
+
struct ts_event {
u16 x[CFG_MAX_TOUCH_POINTS]; /*x coordinate */
u16 y[CFG_MAX_TOUCH_POINTS]; /*y coordinate */
@@ -82,6 +180,15 @@
u8 touch_point;
};
+struct upgrade_info {
+ u16 delay_aa; /*delay of write FT_UPGRADE_AA */
+ u16 delay_55; /*delay of write FT_UPGRADE_55 */
+ u8 upgrade_id_1; /*upgrade id 1 */
+ u8 upgrade_id_2; /*upgrade id 2 */
+ u16 delay_readid; /*delay of read id */
+ u16 delay_earse_flash; /*delay of earse flash*/
+};
+
struct ft5x06_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
@@ -89,7 +196,15 @@
const struct ft5x06_ts_platform_data *pdata;
struct regulator *vdd;
struct regulator *vcc_i2c;
-#ifdef CONFIG_HAS_EARLYSUSPEND
+ char fw_name[FT_FW_NAME_MAX_LEN];
+ bool loading_fw;
+ u8 family_id;
+ struct dentry *dir;
+ u16 addr;
+ bool suspended;
+#if defined(CONFIG_FB)
+ struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
struct early_suspend early_suspend;
#endif
};
@@ -154,6 +269,21 @@
return ret;
}
+static int ft5x0x_write_reg(struct i2c_client *client, u8 addr, const u8 val)
+{
+ u8 buf[2] = {0};
+
+ buf[0] = addr;
+ buf[1] = val;
+
+ return ft5x06_i2c_write(client, buf, sizeof(buf));
+}
+
+static int ft5x0x_read_reg(struct i2c_client *client, u8 addr, u8 *val)
+{
+ return ft5x06_i2c_read(client, &addr, 1, val, 1);
+}
+
static void ft5x06_report_value(struct ft5x06_ts_data *data)
{
struct ts_event *event = &data->event;
@@ -293,8 +423,8 @@
}
if (regulator_count_voltages(data->vdd) > 0) {
- rc = regulator_set_voltage(data->vdd, FT5X06_VTG_MIN_UV,
- FT5X06_VTG_MAX_UV);
+ rc = regulator_set_voltage(data->vdd, FT_VTG_MIN_UV,
+ FT_VTG_MAX_UV);
if (rc) {
dev_err(&data->client->dev,
"Regulator set_vtg failed vdd rc=%d\n", rc);
@@ -311,8 +441,8 @@
}
if (regulator_count_voltages(data->vcc_i2c) > 0) {
- rc = regulator_set_voltage(data->vcc_i2c, FT5X06_I2C_VTG_MIN_UV,
- FT5X06_I2C_VTG_MAX_UV);
+ rc = regulator_set_voltage(data->vcc_i2c, FT_I2C_VTG_MIN_UV,
+ FT_I2C_VTG_MAX_UV);
if (rc) {
dev_err(&data->client->dev,
"Regulator set_vtg failed vcc_i2c rc=%d\n", rc);
@@ -326,19 +456,19 @@
regulator_put(data->vcc_i2c);
reg_vdd_set_vtg:
if (regulator_count_voltages(data->vdd) > 0)
- regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV);
+ regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV);
reg_vdd_put:
regulator_put(data->vdd);
return rc;
pwr_deinit:
if (regulator_count_voltages(data->vdd) > 0)
- regulator_set_voltage(data->vdd, 0, FT5X06_VTG_MAX_UV);
+ regulator_set_voltage(data->vdd, 0, FT_VTG_MAX_UV);
regulator_put(data->vdd);
if (regulator_count_voltages(data->vcc_i2c) > 0)
- regulator_set_voltage(data->vcc_i2c, 0, FT5X06_I2C_VTG_MAX_UV);
+ regulator_set_voltage(data->vcc_i2c, 0, FT_I2C_VTG_MAX_UV);
regulator_put(data->vcc_i2c);
return 0;
@@ -350,14 +480,26 @@
struct ft5x06_ts_data *data = dev_get_drvdata(dev);
char txbuf[2];
+ if (data->loading_fw) {
+ dev_info(dev, "Firmware loading in process...\n");
+ return 0;
+ }
+
+ if (data->suspended) {
+ dev_info(dev, "Already in suspend state\n");
+ return 0;
+ }
+
disable_irq(data->client->irq);
if (gpio_is_valid(data->pdata->reset_gpio)) {
- txbuf[0] = FT5X06_REG_PMODE;
- txbuf[1] = FT5X06_PMODE_HIBERNATE;
+ txbuf[0] = FT_REG_PMODE;
+ txbuf[1] = FT_PMODE_HIBERNATE;
ft5x06_i2c_write(data->client, txbuf, sizeof(txbuf));
}
+ data->suspended = true;
+
return 0;
}
@@ -365,6 +507,11 @@
{
struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+ if (!data->suspended) {
+ dev_info(dev, "Already in awake state\n");
+ return 0;
+ }
+
if (gpio_is_valid(data->pdata->reset_gpio)) {
gpio_set_value_cansleep(data->pdata->reset_gpio, 0);
msleep(FT_RESET_DLY);
@@ -372,10 +519,32 @@
}
enable_irq(data->client->irq);
+ data->suspended = false;
+
return 0;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
+#if defined(CONFIG_FB)
+static int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+ struct ft5x06_ts_data *ft5x06_data =
+ container_of(self, struct ft5x06_ts_data, fb_notif);
+
+ if (evdata && evdata->data && event == FB_EVENT_BLANK &&
+ ft5x06_data && ft5x06_data->client) {
+ blank = evdata->data;
+ if (*blank == FB_BLANK_UNBLANK)
+ ft5x06_ts_resume(&ft5x06_data->client->dev);
+ else if (*blank == FB_BLANK_POWERDOWN)
+ ft5x06_ts_suspend(&ft5x06_data->client->dev);
+ }
+
+ return 0;
+}
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
static void ft5x06_ts_early_suspend(struct early_suspend *handler)
{
struct ft5x06_ts_data *data = container_of(handler,
@@ -396,18 +565,461 @@
#endif
static const struct dev_pm_ops ft5x06_ts_pm_ops = {
-#ifndef CONFIG_HAS_EARLYSUSPEND
+#if (!defined(CONFIG_FB) && !defined(CONFIG_HAS_EARLYSUSPEND))
.suspend = ft5x06_ts_suspend,
.resume = ft5x06_ts_resume,
#endif
};
#endif
+static int ft5x06_auto_cal(struct i2c_client *client)
+{
+ u8 temp = 0, i;
+
+ /* set to factory mode */
+ msleep(2 * FT_STARTUP_DLY);
+ ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
+ msleep(FT_STARTUP_DLY);
+
+ /* start calibration */
+ ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_START);
+ msleep(2 * FT_STARTUP_DLY);
+ for (i = 0; i < FT_CAL_RETRY; i++) {
+ ft5x0x_read_reg(client, FT_REG_CAL, &temp);
+ /*return to normal mode, calibration finish */
+ if (((temp & FT_CAL_MASK) >> FT_4BIT_SHIFT) == FT_CAL_FIN)
+ break;
+ }
+
+ /*calibration OK */
+ msleep(2 * FT_STARTUP_DLY);
+ ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_FACTORYMODE_VALUE);
+ msleep(FT_STARTUP_DLY);
+
+ /* store calibration data */
+ ft5x0x_write_reg(client, FT_DEV_MODE_REG_CAL, FT_CAL_STORE);
+ msleep(2 * FT_STARTUP_DLY);
+
+ /* set to normal mode */
+ ft5x0x_write_reg(client, FT_REG_DEV_MODE, FT_WORKMODE_VALUE);
+ msleep(2 * FT_STARTUP_DLY);
+
+ return 0;
+}
+
+static int ft5x06_get_upgrade_info(u8 family_id, struct upgrade_info *info)
+{
+ switch (family_id) {
+ case FT5306I_ID:
+ FT_UPGRADE_INFO(info, FT5X06);
+ break;
+ case FT5316_ID:
+ FT_UPGRADE_INFO(info, FT5316);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ft5x06_fw_upgrade_start(struct i2c_client *client,
+ const u8 *data, u32 data_len)
+{
+ struct ft5x06_ts_data *ts_data = i2c_get_clientdata(client);
+ struct upgrade_info info;
+ u8 w_buf[FT_MAX_WR_BUF] = {0}, r_buf[FT_MAX_RD_BUF] = {0};
+ u8 pkt_buf[FT_FW_PKT_LEN + FT_FW_PKT_META_LEN];
+ int rc, i, j, temp;
+ u32 pkt_num, pkt_len;
+ u8 fw_ecc;
+
+ rc = ft5x06_get_upgrade_info(ts_data->family_id, &info);
+ if (rc < 0) {
+ dev_err(&client->dev, "Cannot get upgrade information!\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < FT_UPGRADE_LOOP; i++) {
+ /* reset - write 0xaa and 0x55 to register 0xfc */
+ ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_AA);
+ msleep(info.delay_aa);
+
+ ft5x0x_write_reg(client, FT_RST_CMD_REG, FT_UPGRADE_55);
+ msleep(info.delay_55);
+
+ /* Enter upgrade mode */
+ w_buf[0] = FT_UPGRADE_55;
+ w_buf[1] = FT_UPGRADE_AA;
+ do {
+ i++;
+ rc = ft5x06_i2c_write(client, w_buf, 2);
+ msleep(FT_RETRY_DLY);
+ } while (rc <= 0 && i < FT_MAX_TRIES);
+
+ /* check READ_ID */
+ msleep(info.delay_readid);
+ w_buf[0] = FT_READ_ID_REG;
+ w_buf[1] = 0x00;
+ w_buf[2] = 0x00;
+ w_buf[3] = 0x00;
+
+ ft5x06_i2c_read(client, w_buf, 4, r_buf, 2);
+
+ if (r_buf[0] != info.upgrade_id_1
+ || r_buf[1] != info.upgrade_id_2) {
+ dev_err(&client->dev, "Upgrade ID mismatch(%d)\n", i);
+ } else
+ break;
+ }
+
+ if (i >= FT_UPGRADE_LOOP) {
+ dev_err(&client->dev, "Abort upgrade\n");
+ return -EIO;
+ }
+
+ /* erase app and panel paramenter area */
+ w_buf[0] = FT_ERASE_APP_REG;
+ ft5x06_i2c_write(client, w_buf, 1);
+ msleep(info.delay_earse_flash);
+
+ w_buf[0] = FT_ERASE_PANEL_REG;
+ ft5x06_i2c_write(client, w_buf, 1);
+ msleep(FT_EARSE_DLY_MS);
+
+ /* program firmware */
+ data_len = data_len - 8;
+ pkt_num = (data_len) / FT_FW_PKT_LEN;
+ pkt_len = FT_FW_PKT_LEN;
+ pkt_buf[0] = FT_FW_START_REG;
+ pkt_buf[1] = 0x00;
+ fw_ecc = 0;
+
+ for (i = 0; i < pkt_num; i++) {
+ temp = i * FT_FW_PKT_LEN;
+ pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT);
+ pkt_buf[3] = (u8) temp;
+ pkt_buf[4] = (u8) (pkt_len >> FT_8BIT_SHIFT);
+ pkt_buf[5] = (u8) pkt_len;
+
+ for (j = 0; j < FT_FW_PKT_LEN; j++) {
+ pkt_buf[6 + j] = data[i * FT_FW_PKT_LEN + j];
+ fw_ecc ^= pkt_buf[6 + j];
+ }
+
+ ft5x06_i2c_write(client, pkt_buf,
+ FT_FW_PKT_LEN + FT_FW_PKT_META_LEN);
+ msleep(FT_FW_PKT_DLY_MS);
+ }
+
+ /* send remaining bytes */
+ if ((data_len) % FT_FW_PKT_LEN > 0) {
+ temp = pkt_num * FT_FW_PKT_LEN;
+ pkt_buf[2] = (u8) (temp >> FT_8BIT_SHIFT);
+ pkt_buf[3] = (u8) temp;
+ temp = (data_len) % FT_FW_PKT_LEN;
+ pkt_buf[4] = (u8) (temp >> FT_8BIT_SHIFT);
+ pkt_buf[5] = (u8) temp;
+
+ for (i = 0; i < temp; i++) {
+ pkt_buf[6 + i] = data[pkt_num * FT_FW_PKT_LEN + i];
+ fw_ecc ^= pkt_buf[6 + i];
+ }
+
+ ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
+ msleep(FT_FW_PKT_DLY_MS);
+ }
+
+ /* send the finishing packet */
+ for (i = 0; i < 6; i++) {
+ temp = FT_FW_LAST_PKT + i;
+ pkt_buf[2] = (u8) (temp >> 8);
+ pkt_buf[3] = (u8) temp;
+ temp = 1;
+ pkt_buf[4] = (u8) (temp >> 8);
+ pkt_buf[5] = (u8) temp;
+ pkt_buf[6] = data[data_len + i];
+ fw_ecc ^= pkt_buf[6];
+ ft5x06_i2c_write(client, pkt_buf, temp + FT_FW_PKT_META_LEN);
+ msleep(FT_FW_PKT_DLY_MS);
+ }
+
+ /* verify checksum */
+ w_buf[0] = FT_REG_ECC;
+ ft5x06_i2c_read(client, w_buf, 1, r_buf, 1);
+ if (r_buf[0] != fw_ecc) {
+ dev_err(&client->dev, "ECC error! dev_ecc=%02x fw_ecc=%02x\n",
+ r_buf[0], fw_ecc);
+ return -EIO;
+ }
+
+ /* reset */
+ w_buf[0] = FT_REG_RESET_FW;
+ ft5x06_i2c_write(client, w_buf, 1);
+ msleep(FT_STARTUP_DLY);
+
+ return 0;
+}
+
+static int ft5x06_fw_upgrade(struct device *dev, bool force)
+{
+ struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+ const struct firmware *fw = NULL;
+ int rc;
+ u8 val = 0;
+
+ rc = request_firmware(&fw, data->fw_name, dev);
+ if (rc < 0) {
+ dev_err(dev, "Request firmware failed - %s (%d)\n",
+ data->fw_name, rc);
+ return rc;
+ }
+
+ if (fw->size < FT_FW_MIN_SIZE || fw->size > FT_FW_MAX_SIZE) {
+ dev_err(dev, "Invalid firmware size (%d)\n", fw->size);
+ rc = -EIO;
+ goto rel_fw;
+ }
+
+ /* check firmware version */
+ rc = ft5x0x_read_reg(data->client, FT_REG_FW_VER, &val);
+ if (rc < 0) {
+ dev_err(dev, "Get firmware version failed\n");
+ goto rel_fw;
+ }
+
+ if (val == FT_FW_FILE_VER(fw) && !force) {
+ dev_err(dev, "No need to update (0x%x)\n", val);
+ rc = -EFAULT;
+ goto rel_fw;
+ }
+
+ dev_info(dev, "upgrade to fw ver 0x%x from 0x%x\n",
+ FT_FW_FILE_VER(fw), val);
+
+ /* start firmware upgrade */
+ if (FT_FW_CHECK(fw)) {
+ rc = ft5x06_fw_upgrade_start(data->client, fw->data, fw->size);
+ if (rc < 0)
+ dev_err(dev, "update failed (%d)\n", rc);
+ else
+ ft5x06_auto_cal(data->client);
+ } else {
+ dev_err(dev, "FW format error\n");
+ rc = -EIO;
+ }
+
+rel_fw:
+ release_firmware(fw);
+ return rc;
+}
+
+static ssize_t ft5x06_update_fw_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+ return snprintf(buf, 2, "%d\n", data->loading_fw);
+}
+
+static ssize_t ft5x06_update_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int rc;
+
+ if (size > 2)
+ return -EINVAL;
+
+ rc = kstrtoul(buf, 10, &val);
+ if (rc != 0)
+ return rc;
+
+ mutex_lock(&data->input_dev->mutex);
+ if (!data->loading_fw && val) {
+ data->loading_fw = true;
+ ft5x06_fw_upgrade(dev, false);
+ data->loading_fw = false;
+ }
+ mutex_unlock(&data->input_dev->mutex);
+
+ return size;
+}
+
+static DEVICE_ATTR(update_fw, 0664, ft5x06_update_fw_show,
+ ft5x06_update_fw_store);
+
+static ssize_t ft5x06_force_update_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int rc;
+
+ if (size > 2)
+ return -EINVAL;
+
+ rc = kstrtoul(buf, 10, &val);
+ if (rc != 0)
+ return rc;
+
+ mutex_lock(&data->input_dev->mutex);
+ if (!data->loading_fw && val) {
+ data->loading_fw = true;
+ ft5x06_fw_upgrade(dev, true);
+ data->loading_fw = false;
+ }
+ mutex_unlock(&data->input_dev->mutex);
+
+ return size;
+}
+
+static DEVICE_ATTR(force_update_fw, 0664, ft5x06_update_fw_show,
+ ft5x06_force_update_fw_store);
+
+static ssize_t ft5x06_fw_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+ return snprintf(buf, FT_FW_NAME_MAX_LEN - 1, "%s\n", data->fw_name);
+}
+
+static ssize_t ft5x06_fw_name_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ struct ft5x06_ts_data *data = dev_get_drvdata(dev);
+
+ if (size > FT_FW_NAME_MAX_LEN - 1)
+ return -EINVAL;
+
+ strlcpy(data->fw_name, buf, size);
+ if (data->fw_name[size-1] == '\n')
+ data->fw_name[size-1] = 0;
+
+ return size;
+}
+
+static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store);
+
+static bool ft5x06_debug_addr_is_valid(int addr)
+{
+ if (addr < 0 || addr > 0xFF) {
+ pr_err("FT reg address is invalid: 0x%x\n", addr);
+ return false;
+ }
+
+ return true;
+}
+
+static int ft5x06_debug_data_set(void *_data, u64 val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (ft5x06_debug_addr_is_valid(data->addr))
+ dev_info(&data->client->dev,
+ "Writing into FT registers not supported\n");
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+static int ft5x06_debug_data_get(void *_data, u64 *val)
+{
+ struct ft5x06_ts_data *data = _data;
+ int rc;
+ u8 reg;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (ft5x06_debug_addr_is_valid(data->addr)) {
+ rc = ft5x0x_read_reg(data->client, data->addr, ®);
+ if (rc < 0)
+ dev_err(&data->client->dev,
+ "FT read register 0x%x failed (%d)\n",
+ data->addr, rc);
+ else
+ *val = reg;
+ }
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_data_fops, ft5x06_debug_data_get,
+ ft5x06_debug_data_set, "0x%02llX\n");
+
+static int ft5x06_debug_addr_set(void *_data, u64 val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ if (ft5x06_debug_addr_is_valid(val)) {
+ mutex_lock(&data->input_dev->mutex);
+ data->addr = val;
+ mutex_unlock(&data->input_dev->mutex);
+ }
+
+ return 0;
+}
+
+static int ft5x06_debug_addr_get(void *_data, u64 *val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (ft5x06_debug_addr_is_valid(data->addr))
+ *val = data->addr;
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_addr_fops, ft5x06_debug_addr_get,
+ ft5x06_debug_addr_set, "0x%02llX\n");
+
+static int ft5x06_debug_suspend_set(void *_data, u64 val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+
+ if (val)
+ ft5x06_ts_suspend(&data->client->dev);
+ else
+ ft5x06_ts_resume(&data->client->dev);
+
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+static int ft5x06_debug_suspend_get(void *_data, u64 *val)
+{
+ struct ft5x06_ts_data *data = _data;
+
+ mutex_lock(&data->input_dev->mutex);
+ *val = data->suspended;
+ mutex_unlock(&data->input_dev->mutex);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_suspend_fops, ft5x06_debug_suspend_get,
+ ft5x06_debug_suspend_set, "%lld\n");
+
#ifdef CONFIG_OF
static int ft5x06_get_dt_coords(struct device *dev, char *name,
struct ft5x06_ts_platform_data *pdata)
{
- u32 coords[FT5X06_COORDS_ARR_SIZE];
+ u32 coords[FT_COORDS_ARR_SIZE];
struct property *prop;
struct device_node *np = dev->of_node;
int coords_size, rc;
@@ -419,7 +1031,7 @@
return -ENODATA;
coords_size = prop->length / sizeof(u32);
- if (coords_size != FT5X06_COORDS_ARR_SIZE) {
+ if (coords_size != FT_COORDS_ARR_SIZE) {
dev_err(dev, "invalid %s\n", name);
return -EINVAL;
}
@@ -518,6 +1130,7 @@
struct ft5x06_ts_platform_data *pdata;
struct ft5x06_ts_data *data;
struct input_dev *input_dev;
+ struct dentry *dir, *temp;
u8 reg_value;
u8 reg_addr;
int err;
@@ -653,37 +1266,43 @@
msleep(FT_STARTUP_DLY);
/* check the controller id */
- reg_addr = FT5X06_REG_ID;
+ reg_addr = FT_REG_ID;
err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
if (err < 0) {
dev_err(&client->dev, "version read failed");
return err;
}
+ dev_info(&client->dev, "Device ID = 0x%x\n", reg_value);
+
if (pdata->family_id != reg_value) {
dev_err(&client->dev, "%s:Unsupported controller\n", __func__);
goto free_reset_gpio;
}
+ data->family_id = reg_value;
+
/*get some register information */
- reg_addr = FT5X06_REG_FW_VER;
+ reg_addr = FT_REG_FW_VER;
err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
- if (err)
+ if (err < 0)
dev_err(&client->dev, "version read failed");
- dev_info(&client->dev, "[FTS] Firmware version = 0x%x\n", reg_value);
+ dev_info(&client->dev, "Firmware version = 0x%x\n", reg_value);
- reg_addr = FT5X06_REG_POINT_RATE;
+ reg_addr = FT_REG_POINT_RATE;
ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
- if (err)
+ if (err < 0)
dev_err(&client->dev, "report rate read failed");
- dev_info(&client->dev, "[FTS] report rate is %dHz.\n", reg_value * 10);
- reg_addr = FT5X06_REG_THGROUP;
+ dev_info(&client->dev, "report rate = %dHz\n", reg_value * 10);
+
+ reg_addr = FT_REG_THGROUP;
err = ft5x06_i2c_read(client, ®_addr, 1, ®_value, 1);
- if (err)
+ if (err < 0)
dev_err(&client->dev, "threshold read failed");
- dev_dbg(&client->dev, "[FTS] touch threshold is %d.\n", reg_value * 4);
+
+ dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4);
err = request_threaded_irq(client->irq, NULL,
ft5x06_ts_interrupt, pdata->irqflags,
@@ -693,9 +1312,66 @@
goto free_reset_gpio;
}
-#ifdef CONFIG_HAS_EARLYSUSPEND
+ err = device_create_file(&client->dev, &dev_attr_fw_name);
+ if (err) {
+ dev_err(&client->dev, "sys file creation failed\n");
+ goto irq_free;
+ }
+
+ err = device_create_file(&client->dev, &dev_attr_update_fw);
+ if (err) {
+ dev_err(&client->dev, "sys file creation failed\n");
+ goto free_fw_name_sys;
+ }
+
+ err = device_create_file(&client->dev, &dev_attr_force_update_fw);
+ if (err) {
+ dev_err(&client->dev, "sys file creation failed\n");
+ goto free_update_fw_sys;
+ }
+
+ dir = debugfs_create_dir(FT_DEBUG_DIR_NAME, NULL);
+ if (dir == NULL || IS_ERR(dir)) {
+ pr_err("debugfs_create_dir failed: rc=%ld\n", PTR_ERR(dir));
+ err = PTR_ERR(dir);
+ goto free_force_update_fw_sys;
+ }
+
+ temp = debugfs_create_file("addr", S_IRUSR | S_IWUSR, dir, data,
+ &debug_addr_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ err = PTR_ERR(temp);
+ goto free_debug_dir;
+ }
+
+ temp = debugfs_create_file("data", S_IRUSR | S_IWUSR, dir, data,
+ &debug_data_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ err = PTR_ERR(temp);
+ goto free_debug_dir;
+ }
+
+ temp = debugfs_create_file("suspend", S_IRUSR | S_IWUSR, dir, data,
+ &debug_suspend_fops);
+ if (temp == NULL || IS_ERR(temp)) {
+ pr_err("debugfs_create_file failed: rc=%ld\n", PTR_ERR(temp));
+ err = PTR_ERR(temp);
+ goto free_debug_dir;
+ }
+
+#if defined(CONFIG_FB)
+ data->fb_notif.notifier_call = fb_notifier_callback;
+
+ err = fb_register_client(&data->fb_notif);
+
+ if (err)
+ dev_err(&client->dev, "Unable to register fb_notifier: %d\n",
+ err);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
data->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN +
- FT5X06_SUSPEND_LEVEL;
+ FT_SUSPEND_LEVEL;
data->early_suspend.suspend = ft5x06_ts_early_suspend;
data->early_suspend.resume = ft5x06_ts_late_resume;
register_early_suspend(&data->early_suspend);
@@ -703,12 +1379,22 @@
return 0;
+free_debug_dir:
+ debugfs_remove_recursive(data->dir);
+free_force_update_fw_sys:
+ device_remove_file(&client->dev, &dev_attr_force_update_fw);
+free_update_fw_sys:
+ device_remove_file(&client->dev, &dev_attr_update_fw);
+free_fw_name_sys:
+ device_remove_file(&client->dev, &dev_attr_fw_name);
+irq_free:
+ free_irq(client->irq, data);
free_reset_gpio:
if (gpio_is_valid(pdata->reset_gpio))
gpio_free(pdata->reset_gpio);
free_irq_gpio:
if (gpio_is_valid(pdata->irq_gpio))
- gpio_free(pdata->reset_gpio);
+ gpio_free(pdata->irq_gpio);
pwr_off:
if (pdata->power_on)
pdata->power_on(false);
@@ -733,7 +1419,15 @@
{
struct ft5x06_ts_data *data = i2c_get_clientdata(client);
-#ifdef CONFIG_HAS_EARLYSUSPEND
+ debugfs_remove_recursive(data->dir);
+ device_remove_file(&client->dev, &dev_attr_force_update_fw);
+ device_remove_file(&client->dev, &dev_attr_update_fw);
+ device_remove_file(&client->dev, &dev_attr_fw_name);
+
+#if defined(CONFIG_FB)
+ if (fb_unregister_client(&data->fb_notif))
+ dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n");
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
unregister_early_suspend(&data->early_suspend);
#endif
free_irq(client->irq, data);
@@ -742,7 +1436,7 @@
gpio_free(data->pdata->reset_gpio);
if (gpio_is_valid(data->pdata->irq_gpio))
- gpio_free(data->pdata->reset_gpio);
+ gpio_free(data->pdata->irq_gpio);
if (data->pdata->power_on)
data->pdata->power_on(false);
diff --git a/drivers/input/touchscreen/synaptics_fw_update.c b/drivers/input/touchscreen/synaptics_fw_update.c
index d51481f..349b020 100644
--- a/drivers/input/touchscreen/synaptics_fw_update.c
+++ b/drivers/input/touchscreen/synaptics_fw_update.c
@@ -304,10 +304,10 @@
};
static struct device_attribute attrs[] = {
- __ATTR(forceflash, S_IWUGO,
+ __ATTR(force_update_fw, S_IWUGO,
synaptics_rmi4_show_error,
fwu_sysfs_force_reflash_store),
- __ATTR(doreflash, S_IWUGO,
+ __ATTR(update_fw, S_IWUGO,
synaptics_rmi4_show_error,
fwu_sysfs_do_reflash_store),
__ATTR(writeconfig, S_IWUGO,
diff --git a/drivers/leds/leds-pm8xxx.c b/drivers/leds/leds-pm8xxx.c
index c3a5564..aef6295 100644
--- a/drivers/leds/leds-pm8xxx.c
+++ b/drivers/leds/leds-pm8xxx.c
@@ -133,6 +133,11 @@
_rgb_led_blue << PM8XXX_ID_RGB_LED_BLUE, \
}
+#define PM8XXX_PWM_CURRENT_4MA 4
+#define PM8XXX_PWM_CURRENT_8MA 8
+#define PM8XXX_PWM_CURRENT_12MA 12
+
+
/**
* supported_leds - leds supported for each PMIC version
* @version - version of PMIC
@@ -795,7 +800,7 @@
static int pm8xxx_led_pwm_configure(struct pm8xxx_led_data *led)
{
- int start_idx, idx_len, duty_us, rc;
+ int start_idx, idx_len, duty_us, rc, flags;
led->pwm_dev = pwm_request(led->pwm_channel,
led->cdev.name);
@@ -808,6 +813,22 @@
return -ENODEV;
}
+ flags = PM8XXX_LED_PWM_FLAGS;
+ switch (led->max_current) {
+ case PM8XXX_PWM_CURRENT_4MA:
+ flags |= PM_PWM_BANK_LO;
+ break;
+ case PM8XXX_PWM_CURRENT_8MA:
+ flags |= PM_PWM_BANK_HI;
+ break;
+ case PM8XXX_PWM_CURRENT_12MA:
+ flags |= (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
+ break;
+ default:
+ flags |= (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
+ break;
+ }
+
if (led->pwm_duty_cycles != NULL) {
start_idx = led->pwm_duty_cycles->start_idx;
idx_len = led->pwm_duty_cycles->num_duty_pcts;
@@ -825,7 +846,7 @@
led->pwm_duty_cycles->duty_pcts,
led->pwm_duty_cycles->duty_ms,
start_idx, idx_len, 0, 0,
- PM8XXX_LED_PWM_FLAGS);
+ flags);
} else {
duty_us = led->pwm_period_us;
rc = pwm_config(led->pwm_dev, duty_us, led->pwm_period_us);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
index 1c146d0..84ba4d1 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <mach/iommu.h>
+#include <linux/ratelimit.h>
#include "msm_isp40.h"
#include "msm_isp_util.h"
@@ -496,10 +497,15 @@
*irq_status0 = msm_camera_io_r(vfe_dev->vfe_base + 0x38);
*irq_status1 = msm_camera_io_r(vfe_dev->vfe_base + 0x3C);
/*Ignore composite 3 irq which is used for dual VFE only*/
- *irq_status0 &= ~BIT(28);
+ if (*irq_status0 & 0x6000000)
+ *irq_status0 &= ~(0x10000000);
msm_camera_io_w(*irq_status0, vfe_dev->vfe_base + 0x30);
msm_camera_io_w(*irq_status1, vfe_dev->vfe_base + 0x34);
msm_camera_io_w_mb(1, vfe_dev->vfe_base + 0x24);
+ if (*irq_status0 & 0x10000000) {
+ pr_err_ratelimited("%s: Protection triggered\n", __func__);
+ *irq_status0 &= ~(0x10000000);
+ }
if (*irq_status1 & (1 << 0))
vfe_dev->error_info.camif_status =
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
index f470d36..d3138ed 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
@@ -97,6 +97,8 @@
case V4L2_PIX_FMT_QGBRG12:
case V4L2_PIX_FMT_QGRBG12:
case V4L2_PIX_FMT_QRGGB12:
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_META:
stream_info->num_planes = 1;
stream_info->format_factor = ISP_Q2;
break;
@@ -165,6 +167,8 @@
case V4L2_PIX_FMT_QGBRG8:
case V4L2_PIX_FMT_QGRBG8:
case V4L2_PIX_FMT_QRGGB8:
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_META:
size = plane_cfg[plane_idx].output_height *
plane_cfg[plane_idx].output_width;
break;
@@ -549,9 +553,9 @@
}
if (stream_info->num_planes > 1) {
- msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info);
vfe_dev->hw_info->vfe_ops.axi_ops.
- clear_comp_mask(vfe_dev, stream_info);
+ clear_comp_mask(vfe_dev, stream_info);
+ msm_isp_axi_free_comp_mask(&vfe_dev->axi_data, stream_info);
} else {
vfe_dev->hw_info->vfe_ops.axi_ops.
clear_wm_irq_mask(vfe_dev, stream_info);
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
index ac44c61..908d3c6 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c
@@ -619,6 +619,8 @@
case V4L2_PIX_FMT_QGBRG8:
case V4L2_PIX_FMT_QGRBG8:
case V4L2_PIX_FMT_QRGGB8:
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_META:
val = CAL_WORD(pixel_per_line, 1, 8);
break;
case V4L2_PIX_FMT_SBGGR10:
@@ -672,6 +674,8 @@
case V4L2_PIX_FMT_QGBRG8:
case V4L2_PIX_FMT_QGRBG8:
case V4L2_PIX_FMT_QRGGB8:
+ case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_META:
return 8;
case V4L2_PIX_FMT_SBGGR10:
case V4L2_PIX_FMT_SGBRG10:
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index dc1bcc3..3082e99 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -55,7 +55,7 @@
static inline int msm_ispif_is_intf_valid(uint32_t csid_version,
uint8_t intf_type)
{
- return (csid_version <= CSID_VERSION_V2 && intf_type != VFE0) ?
+ return (csid_version <= CSID_VERSION_V22 && intf_type != VFE0) ?
false : true;
}
@@ -67,7 +67,7 @@
{
int rc = 0;
- if (ispif->csid_version < CSID_VERSION_V3) {
+ if (ispif->csid_version < CSID_VERSION_V30) {
/* Older ISPIF versiond don't need ahb clokc */
return 0;
}
@@ -407,14 +407,14 @@
if ((intftype >= INTF_MAX) ||
(vfe_intf >= ispif->vfe_info.num_vfe) ||
- (ispif->csid_version <= CSID_VERSION_V2 &&
+ (ispif->csid_version <= CSID_VERSION_V22 &&
(vfe_intf > VFE0))) {
pr_err("%s: VFEID %d and CSID version %d mismatch\n",
__func__, vfe_intf, ispif->csid_version);
return -EINVAL;
}
- if (ispif->csid_version >= CSID_VERSION_V3)
+ if (ispif->csid_version >= CSID_VERSION_V30)
msm_ispif_select_clk_mux(ispif, intftype,
params->entries[i].csid, vfe_intf);
@@ -488,7 +488,7 @@
vfe_intf = params->entries[i].vfe_intf;
for (k = 0; k < params->entries[i].num_cids; k++) {
cid = params->entries[i].cids[k];
- vc = cid % 4;
+ vc = cid / 4;
if (intf_type == RDI2) {
/* zero out two bits */
ispif->applied_intf_cmd[vfe_intf].intf_cmd1 &=
@@ -776,7 +776,7 @@
ispif->csid_version = csid_version;
- if (ispif->csid_version >= CSID_VERSION_V3) {
+ if (ispif->csid_version >= CSID_VERSION_V30) {
if (!ispif->clk_mux_mem || !ispif->clk_mux_io) {
pr_err("%s csi clk mux mem %p io %p\n", __func__,
ispif->clk_mux_mem, ispif->clk_mux_io);
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
index 6396486..c8a4366 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_hwreg_v1.h
@@ -103,4 +103,5 @@
#define ISPIF_IRQ_GLOBAL_CLEAR_CMD 0x000001
+#define ISPIF_STOP_INTF_IMMEDIATELY 0xAAAAAAAA
#endif /* __MSM_ISPIF_HWREG_V1_H__ */
diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
index 8b96227..7a06c00 100644
--- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
+++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c
@@ -228,6 +228,7 @@
fail_1:
__msm_jpeg_exit(msm_jpeg_device_p);
+ return rc;
fail:
kfree(msm_jpeg_device_p);
diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 4f02197..e74f1082 100644
--- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
+++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
@@ -1013,6 +1013,7 @@
struct msm_cpp_frame_info_t *u_frame_info =
(struct msm_cpp_frame_info_t *)ioctl_ptr->ioctl_ptr;
int32_t status = 0;
+ uint8_t fw_version_1_2_x = 0;
int i = 0;
if (!new_frame) {
@@ -1117,12 +1118,21 @@
((cpp_frame_msg[12] >> 10) & 0x3FF) +
(cpp_frame_msg[12] & 0x3FF);
+ fw_version_1_2_x = 0;
+ if (cpp_dev->hw_info.cpp_hw_version == 0x10010000)
+ fw_version_1_2_x = 2;
+
for (i = 0; i < num_stripes; i++) {
- cpp_frame_msg[133 + i * 27] += (uint32_t) in_phyaddr;
- cpp_frame_msg[139 + i * 27] += (uint32_t) out_phyaddr0;
- cpp_frame_msg[140 + i * 27] += (uint32_t) out_phyaddr1;
- cpp_frame_msg[141 + i * 27] += (uint32_t) out_phyaddr0;
- cpp_frame_msg[142 + i * 27] += (uint32_t) out_phyaddr1;
+ cpp_frame_msg[(133 + fw_version_1_2_x) + i * 27] +=
+ (uint32_t) in_phyaddr;
+ cpp_frame_msg[(139 + fw_version_1_2_x) + i * 27] +=
+ (uint32_t) out_phyaddr0;
+ cpp_frame_msg[(140 + fw_version_1_2_x) + i * 27] +=
+ (uint32_t) out_phyaddr1;
+ cpp_frame_msg[(141 + fw_version_1_2_x) + i * 27] +=
+ (uint32_t) out_phyaddr0;
+ cpp_frame_msg[(142 + fw_version_1_2_x) + i * 27] +=
+ (uint32_t) out_phyaddr1;
}
frame_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_KERNEL);
@@ -1549,9 +1559,9 @@
}
cpp_dev->iommu_ctx = msm_iommu_get_ctx("cpp");
- if (!cpp_dev->iommu_ctx) {
+ if (IS_ERR(cpp_dev->iommu_ctx)) {
pr_err("%s: cannot get iommu_ctx\n", __func__);
- rc = -ENODEV;
+ rc = -EPROBE_DEFER;
goto ERROR3;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile b/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile
index 572e722..771167d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/Makefile
@@ -2,6 +2,8 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ifeq ($(CONFIG_MSM_CSI20_HEADER),y)
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.0
+else ifeq ($(CONFIG_MSM_CSI22_HEADER),y)
+ ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.2
else ifeq ($(CONFIG_MSM_CSI30_HEADER),y)
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csid/include/csi3.0
endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.2/msm_csid_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.2/msm_csid_hwreg.h
new file mode 100644
index 0000000..5b30472
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/include/csi2.2/msm_csid_hwreg.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSID_HWREG_H
+#define MSM_CSID_HWREG_H
+
+/* MIPI CSID registers */
+#define CSID_HW_VERSION_ADDR 0x0
+#define CSID_CORE_CTRL_0_ADDR 0x4
+#define CSID_CORE_CTRL_1_ADDR 0x4
+#define CSID_RST_CMD_ADDR 0x8
+#define CSID_CID_LUT_VC_0_ADDR 0xc
+#define CSID_CID_LUT_VC_1_ADDR 0x10
+#define CSID_CID_LUT_VC_2_ADDR 0x14
+#define CSID_CID_LUT_VC_3_ADDR 0x18
+#define CSID_CID_n_CFG_ADDR 0x1C
+#define CSID_IRQ_CLEAR_CMD_ADDR 0x5c
+#define CSID_IRQ_MASK_ADDR 0x60
+#define CSID_IRQ_STATUS_ADDR 0x64
+#define CSID_CAPTURED_UNMAPPED_LONG_PKT_HDR_ADDR 0x68
+#define CSID_CAPTURED_MMAPPED_LONG_PKT_HDR_ADDR 0x6c
+#define CSID_CAPTURED_SHORT_PKT_ADDR 0x70
+#define CSID_CAPTURED_LONG_PKT_HDR_ADDR 0x74
+#define CSID_CAPTURED_LONG_PKT_FTR_ADDR 0x78
+#define CSID_PIF_MISR_DL0_ADDR 0x7C
+#define CSID_PIF_MISR_DL1_ADDR 0x80
+#define CSID_PIF_MISR_DL2_ADDR 0x84
+#define CSID_PIF_MISR_DL3_ADDR 0x88
+#define CSID_STATS_TOTAL_PKTS_RCVD_ADDR 0x8C
+#define CSID_STATS_ECC_ADDR 0x90
+#define CSID_STATS_CRC_ADDR 0x94
+#define CSID_TG_CTRL_ADDR 0x9C
+#define CSID_TG_VC_CFG_ADDR 0xA0
+#define CSID_TG_DT_n_CFG_0_ADDR 0xA8
+#define CSID_TG_DT_n_CFG_1_ADDR 0xAC
+#define CSID_TG_DT_n_CFG_2_ADDR 0xB0
+#define CSID_RST_DONE_IRQ_BITSHIFT 11
+#define CSID_RST_STB_ALL 0x7FFF
+#define CSID_DL_INPUT_SEL_SHIFT 0x2
+#define CSID_PHY_SEL_SHIFT 17
+#define CSID_VERSION 0x02001000
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index 4db6855..7af0c14 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -20,8 +20,9 @@
#include "msm_camera_io_util.h"
#define V4L2_IDENT_CSID 50002
-#define CSID_VERSION_V2 0x02000011
-#define CSID_VERSION_V3 0x30000000
+#define CSID_VERSION_V20 0x02000011
+#define CSID_VERSION_V22 0x02001000
+#define CSID_VERSION_V30 0x30000000
#define MSM_CSID_DRV_NAME "msm_csid"
#define DBG_CSID 0
@@ -196,6 +197,15 @@
{"csi_rdi_clk", -1},
};
+static struct msm_cam_clk_info csid_8610_clk_info[] = {
+ {"csi_ahb_clk", -1},
+ {"csi_src_clk", 200000000},
+ {"csi_clk", -1},
+ {"csi_phy_clk", -1},
+ {"csi_pix_clk", -1},
+ {"csi_rdi_clk", -1},
+};
+
static struct camera_vreg_t csid_8960_vreg_info[] = {
{"mipi_csi_vdd", REG_LDO, 1200000, 1200000, 20000},
};
@@ -207,6 +217,7 @@
static int msm_csid_init(struct csid_device *csid_dev, uint32_t *csid_version)
{
int rc = 0;
+ struct camera_vreg_t *cam_vreg;
if (!csid_version) {
pr_err("%s:%d csid_version NULL\n", __func__, __LINE__);
@@ -229,31 +240,47 @@
return rc;
}
- if (CSID_VERSION <= CSID_VERSION_V2) {
+ if (CSID_VERSION == CSID_VERSION_V20)
+ cam_vreg = csid_8960_vreg_info;
+ else
+ cam_vreg = csid_vreg_info;
+
+ if (CSID_VERSION < CSID_VERSION_V30) {
rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
- csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 1);
if (rc < 0) {
pr_err("%s: regulator on failed\n", __func__);
goto vreg_config_failed;
}
-
rc = msm_camera_enable_vreg(&csid_dev->pdev->dev,
- csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 1);
if (rc < 0) {
pr_err("%s: regulator enable failed\n", __func__);
goto vreg_enable_failed;
}
- rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
- csid_8960_clk_info, csid_dev->csid_clk,
- ARRAY_SIZE(csid_8960_clk_info), 1);
- if (rc < 0) {
- pr_err("%s: clock enable failed\n", __func__);
- goto clk_enable_failed;
+ if (CSID_VERSION == CSID_VERSION_V20) {
+ rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+ csid_8960_clk_info, csid_dev->csid_clk,
+ ARRAY_SIZE(csid_8960_clk_info), 1);
+ if (rc < 0) {
+ pr_err("%s: 8960: clock enable failed\n",
+ __func__);
+ goto clk_enable_failed;
+ }
+ } else {
+ rc = msm_cam_clk_enable(&csid_dev->pdev->dev,
+ csid_8610_clk_info, csid_dev->csid_clk,
+ ARRAY_SIZE(csid_8610_clk_info), 1);
+ if (rc < 0) {
+ pr_err("%s: 8610: clock enable failed\n",
+ __func__);
+ goto clk_enable_failed;
+ }
}
- } else if (CSID_VERSION >= CSID_VERSION_V3) {
+ } else if (CSID_VERSION >= CSID_VERSION_V30) {
rc = msm_camera_config_vreg(&csid_dev->pdev->dev,
csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 1);
@@ -294,21 +321,21 @@
return rc;
clk_enable_failed:
- if (CSID_VERSION <= CSID_VERSION_V2) {
+ if (CSID_VERSION < CSID_VERSION_V30) {
msm_camera_enable_vreg(&csid_dev->pdev->dev,
- csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 0);
- } else if (CSID_VERSION >= CSID_VERSION_V3) {
+ } else if (CSID_VERSION >= CSID_VERSION_V30) {
msm_camera_enable_vreg(&csid_dev->pdev->dev,
csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 0);
}
vreg_enable_failed:
- if (CSID_VERSION <= CSID_VERSION_V2) {
+ if (CSID_VERSION < CSID_VERSION_V30) {
msm_camera_config_vreg(&csid_dev->pdev->dev,
- csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
+ csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 0);
- } else if (CSID_VERSION >= CSID_VERSION_V3) {
+ } else if (CSID_VERSION >= CSID_VERSION_V30) {
msm_camera_config_vreg(&csid_dev->pdev->dev,
csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 0);
@@ -335,7 +362,7 @@
disable_irq(csid_dev->irq->start);
- if (csid_dev->hw_version <= CSID_VERSION_V2) {
+ if (csid_dev->hw_version == CSID_VERSION_V20) {
msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8960_clk_info,
csid_dev->csid_clk, ARRAY_SIZE(csid_8960_clk_info), 0);
@@ -346,7 +373,20 @@
msm_camera_config_vreg(&csid_dev->pdev->dev,
csid_8960_vreg_info, ARRAY_SIZE(csid_8960_vreg_info),
NULL, 0, &csid_dev->csi_vdd, 0);
- } else if (csid_dev->hw_version >= CSID_VERSION_V3) {
+ } else if (csid_dev->hw_version == CSID_VERSION_V22) {
+ msm_cam_clk_enable(&csid_dev->pdev->dev,
+ csid_8610_clk_info,
+ csid_dev->csid_clk,
+ ARRAY_SIZE(csid_8610_clk_info), 0);
+
+ msm_camera_enable_vreg(&csid_dev->pdev->dev,
+ csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
+
+ msm_camera_config_vreg(&csid_dev->pdev->dev,
+ csid_vreg_info, ARRAY_SIZE(csid_vreg_info),
+ NULL, 0, &csid_dev->csi_vdd, 0);
+ } else if (csid_dev->hw_version >= CSID_VERSION_V30) {
msm_cam_clk_enable(&csid_dev->pdev->dev, csid_8974_clk_info,
csid_dev->csid_clk, ARRAY_SIZE(csid_8974_clk_info), 0);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile b/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile
index eab1f6f..61671ea 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/Makefile
@@ -2,6 +2,8 @@
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
ifeq ($(CONFIG_MSM_CSI20_HEADER),y)
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.0
+else ifeq ($(CONFIG_MSM_CSI22_HEADER),y)
+ ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.2
else ifeq ($(CONFIG_MSM_CSI30_HEADER),y)
ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi3.0
endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.2/msm_csiphy_hwreg.h b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.2/msm_csiphy_hwreg.h
new file mode 100644
index 0000000..c4ff05d
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/include/csi2.2/msm_csiphy_hwreg.h
@@ -0,0 +1,43 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MSM_CSIPHY_HWREG_H
+#define MSM_CSIPHY_HWREG_H
+
+/*MIPI CSI PHY registers*/
+#define MIPI_CSIPHY_HW_VERSION_ADDR 0x17C
+#define MIPI_CSIPHY_LNn_CFG1_ADDR 0x0
+#define MIPI_CSIPHY_LNn_CFG2_ADDR 0x4
+#define MIPI_CSIPHY_LNn_CFG3_ADDR 0x8
+#define MIPI_CSIPHY_LNn_CFG4_ADDR 0xC
+#define MIPI_CSIPHY_LNn_CFG5_ADDR 0x10
+#define MIPI_CSIPHY_LNCK_CFG1_ADDR 0x100
+#define MIPI_CSIPHY_LNCK_CFG2_ADDR 0x104
+#define MIPI_CSIPHY_LNCK_CFG3_ADDR 0x108
+#define MIPI_CSIPHY_LNCK_CFG4_ADDR 0x10C
+#define MIPI_CSIPHY_LNCK_CFG5_ADDR 0x110
+#define MIPI_CSIPHY_LNCK_MISC1_ADDR 0x128
+#define MIPI_CSIPHY_GLBL_RESET_ADDR 0x140
+#define MIPI_CSIPHY_GLBL_PWR_CFG_ADDR 0x144
+#define MIPI_CSIPHY_GLBL_IRQ_CMD_ADDR 0x164
+#define MIPI_CSIPHY_INTERRUPT_STATUS0_ADDR 0x180
+#define MIPI_CSIPHY_INTERRUPT_MASK0_ADDR 0x1A0
+#define MIPI_CSIPHY_INTERRUPT_MASK_VAL 0x6F
+#define MIPI_CSIPHY_INTERRUPT_MASK_ADDR 0x1A4
+#define MIPI_CSIPHY_INTERRUPT_CLEAR0_ADDR 0x1C0
+#define MIPI_CSIPHY_INTERRUPT_CLEAR_ADDR 0x1C4
+#define MIPI_CSIPHY_MODE_CONFIG_SHIFT 0x4
+#define MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR 0x1E0
+#define MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR 0x1E8
+#define CSIPHY_VERSION 0x1
+
+#endif
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 429d151..0fbe238 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -24,7 +24,9 @@
#define DBG_CSIPHY 0
#define V4L2_IDENT_CSIPHY 50003
-#define CSIPHY_VERSION_V3 0x10
+#define CSIPHY_VERSION_V22 0x01
+#define CSIPHY_VERSION_V20 0x00
+#define CSIPHY_VERSION_V30 0x10
#define MSM_CSIPHY_DRV_NAME "msm_csiphy"
#undef CDBG
@@ -66,7 +68,7 @@
csiphy_params->settle_cnt,
csiphy_params->csid_core);
- if (csiphy_dev->hw_version >= CSIPHY_VERSION_V3) {
+ if (csiphy_dev->hw_version >= CSIPHY_VERSION_V30) {
val = msm_camera_io_r(csiphy_dev->clk_mux_base);
if (csiphy_params->combo_mode &&
(csiphy_params->lane_mask & 0x18)) {
@@ -84,7 +86,7 @@
msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_GLBL_T_INIT_CFG0_ADDR);
msm_camera_io_w(0x1, csiphybase + MIPI_CSIPHY_T_WAKEUP_CFG0_ADDR);
- if (csiphy_dev->hw_version < CSIPHY_VERSION_V3) {
+ if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
val = 0x3;
msm_camera_io_w((lane_mask << 2) | val,
csiphybase + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
@@ -173,6 +175,11 @@
{"csiphy_timer_clk", -1},
};
+static struct msm_cam_clk_info csiphy_8610_clk_info[] = {
+ {"csiphy_timer_src_clk", 200000000},
+ {"csiphy_timer_clk", -1},
+};
+
static struct msm_cam_clk_info csiphy_8974_clk_info[] = {
{"camss_top_ahb_clk", -1},
{"ispif_ahb_clk", -1},
@@ -216,12 +223,17 @@
}
CDBG("%s:%d called\n", __func__, __LINE__);
- if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
+ if (CSIPHY_VERSION == CSIPHY_VERSION_V20) {
CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
ARRAY_SIZE(csiphy_8960_clk_info), 1);
- } else {
+ } else if (CSIPHY_VERSION == CSIPHY_VERSION_V22) {
+ CDBG("%s:%d called\n", __func__, __LINE__);
+ rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+ csiphy_8610_clk_info, csiphy_dev->csiphy_clk,
+ ARRAY_SIZE(csiphy_8610_clk_info), 1);
+ } else if (CSIPHY_VERSION == CSIPHY_VERSION_V30) {
if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) {
pr_err("%s clk mux mem %p io %p\n", __func__,
csiphy_dev->clk_mux_mem,
@@ -242,6 +254,11 @@
rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
ARRAY_SIZE(csiphy_8974_clk_info), 1);
+ } else {
+ pr_err("%s: ERROR Invalid CSIPHY Version %d",
+ __func__, __LINE__);
+ rc = -EINVAL;
+ return rc;
}
CDBG("%s:%d called\n", __func__, __LINE__);
@@ -259,8 +276,13 @@
msm_csiphy_reset(csiphy_dev);
CDBG("%s:%d called\n", __func__, __LINE__);
- csiphy_dev->hw_version =
- msm_camera_io_r(csiphy_dev->base + MIPI_CSIPHY_HW_VERSION_ADDR);
+
+ if (CSIPHY_VERSION == CSIPHY_VERSION_V30)
+ csiphy_dev->hw_version =
+ msm_camera_io_r(csiphy_dev->base +
+ MIPI_CSIPHY_HW_VERSION_ADDR);
+ else
+ csiphy_dev->hw_version = CSIPHY_VERSION;
CDBG("%s:%d called csiphy_dev->hw_version %x\n", __func__, __LINE__,
csiphy_dev->hw_version);
@@ -304,13 +326,17 @@
CDBG("%s:%d called\n", __func__, __LINE__);
- if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
+ if (CSIPHY_VERSION == CSIPHY_VERSION_V20) {
CDBG("%s:%d called\n", __func__, __LINE__);
rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
ARRAY_SIZE(csiphy_8960_clk_info), 1);
- } else {
-
+ } else if (CSIPHY_VERSION == CSIPHY_VERSION_V22) {
+ CDBG("%s:%d called\n", __func__, __LINE__);
+ rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+ csiphy_8610_clk_info, csiphy_dev->csiphy_clk,
+ ARRAY_SIZE(csiphy_8610_clk_info), 1);
+ } else if (CSIPHY_VERSION == CSIPHY_VERSION_V30) {
if (!csiphy_dev->clk_mux_mem || !csiphy_dev->clk_mux_io) {
pr_err("%s clk mux mem %p io %p\n", __func__,
csiphy_dev->clk_mux_mem,
@@ -332,6 +358,11 @@
rc = msm_cam_clk_enable(&csiphy_dev->pdev->dev,
csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
ARRAY_SIZE(csiphy_8974_clk_info), 1);
+ } else {
+ pr_err("%s: ERROR Invalid CSIPHY Version %d",
+ __func__, __LINE__);
+ rc = -EINVAL;
+ return rc;
}
CDBG("%s:%d called\n", __func__, __LINE__);
@@ -347,8 +378,13 @@
msm_csiphy_reset(csiphy_dev);
CDBG("%s:%d called\n", __func__, __LINE__);
- csiphy_dev->hw_version =
- msm_camera_io_r(csiphy_dev->base + MIPI_CSIPHY_HW_VERSION_ADDR);
+
+ if (CSIPHY_VERSION == CSIPHY_VERSION_V30)
+ csiphy_dev->hw_version =
+ msm_camera_io_r(csiphy_dev->base +
+ MIPI_CSIPHY_HW_VERSION_ADDR);
+ else
+ csiphy_dev->hw_version = CSIPHY_VERSION;
CDBG("%s:%d called csiphy_dev->hw_version %x\n", __func__, __LINE__,
csiphy_dev->hw_version);
@@ -382,7 +418,7 @@
csi_lane_params->csi_lane_assign,
csi_lane_params->csi_lane_mask);
- if (csiphy_dev->hw_version < CSIPHY_VERSION_V3) {
+ if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
for (i = 0; i < 4; i++)
msm_camera_io_w(0x0, csiphy_dev->base +
@@ -412,11 +448,15 @@
disable_irq(csiphy_dev->irq->start);
- if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
+ if (CSIPHY_VERSION == CSIPHY_VERSION_V20) {
msm_cam_clk_enable(&csiphy_dev->pdev->dev,
csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
ARRAY_SIZE(csiphy_8960_clk_info), 0);
- } else {
+ } else if (CSIPHY_VERSION == CSIPHY_VERSION_V22) {
+ msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+ csiphy_8610_clk_info, csiphy_dev->csiphy_clk,
+ ARRAY_SIZE(csiphy_8610_clk_info), 0);
+ } else if (CSIPHY_VERSION == CSIPHY_VERSION_V30) {
msm_cam_clk_enable(&csiphy_dev->pdev->dev,
csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
ARRAY_SIZE(csiphy_8974_clk_info), 0);
@@ -453,7 +493,7 @@
csi_lane_params->csi_lane_assign,
csi_lane_params->csi_lane_mask);
- if (csiphy_dev->hw_version < CSIPHY_VERSION_V3) {
+ if (csiphy_dev->hw_version < CSIPHY_VERSION_V30) {
csiphy_dev->lane_mask[csiphy_dev->pdev->id] = 0;
for (i = 0; i < 4; i++)
msm_camera_io_w(0x0, csiphy_dev->base +
@@ -481,11 +521,17 @@
msm_camera_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_LNCK_CFG2_ADDR);
msm_camera_io_w(0x0, csiphy_dev->base + MIPI_CSIPHY_GLBL_PWR_CFG_ADDR);
- if (CSIPHY_VERSION < CSIPHY_VERSION_V3) {
+ if (CSIPHY_VERSION == CSIPHY_VERSION_V20) {
msm_cam_clk_enable(&csiphy_dev->pdev->dev,
csiphy_8960_clk_info, csiphy_dev->csiphy_clk,
ARRAY_SIZE(csiphy_8960_clk_info), 0);
- } else {
+
+ } else if (CSIPHY_VERSION == CSIPHY_VERSION_V22) {
+ msm_cam_clk_enable(&csiphy_dev->pdev->dev,
+ csiphy_8610_clk_info, csiphy_dev->csiphy_clk,
+ ARRAY_SIZE(csiphy_8610_clk_info), 0);
+
+ } else if (CSIPHY_VERSION == CSIPHY_VERSION_V30) {
msm_cam_clk_enable(&csiphy_dev->pdev->dev,
csiphy_8974_clk_info, csiphy_dev->csiphy_clk,
ARRAY_SIZE(csiphy_8974_clk_info), 0);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/imx135.c b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
index 9b02b17..8368a4d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/imx135.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/imx135.c
@@ -93,9 +93,15 @@
{ }
};
+static int32_t msm_imx135_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &imx135_s_ctrl);
+}
+
static struct i2c_driver imx135_i2c_driver = {
.id_table = imx135_i2c_id,
- .probe = msm_sensor_i2c_probe,
+ .probe = msm_imx135_i2c_probe,
.driver = {
.name = IMX135_SENSOR_NAME,
},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
index 68c7d23..c834925 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.c
@@ -613,11 +613,10 @@
return rc;
}
-static int32_t msm_sensor_get_dt_data(struct platform_device *pdev,
+static int32_t msm_sensor_get_dt_data(struct device_node *of_node,
struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0, i = 0, ret = 0;
- struct device_node *of_node = pdev->dev.of_node;
struct msm_camera_gpio_conf *gconf = NULL;
struct msm_camera_sensor_board_info *sensordata = NULL;
uint16_t *gpio_array = NULL;
@@ -867,6 +866,11 @@
[SENSOR_CAM_MCLK] = {"cam_clk", 24000000},
};
+static struct msm_cam_clk_info cam_8610_clk_info[] = {
+ [SENSOR_CAM_MCLK] = {"cam_src_clk", 24000000},
+ [SENSOR_CAM_CLK] = {"cam_clk", 0},
+};
+
static struct msm_cam_clk_info cam_8974_clk_info[] = {
[SENSOR_CAM_MCLK] = {"cam_src_clk", 19200000},
[SENSOR_CAM_CLK] = {"cam_clk", 0},
@@ -1670,7 +1674,7 @@
CDBG("%s called data %p\n", __func__, data);
CDBG("%s pdev name %s\n", __func__, pdev->id_entry->name);
if (pdev->dev.of_node) {
- rc = msm_sensor_get_dt_data(pdev, s_ctrl);
+ rc = msm_sensor_get_dt_data(pdev->dev.of_node, s_ctrl);
if (rc < 0) {
pr_err("%s failed line %d\n", __func__, __LINE__);
return rc;
@@ -1744,10 +1748,9 @@
}
int32_t msm_sensor_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl)
{
int rc = 0;
- struct msm_sensor_ctrl_t *s_ctrl;
uint32_t session_id;
CDBG("%s %s_i2c_probe called\n", __func__, client->name);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
@@ -1757,15 +1760,25 @@
return rc;
}
- s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
- if (!s_ctrl) {
- pr_err("%s:%d sensor ctrl structure NULL\n", __func__,
- __LINE__);
- return -EINVAL;
+ if (!client->dev.of_node) {
+ CDBG("msm_sensor_i2c_probe: of_node is NULL");
+ s_ctrl = (struct msm_sensor_ctrl_t *)(id->driver_data);
+ if (!s_ctrl) {
+ pr_err("%s:%d sensor ctrl structure NULL\n", __func__,
+ __LINE__);
+ return -EINVAL;
+ }
+ s_ctrl->sensordata = client->dev.platform_data;
+ } else {
+ CDBG("msm_sensor_i2c_probe: of_node exisists");
+ rc = msm_sensor_get_dt_data(client->dev.of_node, s_ctrl);
+ if (rc < 0) {
+ pr_err("%s failed line %d\n", __func__, __LINE__);
+ return rc;
+ }
}
s_ctrl->sensor_device_type = MSM_CAMERA_I2C_DEVICE;
- s_ctrl->sensordata = client->dev.platform_data;
if (s_ctrl->sensordata == NULL) {
pr_err("%s %s NULL sensor data\n", __func__, client->name);
return -EFAULT;
@@ -1793,14 +1806,27 @@
if (!s_ctrl->sensor_v4l2_subdev_ops)
s_ctrl->sensor_v4l2_subdev_ops = &msm_sensor_subdev_ops;
- s_ctrl->clk_info = kzalloc(sizeof(cam_8960_clk_info),
- GFP_KERNEL);
- if (!s_ctrl->clk_info) {
- pr_err("%s:%d failed nomem\n", __func__, __LINE__);
- return -ENOMEM;
+ if (!client->dev.of_node) {
+ s_ctrl->clk_info = kzalloc(sizeof(cam_8960_clk_info),
+ GFP_KERNEL);
+ if (!s_ctrl->clk_info) {
+ pr_err("%s:%d failed nomem\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ memcpy(s_ctrl->clk_info, cam_8960_clk_info,
+ sizeof(cam_8960_clk_info));
+ s_ctrl->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
+ } else {
+ s_ctrl->clk_info = kzalloc(sizeof(cam_8610_clk_info),
+ GFP_KERNEL);
+ if (!s_ctrl->clk_info) {
+ pr_err("%s:%d failed nomem\n", __func__, __LINE__);
+ return -ENOMEM;
+ }
+ memcpy(s_ctrl->clk_info, cam_8610_clk_info,
+ sizeof(cam_8610_clk_info));
+ s_ctrl->clk_info_size = ARRAY_SIZE(cam_8610_clk_info);
}
- memcpy(s_ctrl->clk_info, cam_8960_clk_info, sizeof(cam_8960_clk_info));
- s_ctrl->clk_info_size = ARRAY_SIZE(cam_8960_clk_info);
rc = s_ctrl->func_tbl->sensor_power_up(s_ctrl);
if (rc < 0) {
diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
index fe11a56..80a2bd4 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
+++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor.h
@@ -88,7 +88,7 @@
void *data);
int32_t msm_sensor_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id);
+ const struct i2c_device_id *id, struct msm_sensor_ctrl_t *s_ctrl);
int32_t msm_sensor_free_sensor_data(struct msm_sensor_ctrl_t *s_ctrl);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
index 9911a59..c1cf862 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/mt9m114.c
@@ -1107,9 +1107,15 @@
{ }
};
+static int32_t msm_mt9m114_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &mt9m114_s_ctrl);
+}
+
static struct i2c_driver mt9m114_i2c_driver = {
.id_table = mt9m114_i2c_id,
- .probe = msm_sensor_i2c_probe,
+ .probe = msm_mt9m114_i2c_probe,
.driver = {
.name = MT9M114_SENSOR_NAME,
},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov2720.c b/drivers/media/platform/msm/camera_v2/sensor/ov2720.c
index d790c65..397564b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov2720.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov2720.c
@@ -75,9 +75,15 @@
{ }
};
+static int32_t msm_ov2720_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &ov2720_s_ctrl);
+}
+
static struct i2c_driver ov2720_i2c_driver = {
.id_table = ov2720_i2c_id,
- .probe = msm_sensor_i2c_probe,
+ .probe = msm_ov2720_i2c_probe,
.driver = {
.name = OV2720_SENSOR_NAME,
},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
index b56eb10..3256c5c 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
@@ -93,9 +93,15 @@
{ }
};
+static int32_t msm_ov8825_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &ov8825_s_ctrl);
+}
+
static struct i2c_driver ov8825_i2c_driver = {
.id_table = ov8825_i2c_id,
- .probe = msm_sensor_i2c_probe,
+ .probe = msm_ov8825_i2c_probe,
.driver = {
.name = OV8825_SENSOR_NAME,
},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
index 981cc10..56af02b 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov9724.c
@@ -83,6 +83,12 @@
},
};
+static int32_t msm_ov9724_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &ov9724_s_ctrl);
+}
+
static const struct i2c_device_id ov9724_i2c_id[] = {
{OV9724_SENSOR_NAME, (kernel_ulong_t)&ov9724_s_ctrl},
{ }
@@ -90,7 +96,7 @@
static struct i2c_driver ov9724_i2c_driver = {
.id_table = ov9724_i2c_id,
- .probe = msm_sensor_i2c_probe,
+ .probe = msm_ov9724_i2c_probe,
.driver = {
.name = OV9724_SENSOR_NAME,
},
diff --git a/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c b/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
index 21a7369..225e81d 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/s5k3l1yx.c
@@ -93,9 +93,15 @@
{ }
};
+static int32_t msm_s5k3l1yx_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return msm_sensor_i2c_probe(client, id, &s5k3l1yx_s_ctrl);
+}
+
static struct i2c_driver s5k3l1yx_i2c_driver = {
.id_table = s5k3l1yx_i2c_id,
- .probe = msm_sensor_i2c_probe,
+ .probe = msm_s5k3l1yx_i2c_probe,
.driver = {
.name = S5K3L1YX_SENSOR_NAME,
},
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index a63fccf..85fdff6 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -14,11 +14,12 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/file.h>
+#include <linux/scatterlist.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
#include "mpq_sdmx.h"
-#define SDMX_MAJOR_VERSION_MATCH (3)
+#define SDMX_MAJOR_VERSION_MATCH (4)
#define TS_PACKET_HEADER_LENGTH (4)
@@ -3357,7 +3358,6 @@
if (status != SDMX_SUCCESS) {
MPQ_DVB_ERR_PRINT("%s: sdmx_close_session failed %d\n",
__func__, status);
- return -EINVAL;
}
mpq_demux->sdmx_eos = 0;
mpq_demux->sdmx_session_handle = SDMX_INVALID_SESSION_HANDLE;
@@ -3369,14 +3369,64 @@
}
EXPORT_SYMBOL(mpq_sdmx_close_session);
+static int mpq_sdmx_get_buffer_chunks(struct mpq_demux *mpq_demux,
+ struct ion_handle *buff_handle,
+ u32 actual_buff_size,
+ struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS])
+{
+ int i;
+ struct sg_table *sg_ptr;
+ struct scatterlist *sg;
+ u32 chunk_size;
+
+ memset(buff_chunks, 0,
+ sizeof(struct sdmx_buff_descr) * SDMX_MAX_PHYSICAL_CHUNKS);
+
+ sg_ptr = ion_sg_table(mpq_demux->ion_client, buff_handle);
+ if (sg_ptr == NULL) {
+ MPQ_DVB_ERR_PRINT("%s: ion_sg_table failed\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (sg_ptr->nents == 0) {
+ MPQ_DVB_ERR_PRINT("%s: num of scattered entries is 0\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (sg_ptr->nents > SDMX_MAX_PHYSICAL_CHUNKS) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: num of scattered entries %d greater than max supported %d\n",
+ __func__, sg_ptr->nents, SDMX_MAX_PHYSICAL_CHUNKS);
+ return -EINVAL;
+ }
+
+ sg = sg_ptr->sgl;
+ for (i = 0; i < sg_ptr->nents; i++) {
+ buff_chunks[i].base_addr =
+ (void *)sg_dma_address(sg);
+ if (sg->length > actual_buff_size)
+ chunk_size = actual_buff_size;
+ else
+ chunk_size = sg->length;
+
+ buff_chunks[i].size = chunk_size;
+ sg = sg_next(sg);
+ actual_buff_size -= chunk_size;
+ }
+
+ return 0;
+}
+
static int mpq_sdmx_init_data_buffer(struct mpq_demux *mpq_demux,
struct mpq_feed *feed, u32 *num_buffers,
- struct sdmx_buff_descr *buf_desc, enum sdmx_buf_mode *buf_mode)
+ struct sdmx_data_buff_descr buf_desc[DMX_MAX_DECODER_BUFFER_NUM],
+ enum sdmx_buf_mode *buf_mode)
{
struct dvb_demux_feed *dvbdmx_feed = feed->dvb_demux_feed;
struct dvb_ringbuffer *buffer;
struct mpq_video_feed_info *feed_data = &feed->video_info;
- ion_phys_addr_t addr;
struct ion_handle *sdmx_buff;
int ret;
int i;
@@ -3389,57 +3439,56 @@
*num_buffers = feed_data->buffer_desc.decoder_buffers_num;
for (i = 0; i < *num_buffers; i++) {
- ret = ion_phys(mpq_demux->ion_client,
- feed_data->buffer_desc.ion_handle[i],
- &addr, &buf_desc[i].size);
+ buf_desc[i].length =
+ feed_data->buffer_desc.desc[i].size;
+
+ ret = mpq_sdmx_get_buffer_chunks(mpq_demux,
+ feed_data->buffer_desc.ion_handle[i],
+ buf_desc[i].length,
+ buf_desc[i].buff_chunks);
if (ret) {
MPQ_DVB_ERR_PRINT(
- "%s: FAILED to get physical buffer address, ret=%d\n",
- __func__, ret);
- goto end;
+ "%s: mpq_sdmx_get_buffer_chunks failed\n",
+ __func__);
+ return ret;
}
- buf_desc[i].base_addr = (void *)addr;
- buf_desc[i].size = feed_data->buffer_desc.desc[i].size;
- }
- } else {
- *num_buffers = 1;
- if (dvb_dmx_is_sec_feed(dvbdmx_feed) ||
- dvb_dmx_is_pcr_feed(dvbdmx_feed)) {
- buffer = &feed->sdmx_buf;
- sdmx_buff = feed->sdmx_buf_handle;
- } else {
- buffer = (struct dvb_ringbuffer *)
- dvbdmx_feed->feed.ts.buffer.ringbuff;
- sdmx_buff = dvbdmx_feed->feed.ts.buffer.priv_handle;
}
- if (sdmx_buff == NULL) {
- MPQ_DVB_ERR_PRINT(
- "%s: Invalid buffer allocation\n",
- __func__);
- return -ENOMEM;
- }
-
- ret = ion_phys(mpq_demux->ion_client, sdmx_buff, &addr,
- &buf_desc[0].size);
- if (ret) {
- MPQ_DVB_ERR_PRINT(
- "%s: FAILED to get physical buffer address, ret=%d\n",
- __func__, ret);
- goto end;
- } else {
- buf_desc[0].size = buffer->size;
- buf_desc[0].base_addr = (void *)addr;
- }
-
+ return 0;
}
+
+ *num_buffers = 1;
+ if (dvb_dmx_is_sec_feed(dvbdmx_feed) ||
+ dvb_dmx_is_pcr_feed(dvbdmx_feed)) {
+ buffer = &feed->sdmx_buf;
+ sdmx_buff = feed->sdmx_buf_handle;
+ } else {
+ buffer = (struct dvb_ringbuffer *)
+ dvbdmx_feed->feed.ts.buffer.ringbuff;
+ sdmx_buff = dvbdmx_feed->feed.ts.buffer.priv_handle;
+ }
+
+ if (sdmx_buff == NULL) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: Invalid buffer allocation\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ buf_desc[0].length = buffer->size;
+ ret = mpq_sdmx_get_buffer_chunks(mpq_demux, sdmx_buff,
+ buf_desc[0].length,
+ buf_desc[0].buff_chunks);
+ if (ret) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: mpq_sdmx_get_buffer_chunks failed\n",
+ __func__);
+ return ret;
+ }
+
return 0;
-
-end:
- return ret;
}
-
static int mpq_sdmx_filter_setup(struct mpq_demux *mpq_demux,
struct dvb_demux_feed *dvbdmx_feed)
{
@@ -3447,7 +3496,7 @@
struct mpq_feed *feed;
struct mpq_feed *main_rec_feed;
struct sdmx_buff_descr metadata_buff_desc;
- struct sdmx_buff_descr data_buff_desc[DMX_MAX_DECODER_BUFFER_NUM];
+ struct sdmx_data_buff_descr *data_buff_desc = NULL;
u32 data_buf_num = DMX_MAX_DECODER_BUFFER_NUM;
enum sdmx_buf_mode buf_mode;
enum sdmx_raw_out_format ts_out_format = SDMX_188_OUTPUT;
@@ -3490,6 +3539,15 @@
MPQ_DVB_DBG_PRINT("%s: SDMX_PES_FILTER\n", __func__);
}
+ data_buff_desc = vmalloc(
+ sizeof(*data_buff_desc)*DMX_MAX_DECODER_BUFFER_NUM);
+ if (!data_buff_desc) {
+ MPQ_DVB_ERR_PRINT(
+ "%s: failed to allocate memory for data buffer\n",
+ __func__);
+ return -ENOMEM;
+ }
+
/*
* Recording feed sdmx filter handle lookup:
* In case this is a recording filter with multiple feeds,
@@ -3530,7 +3588,7 @@
MPQ_DVB_ERR_PRINT(
"%s: Failed to initialize metadata buffer. ret=%d\n",
__func__, ret);
- goto end;
+ goto sdmx_filter_setup_failed;
}
}
@@ -3541,7 +3599,7 @@
"%s: Failed to initialize data buffer. ret=%d\n",
__func__, ret);
mpq_sdmx_terminate_metadata_buffer(feed);
- goto end;
+ goto sdmx_filter_setup_failed;
}
ret = sdmx_add_filter(mpq_demux->sdmx_session_handle,
dvbdmx_feed->pid,
@@ -3559,14 +3617,14 @@
__func__, ret);
ret = -ENODEV;
mpq_sdmx_terminate_metadata_buffer(feed);
- goto end;
+ goto sdmx_filter_setup_failed;
}
MPQ_DVB_DBG_PRINT(
"%s: feed=0x%p, filter pid=%d, handle=%d, data buffer(s)=%d, size=%d\n",
__func__, feed, dvbdmx_feed->pid,
feed->sdmx_filter_handle,
- data_buf_num, data_buff_desc[0].size);
+ data_buf_num, data_buff_desc[0].length);
mpq_demux->sdmx_filter_count++;
} else {
@@ -3583,7 +3641,7 @@
"%s: FAILED to add raw pid, ret=%d\n",
__func__, ret);
ret = -ENODEV;
- goto end;
+ goto sdmx_filter_setup_failed;
}
}
@@ -3605,12 +3663,14 @@
MPQ_DVB_ERR_PRINT(
"%s: FAILED to set key ladder, ret=%d\n",
__func__, ret);
- ret = -ENODEV;
- goto end;
}
}
-end:
+ vfree(data_buff_desc);
+ return 0;
+
+sdmx_filter_setup_failed:
+ vfree(data_buff_desc);
return ret;
}
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c
index 14d3a39..888bbbf 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.c
@@ -115,7 +115,7 @@
enum sdmx_raw_out_format ts_out_format;
u32 flags;
u32 num_data_bufs;
- struct sdmx_buff_descr data_bufs[];
+ struct sdmx_data_buff_descr data_bufs[];
};
struct sdmx_add_filt_rsp {
@@ -478,7 +478,7 @@
struct sdmx_buff_descr *meta_data_buf,
enum sdmx_buf_mode d_buf_mode,
u32 num_data_bufs,
- struct sdmx_buff_descr *data_bufs,
+ struct sdmx_data_buff_descr *data_bufs,
int *filter_handle,
enum sdmx_raw_out_format ts_out_format,
u32 flags)
@@ -493,7 +493,7 @@
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_add_filt_req)
- + num_data_bufs * sizeof(struct sdmx_buff_descr);
+ + num_data_bufs * sizeof(struct sdmx_data_buff_descr);
rsp_len = sizeof(struct sdmx_add_filt_rsp);
/* Will be later overridden by SDMX response */
@@ -523,7 +523,7 @@
cmd->buffer_mode = d_buf_mode;
cmd->num_data_bufs = num_data_bufs;
memcpy(cmd->data_bufs, data_bufs,
- num_data_bufs * sizeof(struct sdmx_buff_descr));
+ num_data_bufs * sizeof(struct sdmx_data_buff_descr));
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
index 6b669e4..fadb6b2 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
+++ b/drivers/media/platform/msm/dvb/demux/mpq_sdmx.h
@@ -19,6 +19,8 @@
#define SDMX_MAX_SESSIONS (4)
#define SDMX_LOOPBACK_PID (0x2000)
+#define SDMX_MAX_PHYSICAL_CHUNKS (10)
+
/* Filter-level error indicators */
#define SDMX_FILTER_SUCCESS (0)
#define SDMX_FILTER_ERR_MD_BUF_FULL BIT(0)
@@ -164,10 +166,18 @@
/* Physical address where buffer starts */
void *base_addr;
- /* Total size of buffer */
+ /* Size of buffer */
u32 size;
};
+struct sdmx_data_buff_descr {
+ /* Physical chunks of the buffer */
+ struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS];
+
+ /* Length of buffer */
+ u32 length;
+};
+
/*
* Data payload residing in the data buffers is described using this meta-data
* header. The meta data header specifies where the payload is located in the
@@ -231,7 +241,7 @@
int sdmx_add_filter(int session_handle, u16 pid, enum sdmx_filter filter_type,
struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode,
- u32 num_data_bufs, struct sdmx_buff_descr *data_bufs,
+ u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs,
int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags);
int sdmx_remove_filter(int session_handle, int filter_handle);
diff --git a/drivers/mfd/pm8xxx-pwm.c b/drivers/mfd/pm8xxx-pwm.c
index caaba81..0388484 100644
--- a/drivers/mfd/pm8xxx-pwm.c
+++ b/drivers/mfd/pm8xxx-pwm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -58,10 +58,11 @@
#define PM8XXX_PWM_DISABLE 0x3F
/* PM8XXX LPG PWM */
+#define SSBI_REG_ADDR_LPG_BANK_LOW_EN 0x130
#define SSBI_REG_ADDR_LPG_CTL_BASE 0x13C
#define SSBI_REG_ADDR_LPG_CTL(n) (SSBI_REG_ADDR_LPG_CTL_BASE + (n))
#define SSBI_REG_ADDR_LPG_BANK_SEL 0x143
-#define SSBI_REG_ADDR_LPG_BANK_EN 0x144
+#define SSBI_REG_ADDR_LPG_BANK_HIGH_EN 0x144
#define SSBI_REG_ADDR_LPG_LUT_CFG0 0x145
#define SSBI_REG_ADDR_LPG_LUT_CFG1 0x146
#define SSBI_REG_ADDR_LPG_TEST 0x147
@@ -206,13 +207,15 @@
struct pm8xxx_pwm_chip *chip;
int bypass_lut;
int dtest_mode_supported;
+ int banks;
};
struct pm8xxx_pwm_chip {
struct pwm_device *pwm_dev;
u8 pwm_channels;
u8 pwm_total_pre_divs;
- u8 bank_mask;
+ u8 lo_bank_mask;
+ u8 hi_bank_mask;
struct mutex pwm_mutex;
struct device *dev;
bool is_lpg_supported;
@@ -259,18 +262,37 @@
chip = pwm->chip;
- if (enable)
- reg = chip->bank_mask | (1 << pwm->pwm_id);
- else
- reg = chip->bank_mask & ~(1 << pwm->pwm_id);
+ if (pwm->banks & PM_PWM_BANK_LO) {
+ if (enable)
+ reg = chip->lo_bank_mask | (1 << pwm->pwm_id);
+ else
+ reg = chip->lo_bank_mask & ~(1 << pwm->pwm_id);
- rc = pm8xxx_writeb(chip->dev->parent, SSBI_REG_ADDR_LPG_BANK_EN, reg);
- if (rc) {
- pr_err("pm8xxx_writeb(): rc=%d (Enable LPG Bank)\n", rc);
- return rc;
+ rc = pm8xxx_writeb(chip->dev->parent,
+ SSBI_REG_ADDR_LPG_BANK_LOW_EN, reg);
+ if (rc) {
+ pr_err("pm8xxx_writeb(): Enable Bank Low =%d\n", rc);
+ return rc;
+ }
+
+ chip->lo_bank_mask = reg;
}
- chip->bank_mask = reg;
+ if (pwm->banks & PM_PWM_BANK_HI) {
+ if (enable)
+ reg = chip->hi_bank_mask | (1 << pwm->pwm_id);
+ else
+ reg = chip->hi_bank_mask & ~(1 << pwm->pwm_id);
+
+ rc = pm8xxx_writeb(chip->dev->parent,
+ SSBI_REG_ADDR_LPG_BANK_HIGH_EN, reg);
+ if (rc) {
+ pr_err("pm8xxx_writeb(): Enable Bank High =%d\n", rc);
+ return rc;
+ }
+
+ chip->hi_bank_mask = reg;
+ }
return 0;
}
@@ -1010,6 +1032,16 @@
period = &pwm->period;
mutex_lock(&pwm->chip->pwm_mutex);
+ if (flags & PM_PWM_BANK_HI)
+ pwm->banks = PM_PWM_BANK_HI;
+
+ if (flags & PM_PWM_BANK_LO)
+ pwm->banks |= PM_PWM_BANK_LO;
+
+ /*Enable both banks if banks information is not shared.*/
+ if (!pwm->banks)
+ pwm->banks |= (PM_PWM_BANK_LO | PM_PWM_BANK_HI);
+
if (!pwm->in_use) {
pr_err("pwm_id: %d: stale handle?\n", pwm->pwm_id);
rc = -EINVAL;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index ac2ecbb..a990f43 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -128,6 +128,16 @@
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
+ if (!drv) {
+ pr_debug("%s: %s: drv is NULL\n", dev_name(dev), __func__);
+ return;
+ }
+
+ if (!card) {
+ pr_debug("%s: %s: card is NULL\n", dev_name(dev), __func__);
+ return;
+ }
+
if (drv->shutdown)
drv->shutdown(card);
}
diff --git a/drivers/net/ethernet/msm/ecm_ipa.c b/drivers/net/ethernet/msm/ecm_ipa.c
index be9058b..f000df7 100644
--- a/drivers/net/ethernet/msm/ecm_ipa.c
+++ b/drivers/net/ethernet/msm/ecm_ipa.c
@@ -47,27 +47,50 @@
#define ECM_IPA_LOG_EXIT() pr_debug("end\n")
/**
- * enum ecm_ipa_state - specify the current driver internal state.
+ * enum ecm_ipa_state - specify the current driver internal state
+ * which is guarded by a state machine.
*
- * The driver internal state changes due to its API usage.
+ * The driver internal state changes due to its external API usage.
* The driver saves its internal state to guard from caller illegal
* call sequence.
- * LOADED is the first state which is the default one.
+ * states:
+ * UNLOADED is the first state which is the default one and is also the state
+ * after the driver gets unloaded(cleanup).
* INITIALIZED is the driver state once it finished registering
- * the network device
+ * the network device and all internal data struct were initialized
* CONNECTED is the driver state once the USB pipes were connected to IPA
- * UP is the driver state when it allows Linux network stack start
- * data transfer
+ * UP is the driver state after the interface mode was set to UP but the
+ * pipes are not connected yet - this state is meta-stable state.
+ * CONNECTED_AND_UP is the driver state when the pipe were connected and
+ * the interface got UP request from the network stack. this is the driver
+ * idle operation state which allows it to transmit/receive data.
+ * INVALID is a state which is not allowed.
*/
-enum ecm_ipa_mode {
- ECM_IPA_LOADED,
+enum ecm_ipa_state {
+ ECM_IPA_UNLOADED = 0,
ECM_IPA_INITIALIZED,
ECM_IPA_CONNECTED,
ECM_IPA_UP,
+ ECM_IPA_CONNECTED_AND_UP,
+ ECM_IPA_INVALID,
};
-#define ECM_IPA_MODE(ecm_ipa_ctx) \
- pr_debug("Driver mode changed - %d", ecm_ipa_ctx->mode);
+/**
+ * enum ecm_ipa_operation - enumerations used to descibe the API operation
+ *
+ * Those enums are used as input for the driver state machine.
+ */
+enum ecm_ipa_operation {
+ ECM_IPA_INITIALIZE,
+ ECM_IPA_CONNECT,
+ ECM_IPA_OPEN,
+ ECM_IPA_STOP,
+ ECM_IPA_DISCONNECT,
+ ECM_IPA_CLEANUP,
+};
+
+#define ECM_IPA_STATE_DEBUG(ecm_ipa_ctx) \
+ pr_debug("Driver state - %s", ecm_ipa_state_string(ecm_ipa_ctx->state));
/**
* struct ecm_ipa_dev - main driver context parameters
@@ -85,7 +108,7 @@
* @outstanding_high: number of outstanding packets allowed
* @outstanding_low: number of outstanding packets which shall cause
* to netdev queue start (after stopped due to outstanding_high reached)
- * @mode: current mode of ecm_ipa driver
+ * @state: current state of ecm_ipa driver
*/
struct ecm_ipa_dev {
struct net_device *net;
@@ -101,7 +124,7 @@
atomic_t outstanding_pkts;
u8 outstanding_high;
u8 outstanding_low;
- enum ecm_ipa_mode mode;
+ enum ecm_ipa_state state;
};
static int ecm_ipa_open(struct net_device *net);
@@ -142,8 +165,9 @@
static int ecm_ipa_ep_registers_dma_cfg(u32 usb_to_ipa_hdl);
static int ecm_ipa_set_device_ethernet_addr(u8 *dev_ethaddr,
u8 device_ethaddr[]);
-static bool ecm_ipa_state_validate(enum ecm_ipa_mode current_mode,
- enum ecm_ipa_mode new_mode);
+static enum ecm_ipa_state ecm_ipa_next_state(enum ecm_ipa_state current_state,
+ enum ecm_ipa_operation operation);
+static const char *ecm_ipa_state_string(enum ecm_ipa_state state);
static int ecm_ipa_init_module(void);
static void ecm_ipa_cleanup_module(void);
@@ -270,8 +294,8 @@
params->ecm_ipa_rx_dp_notify = ecm_ipa_packet_receive_notify;
params->ecm_ipa_tx_dp_notify = ecm_ipa_tx_complete_notify;
params->private = (void *)ecm_ipa_ctx;
- ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
- ECM_IPA_MODE(ecm_ipa_ctx);
+ ecm_ipa_ctx->state = ECM_IPA_INITIALIZED;
+ ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
ECM_IPA_LOG_EXIT();
@@ -314,16 +338,20 @@
void *priv)
{
struct ecm_ipa_dev *ecm_ipa_ctx = priv;
+ int next_state;
ECM_IPA_LOG_ENTRY();
NULL_CHECK(priv);
pr_debug("usb_to_ipa_hdl = %d, ipa_to_usb_hdl = %d, priv=0x%p\n",
usb_to_ipa_hdl, ipa_to_usb_hdl, priv);
- if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
- ECM_IPA_ERROR("can't call connect before driver init\n");
+ next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_CONNECT);
+ if (next_state == ECM_IPA_INVALID) {
+ ECM_IPA_ERROR("can't call connect before calling initialize\n");
return -EPERM;
}
+ ecm_ipa_ctx->state = next_state;
+ ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
if (!usb_to_ipa_hdl || usb_to_ipa_hdl >= IPA_CLIENT_MAX) {
ECM_IPA_ERROR("usb_to_ipa_hdl(%d) is not a valid ipa handle\n",
@@ -347,8 +375,10 @@
}
pr_debug("carrier_on notified, ecm_ipa is operational\n");
- ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
- ECM_IPA_MODE(ecm_ipa_ctx);
+ if (ecm_ipa_ctx->state == ECM_IPA_CONNECTED_AND_UP) {
+ netif_start_queue(ecm_ipa_ctx->net);
+ pr_debug("queue started\n");
+ }
ECM_IPA_LOG_EXIT();
@@ -368,24 +398,26 @@
static int ecm_ipa_open(struct net_device *net)
{
struct ecm_ipa_dev *ecm_ipa_ctx;
+ int next_state;
ECM_IPA_LOG_ENTRY();
ecm_ipa_ctx = netdev_priv(net);
- if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_UP)) {
- ECM_IPA_ERROR("can't bring driver up before cable connect\n");
+ next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_OPEN);
+ if (next_state == ECM_IPA_INVALID) {
+ ECM_IPA_ERROR("can't bring driver up before initialize\n");
return -EPERM;
}
+ ecm_ipa_ctx->state = next_state;
+ ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
- if (!netif_carrier_ok(net))
- pr_debug("carrier is not ON yet - continuing\n");
-
- netif_start_queue(net);
- pr_debug("queue started\n");
-
- ecm_ipa_ctx->mode = ECM_IPA_UP;
- ECM_IPA_MODE(ecm_ipa_ctx);
+ if (ecm_ipa_ctx->state == ECM_IPA_CONNECTED_AND_UP) {
+ netif_start_queue(net);
+ pr_debug("queue started\n");
+ } else {
+ pr_debug("queue was not started due to meta-stabilie state\n");
+ }
ECM_IPA_LOG_EXIT();
@@ -424,8 +456,8 @@
goto out;
}
- if (unlikely(ecm_ipa_ctx->mode != ECM_IPA_UP)) {
- ECM_IPA_ERROR("can't send without network interface up\n");
+ if (unlikely(ecm_ipa_ctx->state != ECM_IPA_CONNECTED_AND_UP)) {
+ ECM_IPA_ERROR("Missing pipe connected and/or iface up\n");
return -NETDEV_TX_BUSY;
}
@@ -488,6 +520,11 @@
struct ecm_ipa_dev *ecm_ipa_ctx = priv;
int result;
+ if (unlikely(ecm_ipa_ctx->state != ECM_IPA_CONNECTED_AND_UP)) {
+ ECM_IPA_ERROR("Missing pipe connected and/or iface up\n");
+ return;
+ }
+
if (evt != IPA_RECEIVE) {
ECM_IPA_ERROR("A none IPA_RECEIVE event in ecm_ipa_receive\n");
return;
@@ -522,20 +559,21 @@
static int ecm_ipa_stop(struct net_device *net)
{
struct ecm_ipa_dev *ecm_ipa_ctx = netdev_priv(net);
+ int next_state;
ECM_IPA_LOG_ENTRY();
- if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_CONNECTED)) {
+ next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_STOP);
+ if (next_state == ECM_IPA_INVALID) {
ECM_IPA_ERROR("can't do network interface down without up\n");
return -EPERM;
}
+ ecm_ipa_ctx->state = next_state;
+ ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
netif_stop_queue(net);
pr_debug("network device stopped\n");
- ecm_ipa_ctx->mode = ECM_IPA_CONNECTED;
- ECM_IPA_MODE(ecm_ipa_ctx);
-
ECM_IPA_LOG_EXIT();
return 0;
}
@@ -553,15 +591,19 @@
int ecm_ipa_disconnect(void *priv)
{
struct ecm_ipa_dev *ecm_ipa_ctx = priv;
+ int next_state;
ECM_IPA_LOG_ENTRY();
NULL_CHECK(ecm_ipa_ctx);
pr_debug("priv=0x%p\n", priv);
- if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_INITIALIZED)) {
- ECM_IPA_ERROR("can't disconnect without connect first\n");
+ next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_DISCONNECT);
+ if (next_state == ECM_IPA_INVALID) {
+ ECM_IPA_ERROR("can't disconnect before connect\n");
return -EPERM;
}
+ ecm_ipa_ctx->state = next_state;
+ ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
netif_carrier_off(ecm_ipa_ctx->net);
pr_debug("carrier_off notifcation was sent\n");
@@ -569,9 +611,6 @@
netif_stop_queue(ecm_ipa_ctx->net);
pr_debug("queue stopped\n");
- ecm_ipa_ctx->mode = ECM_IPA_INITIALIZED;
- ECM_IPA_MODE(ecm_ipa_ctx);
-
ECM_IPA_LOG_EXIT();
return 0;
@@ -598,6 +637,7 @@
void ecm_ipa_cleanup(void *priv)
{
struct ecm_ipa_dev *ecm_ipa_ctx = priv;
+ int next_state;
ECM_IPA_LOG_ENTRY();
@@ -608,9 +648,13 @@
return;
}
- if (!ecm_ipa_state_validate(ecm_ipa_ctx->mode, ECM_IPA_LOADED))
+ next_state = ecm_ipa_next_state(ecm_ipa_ctx->state, ECM_IPA_CLEANUP);
+ if (next_state == ECM_IPA_INVALID) {
ECM_IPA_ERROR("can't clean driver without cable disconnect\n");
-
+ return;
+ }
+ ecm_ipa_ctx->state = next_state;
+ ECM_IPA_STATE_DEBUG(ecm_ipa_ctx);
ecm_ipa_destory_rm_resource(ecm_ipa_ctx);
ecm_ipa_debugfs_destroy(ecm_ipa_ctx);
@@ -619,7 +663,6 @@
free_netdev(ecm_ipa_ctx->net);
pr_debug("cleanup done\n");
- ecm_ipa_ctx = NULL;
ECM_IPA_LOG_EXIT();
return ;
@@ -1224,46 +1267,87 @@
return 0;
}
-/** ecm_ipa_state_validate - check if a state transition is allowed
+/** ecm_ipa_next_state - return the next state of the driver
+ * @current_state: the current state of the driver
+ * @operation: an enum which represent the operation being made on the driver
+ * by its API.
*
- * Allowed transition:
- * LOADED->INITIALIZED: ecm_ipa_init()
- * INITIALIZED->CONNECTED: ecm_ipa_connect()
- * CONNECTED->INITIALIZED: ecm_ipa_disconnect()
- * CONNECTED->UP: ecm_ipa_open()
- * UP->CONNECTED: ecm_ipa_stop()
- * UP->INITIALIZED: ecm_ipa_disconnect()
- * INITIALIZED-> LOADED
+ * This function implements the driver internal state machine.
+ * Its decisions are based on the driver current state and the operation
+ * being made.
+ * In case the operation is invalid this state machine will return
+ * the value ECM_IPA_INVALID to inform the caller for a forbidden sequence.
*/
-static bool ecm_ipa_state_validate(enum ecm_ipa_mode current_mode,
- enum ecm_ipa_mode new_mode)
+static enum ecm_ipa_state ecm_ipa_next_state(enum ecm_ipa_state current_state,
+ enum ecm_ipa_operation operation)
{
- bool result;
+ int next_state = ECM_IPA_INVALID;
- switch (current_mode) {
- case ECM_IPA_LOADED:
- result = (new_mode == ECM_IPA_INITIALIZED);
+ switch (current_state) {
+ case ECM_IPA_UNLOADED:
+ if (operation == ECM_IPA_INITIALIZE)
+ next_state = ECM_IPA_INITIALIZED;
break;
case ECM_IPA_INITIALIZED:
- result = (new_mode == ECM_IPA_CONNECTED ||
- new_mode == ECM_IPA_LOADED);
+ if (operation == ECM_IPA_CONNECT)
+ next_state = ECM_IPA_CONNECTED;
+ else if (operation == ECM_IPA_OPEN)
+ next_state = ECM_IPA_UP;
+ else if (operation == ECM_IPA_CLEANUP)
+ next_state = ECM_IPA_UNLOADED;
break;
case ECM_IPA_CONNECTED:
- result = (new_mode == ECM_IPA_INITIALIZED ||
- new_mode == ECM_IPA_UP);
+ if (operation == ECM_IPA_DISCONNECT)
+ next_state = ECM_IPA_INITIALIZED;
+ else if (operation == ECM_IPA_OPEN)
+ next_state = ECM_IPA_CONNECTED_AND_UP;
break;
case ECM_IPA_UP:
- result = (new_mode == ECM_IPA_CONNECTED ||
- new_mode == ECM_IPA_INITIALIZED);
+ if (operation == ECM_IPA_STOP)
+ next_state = ECM_IPA_INITIALIZED;
+ else if (operation == ECM_IPA_CONNECT)
+ next_state = ECM_IPA_CONNECTED_AND_UP;
+ break;
+ case ECM_IPA_CONNECTED_AND_UP:
+ if (operation == ECM_IPA_STOP)
+ next_state = ECM_IPA_CONNECTED;
+ else if (operation == ECM_IPA_DISCONNECT)
+ next_state = ECM_IPA_UP;
break;
default:
- result = false;
+ ECM_IPA_ERROR("State is not supported\n");
break;
}
- pr_debug("state transition (%d->%d)- %s\n", current_mode,
- new_mode , result ? "Allowed" : "Forbidden");
- return result;
+ pr_debug("state transition ( %s -> %s )- %s\n",
+ ecm_ipa_state_string(current_state),
+ ecm_ipa_state_string(next_state) ,
+ next_state == ECM_IPA_INVALID ?
+ "Forbidden" : "Allowed");
+
+ return next_state;
+}
+
+/**
+ * ecm_ipa_state_string - return the state string representation
+ * @state: enum which describe the state
+ */
+static const char *ecm_ipa_state_string(enum ecm_ipa_state state)
+{
+ switch (state) {
+ case ECM_IPA_UNLOADED:
+ return "ECM_IPA_UNLOADED";
+ case ECM_IPA_INITIALIZED:
+ return "ECM_IPA_INITIALIZED";
+ case ECM_IPA_CONNECTED:
+ return "ECM_IPA_CONNECTED";
+ case ECM_IPA_UP:
+ return "ECM_IPA_UP";
+ case ECM_IPA_CONNECTED_AND_UP:
+ return "ECM_IPA_CONNECTED_AND_UP";
+ default:
+ return "Not supported";
+ }
}
/**
diff --git a/drivers/net/wireless/wcnss/wcnss_prealloc.c b/drivers/net/wireless/wcnss/wcnss_prealloc.c
index 7d10657..c450bcb 100644
--- a/drivers/net/wireless/wcnss/wcnss_prealloc.c
+++ b/drivers/net/wireless/wcnss/wcnss_prealloc.c
@@ -13,8 +13,9 @@
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/wcnss_wlan.h>
+#include <linux/spinlock.h>
-static DEFINE_MUTEX(alloc_lock);
+static DEFINE_SPINLOCK(alloc_lock);
struct wcnss_prealloc {
int occupied;
@@ -57,15 +58,18 @@
{
int i = 0;
- for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++)
+ for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
kfree(wcnss_allocs[i].ptr);
+ wcnss_allocs[i].ptr = NULL;
+ }
}
void *wcnss_prealloc_get(unsigned int size)
{
int i = 0;
+ unsigned long flags;
- mutex_lock(&alloc_lock);
+ spin_lock_irqsave(&alloc_lock, flags);
for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
if (wcnss_allocs[i].occupied)
continue;
@@ -73,12 +77,13 @@
if (wcnss_allocs[i].size > size) {
/* we found the slot */
wcnss_allocs[i].occupied = 1;
- mutex_unlock(&alloc_lock);
+ spin_unlock_irqrestore(&alloc_lock, flags);
return wcnss_allocs[i].ptr;
}
}
- pr_err("wcnss: %s: prealloc not available\n", __func__);
- mutex_unlock(&alloc_lock);
+ spin_unlock_irqrestore(&alloc_lock, flags);
+ pr_err("wcnss: %s: prealloc not available for size: %d\n",
+ __func__, size);
return NULL;
}
@@ -87,16 +92,17 @@
int wcnss_prealloc_put(void *ptr)
{
int i = 0;
+ unsigned long flags;
- mutex_lock(&alloc_lock);
+ spin_lock_irqsave(&alloc_lock, flags);
for (i = 0; i < ARRAY_SIZE(wcnss_allocs); i++) {
if (wcnss_allocs[i].ptr == ptr) {
wcnss_allocs[i].occupied = 0;
- mutex_unlock(&alloc_lock);
+ spin_unlock_irqrestore(&alloc_lock, flags);
return 1;
}
}
- mutex_unlock(&alloc_lock);
+ spin_unlock_irqrestore(&alloc_lock, flags);
return 0;
}
diff --git a/drivers/net/wireless/wcnss/wcnss_wlan.c b/drivers/net/wireless/wcnss/wcnss_wlan.c
index e8b8fc2..0b4f0fe 100644
--- a/drivers/net/wireless/wcnss/wcnss_wlan.c
+++ b/drivers/net/wireless/wcnss/wcnss_wlan.c
@@ -79,6 +79,15 @@
#define CCU_RIVA_LAST_ADDR1_OFFSET 0x108
#define CCU_RIVA_LAST_ADDR2_OFFSET 0x10c
+#define PRONTO_PMU_SPARE_OFFSET 0x1088
+
+#define PRONTO_PMU_GDSCR_OFFSET 0x0024
+#define PRONTO_PMU_GDSCR_SW_COLLAPSE BIT(0)
+#define PRONTO_PMU_GDSCR_HW_CTRL BIT(1)
+
+#define PRONTO_PMU_CBCR_OFFSET 0x0008
+#define PRONTO_PMU_CBCR_CLK_EN BIT(0)
+
#define MSM_PRONTO_A2XB_BASE 0xfb100400
#define A2XB_CFG_OFFSET 0x00
#define A2XB_INT_SRC_OFFSET 0x0c
@@ -419,6 +428,28 @@
void __iomem *reg_addr, *tst_addr, *tst_ctrl_addr;
u32 reg = 0;
+
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ pr_info_ratelimited("%s: PRONTO_PMU_SPARE %08x\n", __func__, reg);
+
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_GDSCR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ reg >>= 31;
+
+ if (!reg) {
+ pr_info_ratelimited("%s: Cannot log, Pronto common SS is power collapsed\n",
+ __func__);
+ return;
+ }
+ reg &= ~(PRONTO_PMU_GDSCR_SW_COLLAPSE | PRONTO_PMU_GDSCR_HW_CTRL);
+ writel_relaxed(reg, reg_addr);
+
+ reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CBCR_OFFSET;
+ reg = readl_relaxed(reg_addr);
+ reg |= PRONTO_PMU_CBCR_CLK_EN;
+ writel_relaxed(reg, reg_addr);
+
reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
reg = readl_relaxed(reg_addr);
pr_info_ratelimited("%s: A2XB_CFG_OFFSET %08x\n", __func__, reg);
@@ -675,7 +706,7 @@
static int __devinit
wcnss_wlan_ctrl_probe(struct platform_device *pdev)
{
- if (!penv)
+ if (!penv || !penv->triggered)
return -ENODEV;
penv->smd_channel_ready = 1;
@@ -730,7 +761,7 @@
{
int ret = 0;
- if (!penv)
+ if (!penv || !penv->triggered)
return -ENODEV;
ret = smd_named_open_on_edge(WCNSS_CTRL_CHANNEL, SMD_APPS_WCNSS,
@@ -1573,15 +1604,6 @@
goto fail_power;
}
- /* trigger initialization of the WCNSS */
- penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
- if (IS_ERR(penv->pil)) {
- dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
- ret = PTR_ERR(penv->pil);
- penv->pil = NULL;
- goto fail_pil;
- }
-
/* allocate resources */
penv->mmio_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"wcnss_mmio");
@@ -1613,7 +1635,7 @@
if (!penv->msm_wcnss_base) {
ret = -ENOMEM;
pr_err("%s: ioremap wcnss physical failed\n", __func__);
- goto fail_wake;
+ goto fail_ioremap;
}
if (wcnss_hardware_type() == WCNSS_RIVA_HW) {
@@ -1621,20 +1643,20 @@
if (!penv->riva_ccu_base) {
ret = -ENOMEM;
pr_err("%s: ioremap wcnss physical failed\n", __func__);
- goto fail_ioremap;
+ goto fail_ioremap2;
}
} else {
penv->pronto_a2xb_base = ioremap(MSM_PRONTO_A2XB_BASE, SZ_512);
if (!penv->pronto_a2xb_base) {
ret = -ENOMEM;
pr_err("%s: ioremap wcnss physical failed\n", __func__);
- goto fail_ioremap;
+ goto fail_ioremap2;
}
penv->pronto_ccpu_base = ioremap(MSM_PRONTO_CCPU_BASE, SZ_512);
if (!penv->pronto_ccpu_base) {
ret = -ENOMEM;
pr_err("%s: ioremap wcnss physical failed\n", __func__);
- goto fail_ioremap2;
+ goto fail_ioremap3;
}
/* for reset FIQ */
res = platform_get_resource_byname(penv->pdev,
@@ -1642,31 +1664,45 @@
if (!res) {
dev_err(&pdev->dev, "insufficient irq mem resources\n");
ret = -ENOENT;
- goto fail_ioremap3;
+ goto fail_ioremap4;
}
penv->fiq_reg = ioremap_nocache(res->start, resource_size(res));
if (!penv->fiq_reg) {
pr_err("wcnss: %s: ioremap_nocache() failed fiq_reg addr:%pr\n",
__func__, &res->start);
ret = -ENOMEM;
- goto fail_ioremap3;
+ goto fail_ioremap4;
}
}
+ /* trigger initialization of the WCNSS */
+ penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
+ if (IS_ERR(penv->pil)) {
+ dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
+ ret = PTR_ERR(penv->pil);
+ penv->pil = NULL;
+ goto fail_pil;
+ }
+
return 0;
+fail_pil:
+ if (penv->riva_ccu_base)
+ iounmap(penv->riva_ccu_base);
+ if (penv->fiq_reg)
+ iounmap(penv->fiq_reg);
+fail_ioremap4:
+ if (penv->pronto_ccpu_base)
+ iounmap(penv->pronto_ccpu_base);
fail_ioremap3:
- iounmap(penv->pronto_ccpu_base);
+ if (penv->pronto_a2xb_base)
+ iounmap(penv->pronto_a2xb_base);
fail_ioremap2:
- iounmap(penv->pronto_a2xb_base);
+ if (penv->msm_wcnss_base)
+ iounmap(penv->msm_wcnss_base);
fail_ioremap:
- iounmap(penv->msm_wcnss_base);
-fail_wake:
wake_lock_destroy(&penv->wcnss_wake_lock);
fail_res:
- if (penv->pil)
- subsystem_put(penv->pil);
-fail_pil:
wcnss_wlan_power(&pdev->dev, &penv->wlan_config,
WCNSS_WLAN_SWITCH_OFF);
fail_power:
diff --git a/drivers/platform/msm/ipa/a2_service.c b/drivers/platform/msm/ipa/a2_service.c
index 0d77741..8e79185 100644
--- a/drivers/platform/msm/ipa/a2_service.c
+++ b/drivers/platform/msm/ipa/a2_service.c
@@ -278,7 +278,8 @@
A2_MUX_COMPLETION_TIMEOUT);
a2_mux_ctx->wait_for_ack = 0;
if (unlikely(ret == 0)) {
- IPADBG("%s timeout previous ack\n", __func__);
+ IPAERR("%s previous ack from modem timed out\n",
+ __func__);
goto bail;
}
}
@@ -288,7 +289,7 @@
ret = wait_for_completion_timeout(&a2_mux_ctx->ul_wakeup_ack_completion,
A2_MUX_COMPLETION_TIMEOUT);
if (unlikely(ret == 0)) {
- IPADBG("%s timeout wakeup ack\n", __func__);
+ IPAERR("%s wakup ack from modem timed out\n", __func__);
goto bail;
}
INIT_COMPLETION(a2_mux_ctx->bam_connection_completion);
@@ -297,7 +298,7 @@
&a2_mux_ctx->bam_connection_completion,
A2_MUX_COMPLETION_TIMEOUT);
if (unlikely(ret == 0)) {
- IPADBG("%s timeout power on\n", __func__);
+ IPAERR("%s modem power on timed out\n", __func__);
goto bail;
}
}
@@ -450,7 +451,8 @@
&a2_mux_ctx->dl_wakeup_completion,
A2_MUX_COMPLETION_TIMEOUT);
if (unlikely(ret == 0)) {
- IPAERR("%s timeout A2 PROD\n", __func__);
+ IPAERR("%s timeout waiting for A2 PROD granted\n",
+ __func__);
BUG();
return;
}
@@ -475,8 +477,8 @@
&a2_mux_ctx->request_resource_completion,
A2_MUX_COMPLETION_TIMEOUT);
if (unlikely(ret == 0)) {
- IPADBG("%s timeout request A2 PROD resource\n",
- __func__);
+ IPAERR("%s timeout waiting for A2 PROD granted\n",
+ __func__);
BUG();
return;
}
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 67c86b9..1cbd514 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -50,7 +50,6 @@
#define IPA_AGGR_STR_IN_BYTES(str) \
(strnlen((str), IPA_AGGR_MAX_STR_LENGTH - 1) + 1)
-
static struct ipa_plat_drv_res ipa_res = {0, };
static struct of_device_id ipa_plat_drv_match[] = {
{
@@ -197,6 +196,8 @@
if (_IOC_NR(cmd) >= IPA_IOCTL_MAX)
return -ENOTTY;
+ ipa_inc_client_enable_clks();
+
switch (cmd) {
case IPA_IOC_ALLOC_NAT_MEM:
if (copy_from_user((u8 *)&nat_mem, (u8 *)arg,
@@ -639,10 +640,13 @@
rm_depend.depends_on_name);
break;
default: /* redundant, as cmd was checked against MAXNR */
+ ipa_dec_client_disable_clks();
return -ENOTTY;
}
kfree(param);
+ ipa_dec_client_disable_clks();
+
return retval;
}
@@ -1730,6 +1734,22 @@
result = -ENOMEM;
goto fail_rt_tbl_cache;
}
+ ipa_ctx->tx_pkt_wrapper_cache =
+ kmem_cache_create("IPA TX PKT WRAPPER",
+ sizeof(struct ipa_tx_pkt_wrapper), 0, 0, NULL);
+ if (!ipa_ctx->tx_pkt_wrapper_cache) {
+ IPAERR(":ipa tx pkt wrapper cache create failed\n");
+ result = -ENOMEM;
+ goto fail_tx_pkt_wrapper_cache;
+ }
+ ipa_ctx->rx_pkt_wrapper_cache =
+ kmem_cache_create("IPA RX PKT WRAPPER",
+ sizeof(struct ipa_rx_pkt_wrapper), 0, 0, NULL);
+ if (!ipa_ctx->rx_pkt_wrapper_cache) {
+ IPAERR(":ipa rx pkt wrapper cache create failed\n");
+ result = -ENOMEM;
+ goto fail_rx_pkt_wrapper_cache;
+ }
ipa_ctx->tree_node_cache =
kmem_cache_create("IPA TREE", sizeof(struct ipa_tree_node), 0, 0,
NULL);
@@ -1798,8 +1818,6 @@
mutex_init(&ipa_ctx->lock);
mutex_init(&ipa_ctx->nat_mem.lock);
- skb_queue_head_init(&ipa_ctx->rx_list);
-
for (i = 0; i < IPA_A5_SYS_MAX; i++) {
INIT_LIST_HEAD(&ipa_ctx->sys[i].head_desc_list);
spin_lock_init(&ipa_ctx->sys[i].spinlock);
@@ -1813,15 +1831,15 @@
atomic_set(&ipa_ctx->sys[i].curr_polling_state, 0);
}
- ipa_ctx->rx_wq = alloc_workqueue("ipa rx wq", WQ_MEM_RECLAIM |
- WQ_CPU_INTENSIVE, 1);
+ ipa_ctx->rx_wq = create_singlethread_workqueue("ipa rx wq");
if (!ipa_ctx->rx_wq) {
IPAERR(":fail to create rx wq\n");
result = -ENOMEM;
goto fail_rx_wq;
}
- ipa_ctx->tx_wq = create_singlethread_workqueue("ipa tx wq");
+ ipa_ctx->tx_wq = alloc_workqueue("ipa tx wq", WQ_MEM_RECLAIM |
+ WQ_CPU_INTENSIVE, 2);
if (!ipa_ctx->tx_wq) {
IPAERR(":fail to create tx wq\n");
result = -ENOMEM;
@@ -1974,6 +1992,10 @@
fail_dma_pool:
kmem_cache_destroy(ipa_ctx->tree_node_cache);
fail_tree_node_cache:
+ kmem_cache_destroy(ipa_ctx->rx_pkt_wrapper_cache);
+fail_rx_pkt_wrapper_cache:
+ kmem_cache_destroy(ipa_ctx->tx_pkt_wrapper_cache);
+fail_tx_pkt_wrapper_cache:
kmem_cache_destroy(ipa_ctx->rt_tbl_cache);
fail_rt_tbl_cache:
kmem_cache_destroy(ipa_ctx->hdr_offset_cache);
diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c
index ae59f37..5c343e8 100644
--- a/drivers/platform/msm/ipa/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_client.c
@@ -9,7 +9,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-
#include <linux/delay.h>
#include "ipa_i.h"
@@ -251,26 +250,6 @@
memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context));
- if (IPA_CLIENT_IS_CONS(in->client)) {
- ep->cmd = kzalloc(sizeof(struct ipa_ip_packet_init),
- GFP_KERNEL);
- if (!ep->cmd) {
- IPAERR("failed to alloc immediate command object\n");
- result = -ENOMEM;
- goto fail;
- }
- ep->cmd->destination_pipe_index = ipa_ep_idx;
- ep->dma_addr = dma_map_single(NULL, ep->cmd,
- sizeof(struct ipa_ip_packet_init),
- DMA_TO_DEVICE);
- if (ep->dma_addr == 0 || ep->dma_addr == ~0) {
- IPAERR("failed to DMA MAP pkt_init\n");
- result = -ENOMEM;
- kfree(ep->cmd);
- goto fail;
- }
- }
-
ep->valid = 1;
ep->client = in->client;
ep->client_notify = in->notify;
@@ -447,13 +426,6 @@
return -EPERM;
}
- if (IPA_CLIENT_IS_CONS(ep->client)) {
- dma_unmap_single(NULL, ep->dma_addr,
- sizeof(struct ipa_ip_packet_init),
- DMA_TO_DEVICE);
- kfree(ep->cmd);
- }
-
ipa_enable_data_path(clnt_hdl);
memset(&ipa_ctx->ep[clnt_hdl], 0, sizeof(struct ipa_ep_context));
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index c564922..ba81e5d 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -17,23 +17,21 @@
#include <linux/netdevice.h>
#include "ipa_i.h"
+
#define list_next_entry(pos, member) \
list_entry(pos->member.next, typeof(*pos), member)
+#define IPA_LAST_DESC_CNT 0xFFFF
#define POLLING_INACTIVITY_RX 40
-#define POLLING_MIN_SLEEP_RX 2350
-#define POLLING_MAX_SLEEP_RX 2450
-#define POLLING_INACTIVITY_TX 10
-#define POLLING_MIN_SLEEP_TX 100
-#define POLLING_MAX_SLEEP_TX 200
-#define RX_MAX_IND 40
+#define POLLING_MIN_SLEEP_RX 950
+#define POLLING_MAX_SLEEP_RX 1050
+#define POLLING_INACTIVITY_TX 40
+#define POLLING_MIN_SLEEP_TX 400
+#define POLLING_MAX_SLEEP_TX 500
static void replenish_rx_work_func(struct work_struct *work);
static struct delayed_work replenish_rx_work;
static void ipa_wq_handle_rx(struct work_struct *work);
static DECLARE_WORK(rx_work, ipa_wq_handle_rx);
-static void ipa_wq_handle_tx(struct work_struct *work);
-static DECLARE_WORK(tx_work, ipa_wq_handle_tx);
-
/**
* ipa_write_done() - this function will be (eventually) called when a Tx
* operation is complete
@@ -83,7 +81,7 @@
if (tx_pkt->callback)
tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
- kfree(tx_pkt);
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
}
int ipa_handle_tx_core(struct ipa_sys_context *sys, bool process_all,
@@ -121,13 +119,23 @@
IPADBG("--curr_cnt=%d\n", sys->len);
- if (tx_pkt->callback) {
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
+ dma_pool_free(ipa_ctx->dma_pool,
+ tx_pkt->bounce,
+ tx_pkt->mem.phys_base);
+ else
dma_unmap_single(NULL, tx_pkt->mem.phys_base,
- tx_pkt->mem.size, DMA_TO_DEVICE);
- tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
- }
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
- kfree(tx_pkt);
+ if (tx_pkt->callback)
+ tx_pkt->callback(tx_pkt->user1, tx_pkt->user2);
+
+ if (tx_pkt->cnt > 1 && tx_pkt->cnt != IPA_LAST_DESC_CNT)
+ dma_pool_free(ipa_ctx->dma_pool, tx_pkt->mult.base,
+ tx_pkt->mult.phys_base);
+
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
cnt++;
};
@@ -146,6 +154,11 @@
goto fail;
}
+ ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ goto fail;
+ }
sys->event.options = SPS_O_EOT;
ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
if (ret) {
@@ -192,7 +205,9 @@
static void ipa_wq_handle_tx(struct work_struct *work)
{
- ipa_handle_tx(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT]);
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ tx_pkt = container_of(work, struct ipa_tx_pkt_wrapper, work);
+ ipa_handle_tx(tx_pkt->sys);
}
/**
@@ -225,7 +240,7 @@
if (unlikely(!in_atomic))
mem_flag = GFP_KERNEL;
- tx_pkt = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), mem_flag);
+ tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache, mem_flag);
if (!tx_pkt) {
IPAERR("failed to alloc tx wrapper\n");
goto fail_mem_alloc;
@@ -281,11 +296,14 @@
IPADBG("sending cmd=%d pyld_len=%d sps_flags=%x\n",
desc->opcode, desc->len, sps_flags);
IPA_DUMP_BUFF(desc->pyld, dma_address, desc->len);
+ INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
} else {
len = desc->len;
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
}
- INIT_WORK(&tx_pkt->work, ipa_wq_write_done);
+ if (unlikely(ipa_ctx->polling_mode))
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
spin_lock_irqsave(&sys->spinlock, irq_flags);
list_add_tail(&tx_pkt->link, &sys->head_desc_list);
@@ -309,12 +327,192 @@
else
dma_unmap_single(NULL, dma_address, desc->len, DMA_TO_DEVICE);
fail_dma_map:
- kfree(tx_pkt);
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
fail_mem_alloc:
return -EFAULT;
}
/**
+ * ipa_send() - Send multiple descriptors in one HW transaction
+ * @sys: system pipe context
+ * @num_desc: number of packets
+ * @desc: packets to send (may be immediate command or data)
+ * @in_atomic: whether caller is in atomic context
+ *
+ * This function is used for system-to-bam connection.
+ * - SPS driver expect struct sps_transfer which will contain all the data
+ * for a transaction
+ * - The sps_transfer struct will be pointing to bounce buffers for
+ * its DMA command (immediate command and data)
+ * - ipa_tx_pkt_wrapper will be used for each ipa
+ * descriptor (allocated from wrappers cache)
+ * - The wrapper struct will be configured for each ipa-desc payload and will
+ * contain information which will be later used by the user callbacks
+ * - each transfer will be made by calling to sps_transfer()
+ * - Each packet (command or data) that will be sent will also be saved in
+ * ipa_sys_context for later check that all data was sent
+ *
+ * Return codes: 0: success, -EFAULT: failure
+ */
+int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
+ bool in_atomic)
+{
+ struct ipa_tx_pkt_wrapper *tx_pkt;
+ struct ipa_tx_pkt_wrapper *next_pkt;
+ struct sps_transfer transfer = { 0 };
+ struct sps_iovec *iovec;
+ unsigned long irq_flags;
+ dma_addr_t dma_addr;
+ int i = 0;
+ int j;
+ int result;
+ int fail_dma_wrap = 0;
+ uint size = num_desc * sizeof(struct sps_iovec);
+ u32 mem_flag = GFP_ATOMIC;
+
+ if (unlikely(!in_atomic))
+ mem_flag = GFP_KERNEL;
+
+ transfer.iovec = dma_pool_alloc(ipa_ctx->dma_pool, mem_flag, &dma_addr);
+ transfer.iovec_phys = dma_addr;
+ transfer.iovec_count = num_desc;
+ spin_lock_irqsave(&sys->spinlock, irq_flags);
+ if (!transfer.iovec) {
+ IPAERR("fail to alloc DMA mem for sps xfr buff\n");
+ goto failure_coherent;
+ }
+
+ for (i = 0; i < num_desc; i++) {
+ fail_dma_wrap = 0;
+ tx_pkt = kmem_cache_zalloc(ipa_ctx->tx_pkt_wrapper_cache,
+ mem_flag);
+ if (!tx_pkt) {
+ IPAERR("failed to alloc tx wrapper\n");
+ goto failure;
+ }
+ /*
+ * first desc of set is "special" as it holds the count and
+ * other info
+ */
+ if (i == 0) {
+ transfer.user = tx_pkt;
+ tx_pkt->mult.phys_base = dma_addr;
+ tx_pkt->mult.base = transfer.iovec;
+ tx_pkt->mult.size = size;
+ tx_pkt->cnt = num_desc;
+ INIT_WORK(&tx_pkt->work, ipa_wq_handle_tx);
+ }
+
+ iovec = &transfer.iovec[i];
+ iovec->flags = 0;
+
+ INIT_LIST_HEAD(&tx_pkt->link);
+ tx_pkt->type = desc[i].type;
+
+ tx_pkt->mem.base = desc[i].pyld;
+ tx_pkt->mem.size = desc[i].len;
+
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0)) {
+ WARN_ON(tx_pkt->mem.size > 512);
+
+ /*
+ * Due to a HW limitation, we need to make sure that the
+ * packet does not cross a 1KB boundary
+ */
+ tx_pkt->bounce =
+ dma_pool_alloc(ipa_ctx->dma_pool,
+ mem_flag,
+ &tx_pkt->mem.phys_base);
+ if (!tx_pkt->bounce) {
+ tx_pkt->mem.phys_base = 0;
+ } else {
+ WARN_ON(!ipa_straddle_boundary(
+ (u32)tx_pkt->mem.phys_base,
+ (u32)tx_pkt->mem.phys_base +
+ tx_pkt->mem.size - 1, 1024));
+ memcpy(tx_pkt->bounce, tx_pkt->mem.base,
+ tx_pkt->mem.size);
+ }
+ } else {
+ tx_pkt->mem.phys_base =
+ dma_map_single(NULL, tx_pkt->mem.base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ }
+ if (!tx_pkt->mem.phys_base) {
+ IPAERR("failed to alloc tx wrapper\n");
+ fail_dma_wrap = 1;
+ goto failure;
+ }
+
+ tx_pkt->sys = sys;
+ tx_pkt->callback = desc[i].callback;
+ tx_pkt->user1 = desc[i].user1;
+ tx_pkt->user2 = desc[i].user2;
+
+ /*
+ * Point the iovec to the bounce buffer and
+ * add this packet to system pipe context.
+ */
+ iovec->addr = tx_pkt->mem.phys_base;
+ list_add_tail(&tx_pkt->link, &sys->head_desc_list);
+
+ /*
+ * Special treatment for immediate commands, where the structure
+ * of the descriptor is different
+ */
+ if (desc[i].type == IPA_IMM_CMD_DESC) {
+ iovec->size = desc[i].opcode;
+ iovec->flags |= SPS_IOVEC_FLAG_IMME;
+ } else {
+ iovec->size = desc[i].len;
+ }
+
+ if (i == (num_desc - 1)) {
+ iovec->flags |= SPS_IOVEC_FLAG_EOT;
+ /* "mark" the last desc */
+ tx_pkt->cnt = IPA_LAST_DESC_CNT;
+ }
+ }
+
+ result = sps_transfer(sys->ep->ep_hdl, &transfer);
+ if (result) {
+ IPAERR("sps_transfer failed rc=%d\n", result);
+ goto failure;
+ }
+
+ spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+ return 0;
+
+failure:
+ tx_pkt = transfer.user;
+ for (j = 0; j < i; j++) {
+ next_pkt = list_next_entry(tx_pkt, link);
+ list_del(&tx_pkt->link);
+ if (unlikely(ipa_ctx->ipa_hw_type == IPA_HW_v1_0))
+ dma_pool_free(ipa_ctx->dma_pool,
+ tx_pkt->bounce,
+ tx_pkt->mem.phys_base);
+ else
+ dma_unmap_single(NULL, tx_pkt->mem.phys_base,
+ tx_pkt->mem.size,
+ DMA_TO_DEVICE);
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+ tx_pkt = next_pkt;
+ }
+ if (i < num_desc)
+ /* last desc failed */
+ if (fail_dma_wrap)
+ kmem_cache_free(ipa_ctx->tx_pkt_wrapper_cache, tx_pkt);
+ if (transfer.iovec_phys)
+ dma_pool_free(ipa_ctx->dma_pool, transfer.iovec,
+ transfer.iovec_phys);
+failure_coherent:
+ spin_unlock_irqrestore(&sys->spinlock, irq_flags);
+ return -EFAULT;
+}
+
+/**
* ipa_sps_irq_cmd_ack - callback function which will be called by SPS driver after an
* immediate command is complete.
* @user1: pointer to the descriptor of the transfer
@@ -345,6 +543,7 @@
*/
int ipa_send_cmd(u16 num_desc, struct ipa_desc *descr)
{
+ struct ipa_desc *desc;
int result = 0;
ipa_inc_client_enable_clks();
@@ -364,10 +563,22 @@
}
wait_for_completion(&descr->xfer_done);
} else {
- IPAERR("unsupported chaining multiple IC\n");
+ desc = &descr[num_desc - 1];
+ init_completion(&desc->xfer_done);
+
+ if (desc->callback || desc->user1)
+ WARN_ON(1);
+
+ desc->callback = ipa_sps_irq_cmd_ack;
+ desc->user1 = desc;
+ if (ipa_send(&ipa_ctx->sys[IPA_A5_CMD], num_desc,
+ descr, false)) {
+ IPAERR("fail to send multiple immediate command set\n");
result = -EFAULT;
goto bail;
}
+ wait_for_completion(&desc->xfer_done);
+ }
IPA_STATS_INC_IC_CNT(num_desc, descr, ipa_ctx->stats.imm_cmds);
bail:
@@ -386,13 +597,21 @@
static void ipa_sps_irq_tx_notify(struct sps_event_notify *notify)
{
struct ipa_sys_context *sys = &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT];
+ struct ipa_tx_pkt_wrapper *tx_pkt;
int ret;
IPADBG("event %d notified\n", notify->event_id);
switch (notify->event_id) {
case SPS_EVENT_EOT:
+ tx_pkt = notify->data.transfer.user;
if (!atomic_read(&sys->curr_polling_state)) {
+ ret = sps_get_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ break;
+ }
sys->ep->connect.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
ret = sps_set_config(sys->ep->ep_hdl,
@@ -402,7 +621,7 @@
break;
}
atomic_set(&sys->curr_polling_state, 1);
- queue_work(ipa_ctx->tx_wq, &tx_work);
+ queue_work(ipa_ctx->tx_wq, &tx_pkt->work);
}
break;
default:
@@ -435,47 +654,6 @@
}
}
-static void ipa_handle_tag_rsp(struct ipa_a5_mux_hdr *mux_hdr)
-{
- struct completion *compl;
- struct ipa_tree_node *node;
-
- /* retrieve the compl object from tag value */
- mux_hdr++;
- compl = (struct completion *) ntohl(*((u32 *)mux_hdr));
- IPADBG("%x %x %p\n", *(u32 *)mux_hdr, *((u32 *)mux_hdr + 1), compl);
-
- mutex_lock(&ipa_ctx->lock);
- node = ipa_search(&ipa_ctx->tag_tree, (u32)compl);
- if (node) {
- complete_all(compl);
- rb_erase(&node->node, &ipa_ctx->tag_tree);
- kmem_cache_free(ipa_ctx->tree_node_cache, node);
- } else {
- WARN_ON(1);
- }
- mutex_unlock(&ipa_ctx->lock);
-}
-
-static void ipa_dejitter(bool limit)
-{
- struct sk_buff *skb;
- int len = skb_queue_len(&ipa_ctx->rx_list);
- int i;
- void *cookie;
- ipa_notify_cb cb;
-
- if (limit && len >= RX_MAX_IND)
- len = RX_MAX_IND;
-
- for (i = len; i > 0; i--) {
- skb = __skb_dequeue(&ipa_ctx->rx_list);
- cb = (ipa_notify_cb)*(u32 *)&(skb->cb[0]);
- cookie = (void *)*(u32 *)&(skb->cb[4]);
- cb(cookie, IPA_RECEIVE, (unsigned long)skb);
- }
-}
-
/**
* ipa_handle_rx_core() - The core functionality of packet reception. This
* function is read from multiple code paths.
@@ -497,9 +675,13 @@
struct ipa_rx_pkt_wrapper *rx_pkt;
struct sk_buff *rx_skb;
struct sps_iovec iov;
+ unsigned int pull_len;
+ unsigned int padding;
int ret;
struct ipa_ep_context *ep;
int cnt = 0;
+ struct completion *compl;
+ struct ipa_tree_node *node;
unsigned int src_pipe;
while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
@@ -539,7 +721,7 @@
rx_skb->tail = rx_skb->data + rx_pkt->len;
rx_skb->len = rx_pkt->len;
rx_skb->truesize = rx_pkt->len + sizeof(struct sk_buff);
- kfree(rx_pkt);
+ kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
mux_hdr = (struct ipa_a5_mux_hdr *)rx_skb->data;
@@ -554,9 +736,29 @@
IPA_STATS_INC_CNT(ipa_ctx->stats.rx_pkts);
IPA_STATS_EXCP_CNT(mux_hdr->flags, ipa_ctx->stats.rx_excp_pkts);
- if (mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG) {
- if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL)
- ipa_handle_tag_rsp(mux_hdr);
+ if (unlikely(mux_hdr->flags & IPA_A5_MUX_HDR_EXCP_FLAG_TAG)) {
+ if (ipa_ctx->ipa_hw_mode != IPA_HW_MODE_VIRTUAL) {
+ /* retrieve the compl object from tag value */
+ mux_hdr++;
+ compl = (struct completion *)
+ ntohl(*((u32 *)mux_hdr));
+ IPADBG("%x %x %p\n", *(u32 *)mux_hdr,
+ *((u32 *)mux_hdr + 1), compl);
+
+ mutex_lock(&ipa_ctx->lock);
+ node = ipa_search(&ipa_ctx->tag_tree,
+ (u32)compl);
+ if (node) {
+ complete_all(compl);
+ rb_erase(&node->node,
+ &ipa_ctx->tag_tree);
+ kmem_cache_free(
+ ipa_ctx->tree_node_cache, node);
+ } else {
+ WARN_ON(1);
+ }
+ mutex_unlock(&ipa_ctx->lock);
+ }
dev_kfree_skb(rx_skb);
ipa_replenish_rx_cache();
++cnt;
@@ -567,22 +769,38 @@
* Any packets arriving over AMPDU_TX should be dispatched
* to the regular WLAN RX data-path.
*/
- if (src_pipe == WLAN_AMPDU_TX_EP)
+ if (unlikely(src_pipe == WLAN_AMPDU_TX_EP))
src_pipe = WLAN_PROD_TX_EP;
- WARN_ON(src_pipe >= IPA_NUM_PIPES);
+ if (unlikely(src_pipe >= IPA_NUM_PIPES ||
+ !ipa_ctx->ep[src_pipe].valid ||
+ !ipa_ctx->ep[src_pipe].client_notify)) {
+ IPAERR("drop pipe=%d ep_valid=%d client_notify=%p\n",
+ src_pipe, ipa_ctx->ep[src_pipe].valid,
+ ipa_ctx->ep[src_pipe].client_notify);
+ dev_kfree_skb(rx_skb);
+ ipa_replenish_rx_cache();
+ ++cnt;
+ continue;
+ }
ep = &ipa_ctx->ep[src_pipe];
- IPADBG("pulling %d bytes from skb\n", ep->pull_len);
- skb_pull(rx_skb, ep->pull_len);
+ pull_len = sizeof(struct ipa_a5_mux_hdr);
+
+ /*
+ * IP packet starts on word boundary
+ * remove the MUX header and any padding and pass the frame to
+ * the client which registered a rx callback on the "src pipe"
+ */
+ padding = ep->cfg.hdr.hdr_len & 0x3;
+ if (padding)
+ pull_len += 4 - padding;
+
+ IPADBG("pulling %d bytes from skb\n", pull_len);
+ skb_pull(rx_skb, pull_len);
ipa_replenish_rx_cache();
- if (ep->client_notify) {
- __skb_queue_tail(&ipa_ctx->rx_list, rx_skb);
- *(u32 *)&(rx_skb->cb[0]) = (u32)ep->client_notify;
- *(u32 *)&(rx_skb->cb[4]) = (u32)ep->priv;
- } else {
- dev_kfree_skb(rx_skb);
- }
+ ep->client_notify(ep->priv, IPA_RECEIVE,
+ (unsigned long)(rx_skb));
cnt++;
};
@@ -601,6 +819,11 @@
goto fail;
}
+ ret = sps_get_config(sys->ep->ep_hdl, &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ goto fail;
+ }
sys->event.options = SPS_O_EOT;
ret = sps_register_event(sys->ep->ep_hdl, &sys->event);
if (ret) {
@@ -647,6 +870,12 @@
switch (notify->event_id) {
case SPS_EVENT_EOT:
if (!atomic_read(&sys->curr_polling_state)) {
+ ret = sps_get_config(sys->ep->ep_hdl,
+ &sys->ep->connect);
+ if (ret) {
+ IPAERR("sps_get_config() failed %d\n", ret);
+ break;
+ }
sys->ep->connect.options = SPS_O_AUTO_ENABLE |
SPS_O_ACK_TRANSFERS | SPS_O_POLL;
ret = sps_set_config(sys->ep->ep_hdl,
@@ -696,10 +925,8 @@
} else {
inactive_cycles = 0;
}
- ipa_dejitter(true);
} while (inactive_cycles <= POLLING_INACTIVITY_RX);
- ipa_dejitter(false);
ipa_rx_switch_to_intr_mode(sys);
ipa_dec_client_disable_clks();
}
@@ -835,7 +1062,6 @@
break;
case 2:
sys_idx = ipa_ep_idx;
- ipa_ctx->sys[sys_idx].max_len = sys_in->desc_fifo_sz / 8 - 2;
INIT_DELAYED_WORK(&ipa_ctx->sys[sys_idx].switch_to_intr_work,
switch_to_intr_tx_work_func);
break;
@@ -950,87 +1176,9 @@
dev_kfree_skb(skb);
}
-static int ipa_send_two(struct sk_buff *skb, struct ipa_sys_context *sys,
- int dst_ep_idx)
+static void ipa_tx_cmd_comp(void *user1, void *user2)
{
- struct ipa_tx_pkt_wrapper *tx_pktc;
- struct ipa_tx_pkt_wrapper *tx_pktd;
- struct ipa_ep_context *ep = &ipa_ctx->ep[dst_ep_idx];
- unsigned long irq_flags;
- dma_addr_t dma_addrd;
- int rc = -ENOMEM;
-
- tx_pktc = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
- if (!tx_pktc) {
- IPAERR("failed to alloc tx wrapper C\n");
- goto fail_mem_alloc_c;
- }
-
- tx_pktd = kmalloc(sizeof(struct ipa_tx_pkt_wrapper), GFP_ATOMIC);
- if (!tx_pktd) {
- IPAERR("failed to alloc tx wrapper D\n");
- goto fail_mem_alloc_d;
- }
-
- dma_addrd = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
- if (!dma_addrd) {
- IPAERR("failed to DMA wrap\n");
- goto fail_dma_map_d;
- }
-
- INIT_LIST_HEAD(&tx_pktc->link);
- tx_pktc->callback = NULL;
-
- INIT_LIST_HEAD(&tx_pktd->link);
- tx_pktd->mem.phys_base = dma_addrd;
- tx_pktd->mem.base = skb->data;
- tx_pktd->mem.size = skb->len;
- tx_pktd->callback = ipa_tx_comp_usr_notify_release;
- tx_pktd->user1 = skb;
- tx_pktd->user2 = (void *)dst_ep_idx;
-
- spin_lock_irqsave(&sys->spinlock, irq_flags);
- if (sys->len >= sys->max_len)
- goto fail_oom;
- list_add_tail(&tx_pktc->link, &sys->head_desc_list);
- if (sps_transfer_one(sys->ep->ep_hdl, ep->dma_addr, IPA_IP_PACKET_INIT,
- tx_pktc, SPS_IOVEC_FLAG_IMME |
- SPS_IOVEC_FLAG_NO_SUBMIT))
- IPAERR("sps_transfer_one 0 failed\n");
- list_add_tail(&tx_pktd->link, &sys->head_desc_list);
- if (sps_transfer_one(sys->ep->ep_hdl, dma_addrd, skb->len, tx_pktd,
- SPS_IOVEC_FLAG_EOT | SPS_IOVEC_FLAG_INT))
- IPAERR("sps_transfer_one 1 failed\n");
- sys->len += 2;
- spin_unlock_irqrestore(&sys->spinlock, irq_flags);
- return 0;
-
-fail_oom:
- dma_unmap_single(NULL, dma_addrd, skb->len, DMA_TO_DEVICE);
-fail_dma_map_d:
- kfree(tx_pktd);
-fail_mem_alloc_d:
- kfree(tx_pktc);
-fail_mem_alloc_c:
- return rc;
-}
-
-static int ipa_send_data_hw_path(struct sk_buff *skb,
- struct ipa_sys_context *sys, int dst_ep_idx)
-{
- struct ipa_desc desc;
-
- desc.pyld = skb->data;
- desc.len = skb->len;
- desc.type = IPA_DATA_DESC_SKB;
- desc.callback = ipa_tx_comp_usr_notify_release;
- desc.user1 = skb;
- desc.user2 = (void *)dst_ep_idx;
-
- if (ipa_send_one(sys, &desc, true))
- return -EFAULT;
-
- return 0;
+ kfree(user1);
}
/**
@@ -1063,42 +1211,76 @@
int ipa_tx_dp(enum ipa_client_type dst, struct sk_buff *skb,
struct ipa_tx_meta *meta)
{
+ struct ipa_desc desc[2];
int ipa_ep_idx;
+ struct ipa_ip_packet_init *cmd;
+
+ memset(&desc, 0, 2 * sizeof(struct ipa_desc));
ipa_ep_idx = ipa_get_ep_mapping(ipa_ctx->mode, dst);
if (unlikely(ipa_ep_idx == -1)) {
IPAERR("dest EP does not exist.\n");
- goto fail;
+ goto fail_gen;
}
if (unlikely(ipa_ctx->ep[ipa_ep_idx].valid == 0)) {
IPAERR("dest EP not valid.\n");
- goto fail;
+ goto fail_gen;
}
if (IPA_CLIENT_IS_CONS(dst)) {
- if (ipa_send_two(skb, &ipa_ctx->sys[IPA_A5_LAN_WAN_OUT],
- ipa_ep_idx)) {
- IPAERR("fail to send pkt_init+skb dst=%d skb=%p\n",
- dst, skb);
- goto fail;
+ cmd = kzalloc(sizeof(struct ipa_ip_packet_init), GFP_ATOMIC);
+ if (!cmd) {
+ IPAERR("failed to alloc immediate command object\n");
+ goto fail_mem_alloc;
+ }
+
+ cmd->destination_pipe_index = ipa_ep_idx;
+ if (meta && meta->mbim_stream_id_valid)
+ cmd->metadata = meta->mbim_stream_id;
+ desc[0].opcode = IPA_IP_PACKET_INIT;
+ desc[0].pyld = cmd;
+ desc[0].len = sizeof(struct ipa_ip_packet_init);
+ desc[0].type = IPA_IMM_CMD_DESC;
+ desc[0].callback = ipa_tx_cmd_comp;
+ desc[0].user1 = cmd;
+ desc[1].pyld = skb->data;
+ desc[1].len = skb->len;
+ desc[1].type = IPA_DATA_DESC_SKB;
+ desc[1].callback = ipa_tx_comp_usr_notify_release;
+ desc[1].user1 = skb;
+ desc[1].user2 = (void *)ipa_ep_idx;
+
+ if (ipa_send(&ipa_ctx->sys[IPA_A5_LAN_WAN_OUT], 2, desc,
+ true)) {
+ IPAERR("fail to send immediate command\n");
+ goto fail_send;
}
IPA_STATS_INC_CNT(ipa_ctx->stats.imm_cmds[IPA_IP_PACKET_INIT]);
} else if (dst == IPA_CLIENT_A5_WLAN_AMPDU_PROD) {
- if (ipa_send_data_hw_path(skb,
- &ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
- ipa_ep_idx)) {
- IPAERR("fail to send skb dst=%d skb=%p\n", dst, skb);
- goto fail;
+ desc[0].pyld = skb->data;
+ desc[0].len = skb->len;
+ desc[0].type = IPA_DATA_DESC_SKB;
+ desc[0].callback = ipa_tx_comp_usr_notify_release;
+ desc[0].user1 = skb;
+ desc[0].user2 = (void *)ipa_ep_idx;
+
+ if (ipa_send_one(&ipa_ctx->sys[IPA_A5_WLAN_AMPDU_OUT],
+ &desc[0], true)) {
+ IPAERR("fail to send skb\n");
+ goto fail_gen;
}
} else {
IPAERR("%d PROD is not supported.\n", dst);
- goto fail;
+ goto fail_gen;
}
return 0;
-fail:
+fail_send:
+ kfree(cmd);
+fail_mem_alloc:
+fail_gen:
return -EFAULT;
}
EXPORT_SYMBOL(ipa_tx_dp);
@@ -1134,7 +1316,8 @@
rx_len_cached = sys->len;
while (rx_len_cached < IPA_RX_POOL_CEIL) {
- rx_pkt = kmalloc(sizeof(struct ipa_rx_pkt_wrapper), flag);
+ rx_pkt = kmem_cache_zalloc(ipa_ctx->rx_pkt_wrapper_cache,
+ flag);
if (!rx_pkt) {
IPAERR("failed to alloc rx wrapper\n");
goto fail_kmem_cache_alloc;
@@ -1182,7 +1365,7 @@
fail_dma_mapping:
dev_kfree_skb(rx_pkt->skb);
fail_skb_alloc:
- kfree(rx_pkt);
+ kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
fail_kmem_cache_alloc:
if (rx_len_cached == 0) {
IPA_STATS_INC_CNT(ipa_ctx->stats.rx_repl_repost);
@@ -1214,7 +1397,7 @@
dma_unmap_single(NULL, rx_pkt->dma_address, IPA_RX_SKB_SIZE,
DMA_FROM_DEVICE);
dev_kfree_skb(rx_pkt->skb);
- kfree(rx_pkt);
+ kmem_cache_free(ipa_ctx->rx_pkt_wrapper_cache, rx_pkt);
}
}
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index 790898a..8ad0b5a 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -119,7 +119,6 @@
#define IPA_DFLT_HDR_NAME "ipa_excp_hdr"
#define IPA_INVALID_L4_PROTOCOL 0xFF
-
#define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
#define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
#define IPA_SETFIELD(val, shift, mask) (((val) << (shift)) & (mask))
@@ -364,9 +363,6 @@
bool desc_fifo_client_allocated;
bool data_fifo_client_allocated;
bool suspended;
- unsigned int pull_len;
- struct ipa_ip_packet_init *cmd;
- dma_addr_t dma_addr;
};
/**
@@ -382,7 +378,6 @@
struct ipa_sys_context {
struct list_head head_desc_list;
u32 len;
- u32 max_len;
spinlock_t spinlock;
struct sps_register_event event;
struct ipa_ep_context *ep;
@@ -641,6 +636,8 @@
struct kmem_cache *hdr_cache;
struct kmem_cache *hdr_offset_cache;
struct kmem_cache *rt_tbl_cache;
+ struct kmem_cache *tx_pkt_wrapper_cache;
+ struct kmem_cache *rx_pkt_wrapper_cache;
struct kmem_cache *tree_node_cache;
unsigned long rt_idx_bitmap[IPA_IP_MAX];
struct mutex lock;
@@ -687,7 +684,6 @@
/* featurize if memory footprint becomes a concern */
struct ipa_stats stats;
void *smem_pipe_mem;
- struct sk_buff_head rx_list;
};
/**
@@ -776,6 +772,8 @@
u32 *consumer_handle);
int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc,
bool in_atomic);
+int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc,
+ bool in_atomic);
int ipa_get_ep_mapping(enum ipa_operating_mode mode,
enum ipa_client_type client);
int ipa_get_client_mapping(enum ipa_operating_mode mode, int pipe_idx);
diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c
index 912d93c..23de300 100644
--- a/drivers/platform/msm/ipa/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_utils.c
@@ -32,24 +32,6 @@
{ 19, -1, -1, -1, -1, 11, 15, 8, 6, 2, 1, 5, 14, 16, 17, 18, -1, 10, 9, 7, 3, 4 },
};
-static unsigned int ipa_calc_pull_len(u32 hdr_len)
-{
- unsigned int pull_len, padding;
-
- pull_len = sizeof(struct ipa_a5_mux_hdr);
-
- /*
- * IP packet starts on word boundary
- * remove the MUX header and any padding and pass the frame to
- * the client which registered a rx callback on the "src pipe"
- */
- padding = hdr_len & 0x3;
- if (padding)
- pull_len += 4 - padding;
-
- return pull_len;
-}
-
/**
* ipa_cfg_route() - configure IPA route
* @route: IPA route
@@ -769,9 +751,6 @@
ipa_write_reg(ipa_ctx->mmio,
IPA_ENDP_INIT_HDR_n_OFST_v2(clnt_hdl), val);
- if (IPA_CLIENT_IS_PROD(ep->client))
- ep->pull_len = ipa_calc_pull_len(ipa_ep_cfg->hdr_len);
-
return 0;
}
EXPORT_SYMBOL(ipa_cfg_ep_hdr);
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index ac0b1d9..d378838 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -38,9 +38,11 @@
#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
#define QPNP_PON_KPDPWR_S2_TIMER(base) (base + 0x41)
#define QPNP_PON_KPDPWR_S2_CNTL(base) (base + 0x42)
+#define QPNP_PON_KPDPWR_S2_CNTL2(base) (base + 0x43)
#define QPNP_PON_RESIN_S1_TIMER(base) (base + 0x44)
#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
+#define QPNP_PON_RESIN_S2_CNTL2(base) (base + 0x47)
#define QPNP_PON_PS_HOLD_RST_CTL(base) (base + 0x5A)
#define QPNP_PON_PS_HOLD_RST_CTL2(base) (base + 0x5B)
#define QPNP_PON_TRIGGER_EN(base) (base + 0x80)
@@ -75,6 +77,7 @@
#define PON_S1_COUNT_MAX 0xF
#define QPNP_KEY_STATUS_DELAY msecs_to_jiffies(250)
+#define QPNP_PON_REV_B 0x01
enum pon_type {
PON_KPDPWR,
@@ -92,6 +95,8 @@
u32 pull_up;
u32 state_irq;
u32 bark_irq;
+ u16 s2_cntl_addr;
+ u16 s2_cntl2_addr;
};
struct qpnp_pon {
@@ -379,8 +384,14 @@
struct qpnp_pon *pon =
container_of(work, struct qpnp_pon, bark_work.work);
+ cfg = qpnp_get_cfg(pon, PON_RESIN);
+ if (!cfg) {
+ dev_err(&pon->spmi->dev, "Invalid config pointer\n");
+ goto err_return;
+ }
+
/* enable reset */
- rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
+ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
if (rc) {
dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
@@ -397,19 +408,13 @@
}
if (!(pon_rt_sts & QPNP_PON_RESIN_BARK_N_SET)) {
- cfg = qpnp_get_cfg(pon, PON_RESIN);
- if (!cfg) {
- dev_err(&pon->spmi->dev, "Invalid config pointer\n");
- goto err_return;
- }
/* report the key event and enable the bark IRQ */
input_report_key(pon->pon_input, cfg->key_code, 0);
input_sync(pon->pon_input);
enable_irq(cfg->bark_irq);
} else {
/* disable reset */
- rc = qpnp_pon_masked_write(pon,
- QPNP_PON_RESIN_S2_CNTL(pon->base),
+ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
QPNP_PON_S2_CNTL_EN, 0);
if (rc) {
dev_err(&pon->spmi->dev,
@@ -433,20 +438,20 @@
/* disable the bark interrupt */
disable_irq_nosync(irq);
- /* disable reset */
- rc = qpnp_pon_masked_write(pon, QPNP_PON_RESIN_S2_CNTL(pon->base),
- QPNP_PON_S2_CNTL_EN, 0);
- if (rc) {
- dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
- goto err_exit;
- }
-
cfg = qpnp_get_cfg(pon, PON_RESIN);
if (!cfg) {
dev_err(&pon->spmi->dev, "Invalid config pointer\n");
goto err_exit;
}
+ /* disable reset */
+ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ goto err_exit;
+ }
+
/* report the key event */
input_report_key(pon->pon_input, cfg->key_code, 1);
input_sync(pon->pon_input);
@@ -489,24 +494,22 @@
{
int rc;
u8 i;
- u16 s1_timer_addr, s2_cntl_addr, s2_timer_addr;
+ u16 s1_timer_addr, s2_timer_addr;
switch (cfg->pon_type) {
case PON_KPDPWR:
s1_timer_addr = QPNP_PON_KPDPWR_S1_TIMER(pon->base);
s2_timer_addr = QPNP_PON_KPDPWR_S2_TIMER(pon->base);
- s2_cntl_addr = QPNP_PON_KPDPWR_S2_CNTL(pon->base);
break;
case PON_RESIN:
s1_timer_addr = QPNP_PON_RESIN_S1_TIMER(pon->base);
s2_timer_addr = QPNP_PON_RESIN_S2_TIMER(pon->base);
- s2_cntl_addr = QPNP_PON_RESIN_S2_CNTL(pon->base);
break;
default:
return -EINVAL;
}
/* disable S2 reset */
- rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
QPNP_PON_S2_CNTL_EN, 0);
if (rc) {
dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
@@ -540,7 +543,7 @@
return rc;
}
- rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr,
QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type);
if (rc) {
dev_err(&pon->spmi->dev, "Unable to configure S2 reset type\n");
@@ -548,7 +551,7 @@
}
/* enable S2 reset */
- rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr,
QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
if (rc) {
dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
@@ -660,6 +663,17 @@
int rc = 0, i = 0;
struct device_node *pp = NULL;
struct qpnp_pon_config *cfg;
+ u8 reg;
+
+ /* Check if it is rev B */
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ QPNP_PON_REVISION2(pon->base), ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read addr=%x, rc(%d)\n",
+ QPNP_PON_REVISION2(pon->base), rc);
+ return rc;
+ }
/* iterate through the list of pon configs */
while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {
@@ -699,6 +713,17 @@
return cfg->bark_irq;
}
}
+
+ if (reg == QPNP_PON_REV_B) {
+ cfg->s2_cntl_addr =
+ QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+ cfg->s2_cntl2_addr =
+ QPNP_PON_KPDPWR_S2_CNTL2(pon->base);
+ } else {
+ cfg->s2_cntl_addr = cfg->s2_cntl2_addr =
+ QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+ }
+
break;
case PON_RESIN:
cfg->state_irq = spmi_get_irq_byname(pon->spmi,
@@ -726,6 +751,17 @@
return cfg->bark_irq;
}
}
+
+ if (reg == QPNP_PON_REV_B) {
+ cfg->s2_cntl_addr =
+ QPNP_PON_RESIN_S2_CNTL(pon->base);
+ cfg->s2_cntl2_addr =
+ QPNP_PON_RESIN_S2_CNTL2(pon->base);
+ } else {
+ cfg->s2_cntl_addr = cfg->s2_cntl2_addr =
+ QPNP_PON_RESIN_S2_CNTL(pon->base);
+ }
+
break;
case PON_CBLPWR:
cfg->state_irq = spmi_get_irq_byname(pon->spmi,
diff --git a/drivers/platform/msm/qpnp-pwm.c b/drivers/platform/msm/qpnp-pwm.c
index be62408..4e94b90 100644
--- a/drivers/platform/msm/qpnp-pwm.c
+++ b/drivers/platform/msm/qpnp-pwm.c
@@ -858,7 +858,7 @@
struct qpnp_lpg_chip *chip = pwm->chip;
u8 value1, value2, mask1, mask2;
u8 *reg1, *reg2;
- u16 addr;
+ u16 addr, addr1;
int rc;
value1 = pwm->chip->qpnp_lpg_registers[QPNP_RAMP_CONTROL];
@@ -878,7 +878,7 @@
value2 = QPNP_DISABLE_LPG_MODE;
}
mask1 = QPNP_RAMP_START_MASK;
- addr = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+ addr1 = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
QPNP_RAMP_CONTROL);
break;
case QPNP_LPG_REVISION_1:
@@ -889,8 +889,8 @@
QPNP_DISABLE_LUT_V1(value1, pwm->pwm_config.channel_id);
value2 = QPNP_DISABLE_LPG_MODE;
}
- mask1 = BIT(pwm->pwm_config.channel_id);
- addr = lpg_config->lut_base_addr +
+ mask1 = value1;
+ addr1 = lpg_config->lut_base_addr +
SPMI_LPG_REV1_RAMP_CONTROL_OFFSET;
break;
default:
@@ -898,15 +898,16 @@
return -EINVAL;
}
- rc = qpnp_lpg_save_and_write(value1, mask1, reg1,
+ addr = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
+ QPNP_ENABLE_CONTROL);
+
+ rc = qpnp_lpg_save_and_write(value2, mask2, reg2,
addr, 1, chip);
if (rc)
return rc;
- addr = SPMI_LPG_REG_ADDR(lpg_config->base_addr,
- QPNP_ENABLE_CONTROL);
- return qpnp_lpg_save_and_write(value2, mask2, reg2,
- addr, 1, chip);
+ return qpnp_lpg_save_and_write(value1, mask1, reg1,
+ addr1, 1, chip);
}
#define QPNP_GPLED_LPG_CHANNEL_RANGE_START 8
diff --git a/drivers/platform/msm/qpnp-revid.c b/drivers/platform/msm/qpnp-revid.c
index f218a5a..897dc2a 100644
--- a/drivers/platform/msm/qpnp-revid.c
+++ b/drivers/platform/msm/qpnp-revid.c
@@ -52,17 +52,20 @@
}
#define PM8941_PERIPHERAL_SUBTYPE 0x01
+#define PM8226_PERIPHERAL_SUBTYPE 0x04
static size_t build_pmic_string(char *buf, size_t n, int sid,
u8 subtype, u8 rev1, u8 rev2, u8 rev3, u8 rev4)
{
size_t pos = 0;
/*
- * In early versions of PM8941, the major revision number started
- * incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
+ * In early versions of PM8941 and PM8226, the major revision number
+ * started incrementing from 0 (eg 0 = v1.0, 1 = v2.0).
* Increment the major revision number here if the chip is an early
- * version of PM8941.
+ * version of PM8941 or PM8226.
*/
- if ((int)subtype == PM8941_PERIPHERAL_SUBTYPE && rev4 < 0x02)
+ if (((int)subtype == PM8941_PERIPHERAL_SUBTYPE
+ || (int)subtype == PM8226_PERIPHERAL_SUBTYPE)
+ && rev4 < 0x02)
rev4++;
pos += snprintf(buf + pos, n - pos, "PMIC@SID%d", sid);
diff --git a/drivers/power/battery_current_limit.c b/drivers/power/battery_current_limit.c
index 69fa4a8..6b6b110 100644
--- a/drivers/power/battery_current_limit.c
+++ b/drivers/power/battery_current_limit.c
@@ -31,6 +31,7 @@
* Mininum BCL poll interval 10 msec
*/
#define MIN_BCL_POLL_INTERVAL 10
+#define BATTERY_VOLTAGE_MIN 3400
static const char bcl_type[] = "bcl";
@@ -43,20 +44,20 @@
};
/*
- * Battery Current Limit IBat Imax Threshold Mode
+ * Battery Current Limit Iavail Threshold Mode set
*/
-enum bcl_ibat_imax_threshold_mode {
- BCL_IBAT_IMAX_THRESHOLD_DISABLED = 0,
- BCL_IBAT_IMAX_THRESHOLD_ENABLED,
+enum bcl_iavail_threshold_mode {
+ BCL_IAVAIL_THRESHOLD_DISABLED = 0,
+ BCL_IAVAIL_THRESHOLD_ENABLED,
};
/*
- * Battery Current Limit Ibat Imax Trip Type (High and Low Threshold)
+ * Battery Current Limit Iavail Threshold Mode
*/
-enum bcl_ibat_imax_threshold_type {
- BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW = 0,
- BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH,
- BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX,
+enum bcl_iavail_threshold_type {
+ BCL_IAVAIL_LOW_THRESHOLD_TYPE = 0,
+ BCL_IAVAIL_HIGH_THRESHOLD_TYPE,
+ BCL_IAVAIL_THRESHOLD_TYPE_MAX,
};
/**
@@ -70,118 +71,137 @@
/* BCL related config parameter */
/* BCL mode enable or not */
enum bcl_device_mode bcl_mode;
- /* BCL Ibat/IMax Threshold Activate or Not */
- enum bcl_ibat_imax_threshold_mode
- bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX];
- /* BCL Ibat/IMax Threshold value in milli Amp */
- int bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_MAX];
+ /* BCL Iavail Threshold Activate or Not */
+ enum bcl_iavail_threshold_mode
+ bcl_threshold_mode[BCL_IAVAIL_THRESHOLD_TYPE_MAX];
+ /* BCL Iavail Threshold value in milli Amp */
+ int bcl_threshold_value_ma[BCL_IAVAIL_THRESHOLD_TYPE_MAX];
/* BCL Type */
char bcl_type[BCL_NAME_LENGTH];
- /* BCL poll in usec */
+ /* BCL poll in msec */
int bcl_poll_interval_msec;
/* BCL realtime value based on poll */
- /* BCL realtime ibat in milli Amp*/
- int bcl_ibat_ma;
- /* BCL realtime calculated imax in milli Amp*/
- int bcl_imax_ma;
- /* BCL realtime calculated ocv in uV*/
- int bcl_ocv_uv;
/* BCL realtime vbat in mV*/
int bcl_vbat_mv;
/* BCL realtime rbat in mOhms*/
- int bcl_rbat;
+ int bcl_rbat_mohm;
+ /*BCL realtime iavail in milli Amp*/
+ int bcl_iavail;
+ /*BCL vbatt min in mV*/
+ int bcl_vbat_min;
/* BCL period poll delay work structure */
- struct delayed_work bcl_imax_work;
+ struct delayed_work bcl_iavail_work;
};
static struct bcl_context *gbcl;
-/*
- * BCL imax calculation and trigger notification to user space
- * if imax cross threshold
- */
-static void bcl_calculate_imax_trigger(void)
+static int bcl_get_battery_voltage(int *vbatt_mv)
{
- int ibatt_ua, vbatt_uv;
- int imax_ma;
- int ibatt_ma, vbatt_mv;
- int imax_low_threshold;
- int imax_high_threshold;
- bool threshold_cross = false;
- union power_supply_propval ret = {0,};
static struct power_supply *psy;
+ union power_supply_propval ret = {0,};
+
+ if (psy == NULL) {
+ psy = power_supply_get_by_name("battery");
+ if (psy == NULL) {
+ pr_err("failed to get ps battery\n");
+ return -EINVAL;
+ }
+ }
+
+ if (psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret))
+ return -EINVAL;
+
+ if (ret.intval <= 0)
+ return -EINVAL;
+
+ *vbatt_mv = ret.intval / 1000;
+ return 0;
+}
+
+
+static int bcl_get_resistance(int *rbatt_mohm)
+{
+ static struct power_supply *psy;
+ union power_supply_propval ret = {0,};
+
+ if (psy == NULL) {
+ psy = power_supply_get_by_name("bms");
+ if (psy == NULL) {
+ pr_err("failed to get ps bms\n");
+ return -EINVAL;
+ }
+ }
+ if (psy->get_property(psy, POWER_SUPPLY_PROP_RESISTANCE, &ret))
+ return -EINVAL;
+
+ if (ret.intval <= 0)
+ return -EINVAL;
+
+ *rbatt_mohm = ret.intval / 1000;
+
+ return 0;
+}
+
+/*
+ * BCL iavail calculation and trigger notification to user space
+ * if iavail cross threshold
+ */
+static void bcl_calculate_iavail_trigger(void)
+{
+ int iavail_ma = 0;
+ int vbatt_mv;
+ int rbatt_mohm;
+ bool threshold_cross = false;
if (!gbcl) {
pr_err("called before initialization\n");
return;
}
- if (psy == NULL) {
- psy = power_supply_get_by_name("battery");
- if (psy == NULL) {
- pr_err("failed to get ps battery\n");
- return;
- }
- }
-
- if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_NOW, &ret))
+ if (bcl_get_battery_voltage(&vbatt_mv))
return;
- ibatt_ua = ret.intval;
- if (psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret))
+ if (bcl_get_resistance(&rbatt_mohm))
return;
- vbatt_uv = ret.intval;
- if (psy->get_property(psy, POWER_SUPPLY_PROP_CURRENT_MAX, &ret))
- return;
- imax_ma = ret.intval/1000;
+ iavail_ma = (vbatt_mv - gbcl->bcl_vbat_min) * 1000 / rbatt_mohm;
- ibatt_ma = ibatt_ua/1000;
- vbatt_mv = vbatt_uv/1000;
-
- gbcl->bcl_ibat_ma = ibatt_ma;
- gbcl->bcl_imax_ma = imax_ma;
+ gbcl->bcl_rbat_mohm = rbatt_mohm;
gbcl->bcl_vbat_mv = vbatt_mv;
+ gbcl->bcl_iavail = iavail_ma;
- pr_debug("ibatt %d, imax %d, vbatt %d\n", ibatt_ma, imax_ma, vbatt_mv);
- if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
- == BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
- imax_high_threshold =
- imax_ma - gbcl->bcl_threshold_value_ma
- [BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH];
- if (ibatt_ma >= imax_high_threshold)
- threshold_cross = true;
- }
+ pr_debug("iavail %d, vbatt %d rbatt %d\n", iavail_ma, vbatt_mv,
+ rbatt_mohm);
- if (gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
- == BCL_IBAT_IMAX_THRESHOLD_ENABLED) {
- imax_low_threshold =
- imax_ma - gbcl->bcl_threshold_value_ma
- [BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW];
- if (ibatt_ma <= imax_low_threshold)
- threshold_cross = true;
- }
+ if ((gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] ==
+ BCL_IAVAIL_THRESHOLD_ENABLED)
+ && (iavail_ma >=
+ gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]))
+ threshold_cross = true;
+ else if ((gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
+ == BCL_IAVAIL_THRESHOLD_ENABLED)
+ && (iavail_ma <=
+ gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE]))
+ threshold_cross = true;
- if (threshold_cross) {
- sysfs_notify(&gbcl->dev->kobj,
- NULL, "type");
- }
+ if (threshold_cross)
+ sysfs_notify(&gbcl->dev->kobj, NULL, "type");
}
/*
- * BCL imax work
+ * BCL iavail work
*/
-static void bcl_imax_work(struct work_struct *work)
+static void bcl_iavail_work(struct work_struct *work)
{
struct bcl_context *bcl = container_of(work,
- struct bcl_context, bcl_imax_work.work);
+ struct bcl_context, bcl_iavail_work.work);
if (gbcl->bcl_mode == BCL_DEVICE_ENABLED) {
- bcl_calculate_imax_trigger();
+ bcl_calculate_iavail_trigger();
/* restart the delay work for caculating imax */
- schedule_delayed_work(&bcl->bcl_imax_work,
+ schedule_delayed_work(&bcl->bcl_iavail_work,
msecs_to_jiffies(bcl->bcl_poll_interval_msec));
}
}
@@ -200,12 +220,12 @@
if (gbcl->bcl_mode == BCL_DEVICE_DISABLED
&& mode == BCL_DEVICE_ENABLED) {
gbcl->bcl_mode = mode;
- bcl_imax_work(&(gbcl->bcl_imax_work.work));
+ bcl_iavail_work(&(gbcl->bcl_iavail_work.work));
return;
} else if (gbcl->bcl_mode == BCL_DEVICE_ENABLED
&& mode == BCL_DEVICE_DISABLED) {
gbcl->bcl_mode = mode;
- cancel_delayed_work_sync(&(gbcl->bcl_imax_work));
+ cancel_delayed_work_sync(&(gbcl->bcl_iavail_work));
return;
}
@@ -223,11 +243,10 @@
}
show_bcl(type, bcl_type, "%s\n")
-show_bcl(ibat, bcl_ibat_ma, "%d\n")
-show_bcl(imax, bcl_imax_ma, "%d\n")
show_bcl(vbat, bcl_vbat_mv, "%d\n")
-show_bcl(rbat, bcl_rbat, "%d\n")
-show_bcl(ocv, bcl_ocv_uv, "%d\n")
+show_bcl(rbat, bcl_rbat_mohm, "%d\n")
+show_bcl(iavail, bcl_iavail, "%d\n")
+show_bcl(vbat_min, bcl_vbat_min, "%d\n");
show_bcl(poll_interval, bcl_poll_interval_msec, "%d\n")
static ssize_t
@@ -259,136 +278,6 @@
}
static ssize_t
-ibat_imax_low_threshold_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- if (!gbcl)
- return -EPERM;
-
- return snprintf(buf, PAGE_SIZE, "%s\n",
- gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
- == BCL_IBAT_IMAX_THRESHOLD_ENABLED ? "enabled" : "disabled");
-}
-
-static ssize_t
-ibat_imax_low_threshold_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- if (!gbcl)
- return -EPERM;
-
- if (!strncmp(buf, "enabled", 7))
- gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
- = BCL_IBAT_IMAX_THRESHOLD_ENABLED;
- else if (!strncmp(buf, "disabled", 8))
- gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
- = BCL_IBAT_IMAX_THRESHOLD_DISABLED;
- else
- return -EINVAL;
-
- return count;
-}
-
-static ssize_t
-ibat_imax_low_threshold_value_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- if (!gbcl)
- return -EPERM;
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]);
-}
-
-static ssize_t
-ibat_imax_low_threshold_value_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int value;
-
- if (!gbcl)
- return -EPERM;
-
- if (!sscanf(buf, "%d", &value))
- return -EINVAL;
-
- if (value < 0)
- return -EINVAL;
-
- gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
- = value;
-
- return count;
-}
-
-static ssize_t
-ibat_imax_high_threshold_mode_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- if (!gbcl)
- return -EPERM;
-
- return snprintf(buf, PAGE_SIZE, "%s\n",
- gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
- == BCL_IBAT_IMAX_THRESHOLD_ENABLED ? "enabled" : "disabled");
-}
-
-static ssize_t
-ibat_imax_high_threshold_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- if (!gbcl)
- return -EPERM;
-
- if (!strncmp(buf, "enabled", 7))
- gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
- = BCL_IBAT_IMAX_THRESHOLD_ENABLED;
- else if (!strncmp(buf, "disabled", 8))
- gbcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
- = BCL_IBAT_IMAX_THRESHOLD_DISABLED;
- else
- return -EINVAL;
-
- return count;
-}
-
-static ssize_t
-ibat_imax_high_threshold_value_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- if (!gbcl)
- return -EPERM;
-
- return snprintf(buf, PAGE_SIZE, "%d\n",
- gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]);
-}
-
-static ssize_t
-ibat_imax_high_threshold_value_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int value;
-
- if (!gbcl)
- return -EPERM;
-
- if (!sscanf(buf, "%d", &value))
- return -EINVAL;
-
- if (value < 0)
- return -EINVAL;
-
- gbcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
- = value;
-
- return count;
-}
-
-static ssize_t
poll_interval_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -409,31 +298,168 @@
return count;
}
+static ssize_t vbat_min_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ int ret;
+
+ if (!gbcl)
+ return -EPERM;
+
+ ret = kstrtoint(buf, 10, &value);
+
+ if (ret || (value < 0)) {
+ pr_err("Incorrect vbatt min value\n");
+ return -EINVAL;
+ }
+
+ gbcl->bcl_vbat_min = value;
+ return count;
+}
+
+static ssize_t iavail_low_threshold_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (!gbcl)
+ return -EPERM;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
+ == BCL_IAVAIL_THRESHOLD_ENABLED ? "enabled" : "disabled");
+}
+
+static ssize_t iavail_low_threshold_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ if (!gbcl)
+ return -EPERM;
+
+ if (!strncmp(buf, "enabled", 7))
+ gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
+ = BCL_IAVAIL_THRESHOLD_ENABLED;
+ else if (!strncmp(buf, "disabled", 7))
+ gbcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE]
+ = BCL_IAVAIL_THRESHOLD_DISABLED;
+ else
+ return -EINVAL;
+
+ return count;
+}
+static ssize_t iavail_high_threshold_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (!gbcl)
+ return -EPERM;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
+ == BCL_IAVAIL_THRESHOLD_ENABLED ? "enabled" : "disabled");
+}
+
+static ssize_t iavail_high_threshold_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ if (!gbcl)
+ return -EPERM;
+
+ if (!strncmp(buf, "enabled", 7))
+ gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
+ = BCL_IAVAIL_THRESHOLD_ENABLED;
+ else if (!strncmp(buf, "disabled", 7))
+ gbcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]
+ = BCL_IAVAIL_THRESHOLD_DISABLED;
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+static ssize_t iavail_low_threshold_value_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (!gbcl)
+ return -EPERM;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE]);
+}
+
+
+static ssize_t iavail_low_threshold_value_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int val;
+ int ret;
+
+ ret = kstrtoint(buf, 10, &val);
+
+ if (ret || (val < 0)) {
+ pr_err("Incorrect available current threshold value\n");
+ return -EINVAL;
+ }
+
+ gbcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE] = val;
+
+ return count;
+}
+static ssize_t iavail_high_threshold_value_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ if (!gbcl)
+ return -EPERM;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE]);
+}
+
+static ssize_t iavail_high_threshold_value_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int val;
+ int ret;
+
+ ret = kstrtoint(buf, 10, &val);
+
+ if (ret || (val < 0)) {
+ pr_err("Incorrect available current threshold value\n");
+ return -EINVAL;
+ }
+
+ gbcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] = val;
+
+ return count;
+}
+
/*
* BCL device attributes
*/
static struct device_attribute bcl_dev_attr[] = {
__ATTR(type, 0444, type_show, NULL),
- __ATTR(ibat, 0444, ibat_show, NULL),
+ __ATTR(iavail, 0444, iavail_show, NULL),
+ __ATTR(vbat_min, 0644, vbat_min_show, vbat_min_store),
__ATTR(vbat, 0444, vbat_show, NULL),
__ATTR(rbat, 0444, rbat_show, NULL),
- __ATTR(ocv, 0444, ocv_show, NULL),
- __ATTR(imax, 0444, imax_show, NULL),
__ATTR(mode, 0644, mode_show, mode_store),
__ATTR(poll_interval, 0644,
poll_interval_show, poll_interval_store),
- __ATTR(ibat_imax_low_threshold_mode, 0644,
- ibat_imax_low_threshold_mode_show,
- ibat_imax_low_threshold_mode_store),
- __ATTR(ibat_imax_high_threshold_mode, 0644,
- ibat_imax_high_threshold_mode_show,
- ibat_imax_high_threshold_mode_store),
- __ATTR(ibat_imax_low_threshold_value, 0644,
- ibat_imax_low_threshold_value_show,
- ibat_imax_low_threshold_value_store),
- __ATTR(ibat_imax_high_threshold_value, 0644,
- ibat_imax_high_threshold_value_show,
- ibat_imax_high_threshold_value_store)
+ __ATTR(iavail_low_threshold_mode, 0644,
+ iavail_low_threshold_mode_show,
+ iavail_low_threshold_mode_store),
+ __ATTR(iavail_high_threshold_mode, 0644,
+ iavail_high_threshold_mode_show,
+ iavail_high_threshold_mode_store),
+ __ATTR(iavail_low_threshold_value, 0644,
+ iavail_low_threshold_value_show,
+ iavail_low_threshold_value_store),
+ __ATTR(iavail_high_threshold_value, 0644,
+ iavail_high_threshold_value_show,
+ iavail_high_threshold_value_store),
};
static int create_bcl_sysfs(struct bcl_context *bcl)
@@ -480,12 +506,13 @@
/* Init default BCL params */
bcl->dev = &pdev->dev;
bcl->bcl_mode = BCL_DEVICE_DISABLED;
- bcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW]
- = BCL_IBAT_IMAX_THRESHOLD_DISABLED;
- bcl->bcl_threshold_mode[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH]
- = BCL_IBAT_IMAX_THRESHOLD_DISABLED;
- bcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_LOW] = 0;
- bcl->bcl_threshold_value_ma[BCL_IBAT_IMAX_THRESHOLD_TYPE_HIGH] = 0;
+ bcl->bcl_threshold_mode[BCL_IAVAIL_LOW_THRESHOLD_TYPE] =
+ BCL_IAVAIL_THRESHOLD_DISABLED;
+ bcl->bcl_threshold_mode[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] =
+ BCL_IAVAIL_THRESHOLD_DISABLED;
+ bcl->bcl_threshold_value_ma[BCL_IAVAIL_LOW_THRESHOLD_TYPE] = 0;
+ bcl->bcl_threshold_value_ma[BCL_IAVAIL_HIGH_THRESHOLD_TYPE] = 0;
+ bcl->bcl_vbat_min = BATTERY_VOLTAGE_MIN;
snprintf(bcl->bcl_type, BCL_NAME_LENGTH, "%s", bcl_type);
bcl->bcl_poll_interval_msec = BCL_POLL_INTERVAL;
ret = create_bcl_sysfs(bcl);
@@ -495,7 +522,7 @@
return ret;
}
platform_set_drvdata(pdev, bcl);
- INIT_DELAYED_WORK(&bcl->bcl_imax_work, bcl_imax_work);
+ INIT_DELAYED_WORK_DEFERRABLE(&bcl->bcl_iavail_work, bcl_iavail_work);
return 0;
}
diff --git a/drivers/power/qpnp-bms.c b/drivers/power/qpnp-bms.c
index 28dd539..d9a216d 100644
--- a/drivers/power/qpnp-bms.c
+++ b/drivers/power/qpnp-bms.c
@@ -74,8 +74,13 @@
/* Extra bms registers */
#define SOC_STORAGE_REG 0xB0
#define IAVG_STORAGE_REG 0xB1
-#define BMS1_BMS_DATA_REG_2 0xB2
+#define BMS_BATT_REMOVED_REG 0xB2
#define BMS1_BMS_DATA_REG_3 0xB3
+#define CHARGE_INCREASE_STORAGE 0xB4
+#define FCC_BATT_TEMP_STORAGE 0xB5
+#define FCC_STORAGE_LSB 0xBC /* LSB=0xBC, MSB=0xBD */
+#define CHARGE_CYCLE_STORAGE_LSB 0xBE /* LSB=0xBE, MSB=0xBF */
+
/* IADC Channel Select */
#define IADC1_BMS_ADC_CH_SEL_CTL 0x48
@@ -88,6 +93,10 @@
#define IAVG_SAMPLES 16
+/* FCC learning constants */
+#define DELTA_FCC_PERCENT 5
+#define VALID_FCC_CHGCYL_RANGE 50
+
#define QPNP_BMS_DEV_NAME "qcom,qpnp-bms"
struct soc_params {
@@ -106,6 +115,12 @@
int last_good_ocv_uv;
};
+struct fcc_data {
+ int fcc_new;
+ int batt_temp;
+ int chargecycles;
+};
+
struct qpnp_bms_chip {
struct device *dev;
struct power_supply bms_psy;
@@ -215,6 +230,23 @@
int ocv_high_threshold_uv;
int ocv_low_threshold_uv;
unsigned long last_recalc_time;
+
+ struct fcc_data *fcc_table;
+ int enable_fcc_learning;
+ int min_fcc_learning_soc;
+ int min_fcc_ocv_pc;
+ int min_fcc_learning_samples;
+ int start_soc;
+ int end_soc;
+ int start_pc;
+ int start_cc_uah;
+ int start_real_soc;
+ int end_cc_uah;
+ uint16_t fcc_new_mah;
+ int fcc_new_batt_temp;
+ uint16_t charge_cycles;
+ u8 charge_increase;
+ int fcc_new_sysfs;
};
static struct of_device_id qpnp_bms_match_table[] = {
@@ -232,9 +264,26 @@
POWER_SUPPLY_PROP_RESISTANCE,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
};
static bool bms_reset;
+static int min_fcc_cycles = -EINVAL;
+static int last_fcc_update_count;
+static int battery_removed;
+
+static int
+bms_ro_ops_set(const char *val, const struct kernel_param *kp)
+{
+ return -EINVAL;
+}
+static struct kernel_param_ops bms_ro_param_ops = {
+ .set = bms_ro_ops_set,
+ .get = param_get_int,
+};
+module_param_cb(min_fcc_cycles, &bms_ro_param_ops, &min_fcc_cycles, 0644);
+module_param_cb(battery_removed, &bms_ro_param_ops, &battery_removed, 0644);
+module_param(last_fcc_update_count, int, 0644);
static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val,
u16 base, int count)
@@ -2262,14 +2311,275 @@
return 0;
}
+static void readjust_fcc_table(struct qpnp_bms_chip *chip)
+{
+ struct single_row_lut *temp, *old;
+ int i, fcc, ratio;
+
+ if (!chip->enable_fcc_learning)
+ return;
+
+ if (!chip->fcc_temp_lut) {
+ pr_err("The static fcc lut table is NULL\n");
+ return;
+ }
+
+ temp = kzalloc(sizeof(struct single_row_lut), GFP_KERNEL);
+ if (!temp) {
+ pr_err("Cannot allocate memory for adjusted fcc table\n");
+ return;
+ }
+
+ fcc = interpolate_fcc(chip->fcc_temp_lut, chip->fcc_new_batt_temp);
+
+ temp->cols = chip->fcc_temp_lut->cols;
+ for (i = 0; i < chip->fcc_temp_lut->cols; i++) {
+ temp->x[i] = chip->fcc_temp_lut->x[i];
+ ratio = div_u64(chip->fcc_temp_lut->y[i] * 1000, fcc);
+ temp->y[i] = (ratio * chip->fcc_new_mah);
+ temp->y[i] /= 1000;
+ }
+
+ old = chip->adjusted_fcc_temp_lut;
+ chip->adjusted_fcc_temp_lut = temp;
+ kfree(old);
+}
+
+
+static void backup_fcc_new(struct qpnp_bms_chip *chip)
+{
+ int rc = 0;
+ u8 temp = 0;
+
+ if (chip->fcc_new_mah > 0) {
+ rc = qpnp_write_wrapper(chip, (u8 *)&chip->fcc_new_mah,
+ chip->base + FCC_STORAGE_LSB, 2);
+ if (rc)
+ pr_err("Unable to backup new_fcc\n");
+
+ temp = chip->fcc_new_batt_temp / 10;
+ rc = qpnp_write_wrapper(chip, &temp,
+ chip->base + FCC_BATT_TEMP_STORAGE, 1);
+ if (rc)
+ pr_err("Unable to backup fcc temp.\n");
+ }
+}
+
+
+static void backup_charge_cycle(struct qpnp_bms_chip *chip)
+{
+ int rc = 0;
+
+ if (chip->charge_increase >= 0) {
+ rc = qpnp_write_wrapper(chip, &chip->charge_increase,
+ chip->base + CHARGE_INCREASE_STORAGE, 1);
+ if (rc)
+ pr_err("Unable to backup charge_increase\n");
+ }
+
+ if (chip->charge_cycles >= 0) {
+ rc = qpnp_write_wrapper(chip, (u8 *)&chip->charge_cycles,
+ chip->base + CHARGE_CYCLE_STORAGE_LSB, 2);
+ if (rc)
+ pr_err("Unable to backup charge_cycles\n");
+ }
+}
+
+static void restore_fcc_data(struct qpnp_bms_chip *chip)
+{
+ int rc = 0;
+ uint16_t temp_u16 = 0;
+ u8 temp_u8 = 0;
+
+ rc = qpnp_read_wrapper(chip, &temp_u8,
+ chip->base + CHARGE_INCREASE_STORAGE, 1);
+ if (!rc && temp_u8 != 0xFF)
+ chip->charge_increase = temp_u8;
+
+ rc = qpnp_read_wrapper(chip, (u8 *)&temp_u16,
+ chip->base + CHARGE_CYCLE_STORAGE_LSB, 2);
+ if (!rc && temp_u16 != 0xFFFF)
+ chip->charge_cycles = temp_u16;
+
+ rc = qpnp_read_wrapper(chip, (u8 *)&temp_u16,
+ chip->base + FCC_STORAGE_LSB, 2);
+ if (!rc && temp_u16 != 0xFFFF) {
+ chip->fcc_new_mah = temp_u16;
+ } else {
+ pr_debug("Backed-up FCC not initialized, FCC not updated\n");
+ return;
+ }
+
+ rc = qpnp_read_wrapper(chip, &temp_u8,
+ chip->base + FCC_BATT_TEMP_STORAGE, 1);
+ if (!rc && temp_u8 != 0xFF) {
+ chip->fcc_new_batt_temp = (s8)temp_u8 * 10;
+ } else {
+ pr_debug("Backed-up temp. not initialized, FCC not updated\n");
+ return;
+ }
+ /* readjust the FCC table if fcc and temp are valid */
+ readjust_fcc_table(chip);
+}
+
+static int calculate_real_soc(struct qpnp_bms_chip *chip,
+ int batt_temp, struct raw_soc_params *raw, int cc_uah)
+{
+ int fcc_uah, rc_uah;
+
+ fcc_uah = calculate_fcc(chip, batt_temp);
+ rc_uah = calculate_ocv_charge(chip, raw, fcc_uah);
+
+ return ((rc_uah - cc_uah) * 100) / fcc_uah;
+}
+
+static void update_fcc_table_for_temp(struct qpnp_bms_chip *chip,
+ int batt_temp_final)
+{
+ int i, fcc_t1, fcc_t2, fcc_final;
+ struct fcc_data *ft;
+
+ /* Interpolate all the FCC entries to the same temperature */
+ for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+ ft = &chip->fcc_table[i];
+ if (ft->batt_temp == batt_temp_final)
+ continue;
+ fcc_t1 = interpolate_fcc(chip->fcc_temp_lut, ft->batt_temp);
+ fcc_t2 = interpolate_fcc(chip->fcc_temp_lut, batt_temp_final);
+ fcc_final = (ft->fcc_new / fcc_t1) * fcc_t2;
+ ft->fcc_new = fcc_final;
+ ft->batt_temp = batt_temp_final;
+ }
+}
+
+static void update_fcc_learning_table(struct qpnp_bms_chip *chip,
+ int fcc_uah, int new_fcc_uah, int chargecycles, int batt_temp)
+{
+ int i, count, new_fcc_avg = 0, temp_fcc_avg = 0, temp_fcc_delta = 0;
+ struct fcc_data *ft;
+
+ count = last_fcc_update_count % chip->min_fcc_learning_samples;
+ ft = &chip->fcc_table[count];
+ ft->fcc_new = chip->fcc_new_sysfs = new_fcc_uah;
+ ft->batt_temp = batt_temp;
+ ft->chargecycles = chargecycles;
+ last_fcc_update_count++;
+ /* update userspace */
+ sysfs_notify(&chip->dev->kobj, NULL, "fcc_data");
+
+ pr_debug("Updated fcc table. new_fcc=%d, chargecycle=%d, temp=%d fcc_update_count=%d\n",
+ new_fcc_uah, chargecycles, batt_temp, last_fcc_update_count);
+
+ if (last_fcc_update_count < chip->min_fcc_learning_samples) {
+ pr_debug("Not enough FCC samples. Current count = %d\n",
+ last_fcc_update_count);
+ return; /* Not enough samples to update fcc */
+ }
+
+ /* reject entries if they are > 50 chargecycles apart */
+ for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+ if ((chip->fcc_table[i].chargecycles + VALID_FCC_CHGCYL_RANGE)
+ < chargecycles) {
+ pr_debug("Charge cycle too old (> %d cycles apart)\n",
+ VALID_FCC_CHGCYL_RANGE);
+ return; /* Samples old, > 50 cycles apart*/
+ }
+ }
+ /* update the fcc table for temperature difference*/
+ update_fcc_table_for_temp(chip, batt_temp);
+
+ for (i = 0; i < chip->min_fcc_learning_samples; i++)
+ temp_fcc_avg += chip->fcc_table[i].fcc_new;
+
+ temp_fcc_avg /= chip->min_fcc_learning_samples;
+ temp_fcc_delta = div_u64(temp_fcc_avg * DELTA_FCC_PERCENT, 100);
+
+ /* fix the fcc if its an outlier i.e. > 5% of the average */
+ for (i = 0; i < chip->min_fcc_learning_samples; i++) {
+ ft = &chip->fcc_table[i];
+ if (abs(ft->fcc_new - temp_fcc_avg) > temp_fcc_delta)
+ ft->fcc_new = temp_fcc_avg;
+ new_fcc_avg += ft->fcc_new;
+ }
+ new_fcc_avg /= chip->min_fcc_learning_samples;
+
+ chip->fcc_new_mah = new_fcc_avg / 1000;
+ chip->fcc_new_batt_temp = batt_temp;
+ pr_info("FCC update: New fcc_mah=%d, fcc_batt_temp=%d\n",
+ new_fcc_avg, batt_temp);
+ readjust_fcc_table(chip);
+ backup_fcc_new(chip);
+}
+
+static bool is_new_fcc_valid(int new_fcc_uah, int fcc_uah)
+{
+ if ((new_fcc_uah >= (fcc_uah / 2)) &&
+ ((new_fcc_uah * 100) <= (fcc_uah * 105)))
+ return true;
+
+ pr_debug("FCC rejected - not within valid limit\n");
+ return false;
+}
+
+static void fcc_learning_config(struct qpnp_bms_chip *chip, bool start)
+{
+ int rc, batt_temp;
+ struct raw_soc_params raw;
+ struct qpnp_vadc_result result;
+ int fcc_uah, new_fcc_uah, delta_cc_uah, delta_soc;
+
+ rc = qpnp_vadc_read(LR_MUX1_BATT_THERM, &result);
+ if (rc) {
+ pr_err("Unable to read batt_temp\n");
+ return;
+ } else {
+ batt_temp = (int)result.physical;
+ }
+
+ rc = read_soc_params_raw(chip, &raw, batt_temp);
+ if (rc) {
+ pr_err("Unable to read CC, cannot update FCC\n");
+ return;
+ }
+
+ if (start) {
+ chip->start_pc = interpolate_pc(chip->pc_temp_ocv_lut,
+ batt_temp / 10, raw.last_good_ocv_uv / 1000);
+ chip->start_cc_uah = calculate_cc(chip, raw.cc, false);
+ chip->start_real_soc = calculate_real_soc(chip,
+ batt_temp, &raw, chip->start_cc_uah);
+ pr_debug("start_pc=%d, start_cc=%d, start_soc=%d real_soc=%d\n",
+ chip->start_pc, chip->start_cc_uah,
+ chip->start_soc, chip->start_real_soc);
+ } else {
+ chip->end_cc_uah = calculate_cc(chip, raw.cc, false);
+ delta_soc = 100 - chip->start_real_soc;
+ delta_cc_uah = abs(chip->end_cc_uah - chip->start_cc_uah);
+ new_fcc_uah = div_u64(delta_cc_uah * 100, delta_soc);
+ fcc_uah = calculate_fcc(chip, batt_temp);
+ pr_debug("start_soc=%d, start_pc=%d, start_real_soc=%d, start_cc=%d, end_cc=%d, new_fcc=%d\n",
+ chip->start_soc, chip->start_pc, chip->start_real_soc,
+ chip->start_cc_uah, chip->end_cc_uah, new_fcc_uah);
+
+ if (is_new_fcc_valid(new_fcc_uah, fcc_uah))
+ update_fcc_learning_table(chip, fcc_uah,
+ new_fcc_uah, chip->charge_cycles, batt_temp);
+ }
+}
+
static void charging_began(struct qpnp_bms_chip *chip)
{
+
mutex_lock(&chip->last_soc_mutex);
chip->charge_start_tm_sec = 0;
chip->catch_up_time_sec = 0;
mutex_unlock(&chip->last_soc_mutex);
+ chip->start_soc = report_state_of_charge(chip);
+
mutex_lock(&chip->last_ocv_uv_mutex);
+ if (chip->enable_fcc_learning)
+ fcc_learning_config(chip, true);
chip->soc_at_cv = -EINVAL;
chip->prev_chg_soc = -EINVAL;
mutex_unlock(&chip->last_ocv_uv_mutex);
@@ -2282,10 +2592,28 @@
chip->catch_up_time_sec = 0;
mutex_unlock(&chip->last_soc_mutex);
+ chip->end_soc = report_state_of_charge(chip);
+
mutex_lock(&chip->last_ocv_uv_mutex);
chip->soc_at_cv = -EINVAL;
chip->prev_chg_soc = -EINVAL;
+
+ /* update the chargecycles */
+ if (chip->end_soc > chip->start_soc) {
+ chip->charge_increase += (chip->end_soc - chip->start_soc);
+ if (chip->charge_increase > 100) {
+ chip->charge_cycles++;
+ chip->charge_increase = chip->charge_increase % 100;
+ }
+ if (chip->enable_fcc_learning)
+ backup_charge_cycle(chip);
+ }
+
if (get_battery_status(chip) == POWER_SUPPLY_STATUS_FULL) {
+ if (chip->enable_fcc_learning &&
+ (chip->start_soc <= chip->min_fcc_learning_soc) &&
+ (chip->start_pc <= chip->min_fcc_ocv_pc))
+ fcc_learning_config(chip, false);
chip->done_charging = true;
chip->last_soc_invalid = true;
} else if (chip->charging_adjusted_ocv > 0) {
@@ -2293,6 +2621,7 @@
chip->charging_adjusted_ocv);
chip->last_ocv_uv = chip->charging_adjusted_ocv;
}
+
chip->charging_adjusted_ocv = -EINVAL;
mutex_unlock(&chip->last_ocv_uv_mutex);
@@ -2417,12 +2746,120 @@
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
val->intval = get_prop_bms_charge_full_design(chip);
break;
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ val->intval = chip->charge_cycles;
+ break;
default:
return -EINVAL;
}
return 0;
}
+static ssize_t fcc_data_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+ static int i;
+ int fcc_new = 0, rc;
+
+ i %= chip->min_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &fcc_new);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].fcc_new = fcc_new;
+ pr_debug("Rcvd: [%d] fcc_new=%d\n", i, fcc_new);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_data_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int count = 0;
+ struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+ count = snprintf(buf, PAGE_SIZE, "%d", chip->fcc_new_sysfs);
+ pr_debug("Sent: fcc_new=%d\n", chip->fcc_new_sysfs);
+
+ return count;
+}
+
+static ssize_t fcc_temp_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ static int i;
+ int batt_temp = 0, rc;
+ struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+ i %= chip->min_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &batt_temp);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].batt_temp = batt_temp;
+ pr_debug("Rcvd: [%d] batt_temp=%d\n", i, batt_temp);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_chgcyl_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ static int i;
+ int chargecycle = 0, rc;
+ struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+
+ i %= chip->min_fcc_learning_samples;
+ rc = sscanf(buf, "%d", &chargecycle);
+ if (rc != 1)
+ return -EINVAL;
+ chip->fcc_table[i].chargecycles = chargecycle;
+ pr_debug("Rcvd: [%d] chargecycle=%d\n", i, chargecycle);
+ i++;
+
+ return count;
+}
+
+static ssize_t fcc_list_get(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct qpnp_bms_chip *chip = dev_get_drvdata(dev);
+ struct fcc_data *ft;
+ int i = 0, j, count = 0;
+
+ if (last_fcc_update_count < chip->min_fcc_learning_samples)
+ i = last_fcc_update_count;
+ else
+ i = chip->min_fcc_learning_samples;
+
+ for (j = 0; j < i; j++) {
+ ft = &chip->fcc_table[j];
+ count += snprintf(buf + count, PAGE_SIZE - count,
+ "%d %d %d\n", ft->fcc_new, ft->chargecycles,
+ ft->batt_temp);
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(fcc_data, 0664, fcc_data_get, fcc_data_set);
+static DEVICE_ATTR(fcc_temp, 0664, NULL, fcc_temp_set);
+static DEVICE_ATTR(fcc_chgcyl, 0664, NULL, fcc_chgcyl_set);
+static DEVICE_ATTR(fcc_list, 0664, fcc_list_get, NULL);
+
+static struct attribute *fcc_attrs[] = {
+ &dev_attr_fcc_data.attr,
+ &dev_attr_fcc_temp.attr,
+ &dev_attr_fcc_chgcyl.attr,
+ &dev_attr_fcc_list.attr,
+ NULL
+};
+
+static const struct attribute_group fcc_attr_group = {
+ .attrs = fcc_attrs,
+};
+
#define OCV_USE_LIMIT_EN BIT(7)
static int set_ocv_voltage_thresholds(struct qpnp_bms_chip *chip,
int low_voltage_threshold,
@@ -2546,6 +2983,8 @@
batt_data = &oem_batt_data;
} else if (chip->batt_type == BATT_QRD_4V35_2000MAH) {
batt_data = &QRD_4v35_2000mAh_data;
+ } else if (chip->batt_type == BATT_QRD_4V2_1300MAH) {
+ batt_data = &qrd_4v2_1300mah_data;
} else {
battery_id = read_battery_id(chip);
if (battery_id < 0) {
@@ -2642,6 +3081,23 @@
if (chip->adjust_soc_low_threshold >= 45)
chip->adjust_soc_low_threshold = 45;
+ chip->enable_fcc_learning = of_property_read_bool(
+ chip->spmi->dev.of_node, "qcom,enable-fcc-learning");
+ if (chip->enable_fcc_learning) {
+ SPMI_PROP_READ(min_fcc_learning_soc,
+ "min-fcc-learning-soc", rc);
+ SPMI_PROP_READ(min_fcc_ocv_pc,
+ "min-fcc-ocv-pc", rc);
+ SPMI_PROP_READ(min_fcc_learning_samples,
+ "min-fcc-learning-samples", rc);
+ chip->fcc_table = kzalloc((sizeof(struct fcc_data) *
+ chip->min_fcc_learning_samples), GFP_KERNEL);
+ pr_debug("min-fcc-soc=%d, min-fcc-pc=%d, min-fcc-cycles=%d\n",
+ chip->min_fcc_learning_soc, chip->min_fcc_ocv_pc,
+ chip->min_fcc_learning_samples);
+ min_fcc_cycles = chip->min_fcc_learning_samples;
+ }
+
pr_debug("dts data: r_sense_uohm:%d, v_cutoff_uv:%d, max_v:%d\n",
chip->r_sense_uohm, chip->v_cutoff_uv,
chip->max_voltage_uv);
@@ -2870,6 +3326,28 @@
return 0;
}
+static void check_battery_removal(struct qpnp_bms_chip *chip)
+{
+ int rc;
+ u8 temp = 0;
+
+ /* check if battery was removed at PON */
+ rc = qpnp_read_wrapper(chip, &temp,
+ chip->base + BMS_BATT_REMOVED_REG, 1);
+ if (temp == 0xFF) {
+ pr_debug("New battery inserted at PON\n");
+ temp = battery_removed = 1;
+ rc = qpnp_write_wrapper(chip, &temp,
+ chip->base + BMS_BATT_REMOVED_REG, 1);
+ if (rc)
+ pr_err("Unable to set BMS_BATT_REMOVED_REG\n");
+ } else {
+ if (rc)
+ pr_err("Unable to read BMS_BATT_REMOVED_REG\n");
+ battery_removed = 0;
+ }
+}
+
static int __devinit qpnp_bms_probe(struct spmi_device *spmi)
{
struct qpnp_bms_chip *chip;
@@ -2972,9 +3450,21 @@
read_shutdown_soc_and_iavg(chip);
+ if (chip->enable_fcc_learning) {
+ restore_fcc_data(chip);
+ rc = sysfs_create_group(&spmi->dev.kobj, &fcc_attr_group);
+ if (rc) {
+ pr_err("Unable to create sysfs entries\n");
+ goto error_setup;
+ }
+ }
+
dev_set_drvdata(&spmi->dev, chip);
device_init_wakeup(&spmi->dev, 1);
+ check_battery_removal(chip);
+
+
rc = setup_vbat_monitoring(chip);
if (rc < 0) {
pr_err("failed to set up voltage notifications: %d\n", rc);
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 6a8ba46..439a8ae 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -1053,6 +1053,7 @@
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
};
static char *pm_power_supplied_to[] = {
@@ -1282,6 +1283,16 @@
return DEFAULT_TEMP;
}
+static int get_prop_cycle_count(struct qpnp_chg_chip *chip)
+{
+ union power_supply_propval ret = {0,};
+
+ if (chip->bms_psy)
+ chip->bms_psy->get_property(chip->bms_psy,
+ POWER_SUPPLY_PROP_CYCLE_COUNT, &ret);
+ return ret.intval;
+}
+
static void
qpnp_batt_external_power_changed(struct power_supply *psy)
{
@@ -1364,6 +1375,9 @@
case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
val->intval = chip->therm_lvl_sel;
break;
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ val->intval = get_prop_cycle_count(chip);
+ break;
default:
return -EINVAL;
}
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 1a4c3f3..53aa475 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -14,6 +14,7 @@
* SPI driver for Qualcomm MSM platforms
*
*/
+
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -43,6 +44,8 @@
#include <mach/msm_spi.h>
#include <mach/sps.h>
#include <mach/dma.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
#include "spi_qsd.h"
static int msm_spi_pm_resume_runtime(struct device *device);
@@ -200,6 +203,177 @@
dd->clock_speed = rate;
}
+static void msm_spi_clk_path_vote(struct msm_spi *dd)
+{
+ if (dd->clk_path_vote.client_hdl)
+ msm_bus_scale_client_update_request(
+ dd->clk_path_vote.client_hdl,
+ MSM_SPI_CLK_PATH_RESUME_VEC);
+}
+
+static void msm_spi_clk_path_unvote(struct msm_spi *dd)
+{
+ if (dd->clk_path_vote.client_hdl)
+ msm_bus_scale_client_update_request(
+ dd->clk_path_vote.client_hdl,
+ MSM_SPI_CLK_PATH_SUSPEND_VEC);
+}
+
+static void msm_spi_clk_path_teardown(struct msm_spi *dd)
+{
+ if (dd->pdata->active_only)
+ msm_spi_clk_path_unvote(dd);
+
+ if (dd->clk_path_vote.client_hdl) {
+ msm_bus_scale_unregister_client(dd->clk_path_vote.client_hdl);
+ dd->clk_path_vote.client_hdl = 0;
+ }
+}
+
+/**
+ * msm_spi_clk_path_init_structs: internal impl detail of msm_spi_clk_path_init
+ *
+ * allocates and initilizes the bus scaling vectors.
+ */
+static int msm_spi_clk_path_init_structs(struct msm_spi *dd)
+{
+ struct msm_bus_vectors *paths = NULL;
+ struct msm_bus_paths *usecases = NULL;
+
+ dev_dbg(dd->dev, "initialises path clock voting structs");
+
+ paths = devm_kzalloc(dd->dev, sizeof(*paths) * 2, GFP_KERNEL);
+ if (!paths) {
+ dev_err(dd->dev,
+ "msm_bus_paths.paths memory allocation failed");
+ return -ENOMEM;
+ }
+
+ usecases = devm_kzalloc(dd->dev, sizeof(*usecases) * 2, GFP_KERNEL);
+ if (!usecases) {
+ dev_err(dd->dev,
+ "msm_bus_scale_pdata.usecases memory allocation failed");
+ goto path_init_err;
+ }
+
+ dd->clk_path_vote.pdata = devm_kzalloc(dd->dev,
+ sizeof(*dd->clk_path_vote.pdata),
+ GFP_KERNEL);
+ if (!dd->clk_path_vote.pdata) {
+ dev_err(dd->dev,
+ "msm_bus_scale_pdata memory allocation failed");
+ goto path_init_err;
+ }
+
+ paths[MSM_SPI_CLK_PATH_SUSPEND_VEC] = (struct msm_bus_vectors) {
+ .src = dd->pdata->master_id,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ };
+
+ paths[MSM_SPI_CLK_PATH_RESUME_VEC] = (struct msm_bus_vectors) {
+ .src = dd->pdata->master_id,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = MSM_SPI_CLK_PATH_AVRG_BW(dd),
+ .ib = MSM_SPI_CLK_PATH_BRST_BW(dd),
+ };
+
+ usecases[MSM_SPI_CLK_PATH_SUSPEND_VEC] = (struct msm_bus_paths) {
+ .num_paths = 1,
+ .vectors = &paths[MSM_SPI_CLK_PATH_SUSPEND_VEC],
+ };
+
+ usecases[MSM_SPI_CLK_PATH_RESUME_VEC] = (struct msm_bus_paths) {
+ .num_paths = 1,
+ .vectors = &paths[MSM_SPI_CLK_PATH_RESUME_VEC],
+ };
+
+ *dd->clk_path_vote.pdata = (struct msm_bus_scale_pdata) {
+ .active_only = dd->pdata->active_only,
+ .name = dev_name(dd->dev),
+ .num_usecases = 2,
+ .usecase = usecases,
+ };
+
+ return 0;
+
+path_init_err:
+ devm_kfree(dd->dev, paths);
+ devm_kfree(dd->dev, usecases);
+ devm_kfree(dd->dev, dd->clk_path_vote.pdata);
+ dd->clk_path_vote.pdata = NULL;
+ return -ENOMEM;
+}
+
+/**
+ * msm_spi_clk_path_postponed_register: reg with bus-scaling after it is probed
+ *
+ * @return zero on success
+ *
+ * Workaround: SPI driver may be probed before the bus scaling driver. Calling
+ * msm_bus_scale_register_client() will fail if the bus scaling driver is not
+ * ready yet. Thus, this function should be called not from probe but from a
+ * later context. Also, this function may be called more then once before
+ * register succeed. At this case only one error message will be logged. At boot
+ * time all clocks are on, so earlier SPI transactions should succeed.
+ */
+static int msm_spi_clk_path_postponed_register(struct msm_spi *dd)
+{
+ dd->clk_path_vote.client_hdl = msm_bus_scale_register_client(
+ dd->clk_path_vote.pdata);
+
+ if (dd->clk_path_vote.client_hdl) {
+ if (dd->clk_path_vote.reg_err) {
+ /* log a success message if an error msg was logged */
+ dd->clk_path_vote.reg_err = false;
+ dev_info(dd->dev,
+ "msm_bus_scale_register_client(mstr-id:%d "
+ "actv-only:%d):0x%x",
+ dd->pdata->master_id, dd->pdata->active_only,
+ dd->clk_path_vote.client_hdl);
+ }
+
+ if (dd->pdata->active_only)
+ msm_spi_clk_path_vote(dd);
+ } else {
+ /* guard to log only one error on multiple failure */
+ if (!dd->clk_path_vote.reg_err) {
+ dd->clk_path_vote.reg_err = true;
+
+ dev_info(dd->dev,
+ "msm_bus_scale_register_client(mstr-id:%d "
+ "actv-only:%d):0",
+ dd->pdata->master_id, dd->pdata->active_only);
+ }
+ }
+
+ return dd->clk_path_vote.client_hdl ? 0 : -EAGAIN;
+}
+
+static void msm_spi_clk_path_init(struct msm_spi *dd)
+{
+ /*
+ * bail out if path voting is diabled (master_id == 0) or if it is
+ * already registered (client_hdl != 0)
+ */
+ if (!dd->pdata->master_id || dd->clk_path_vote.client_hdl)
+ return;
+
+ /* if fail once then try no more */
+ if (!dd->clk_path_vote.pdata && msm_spi_clk_path_init_structs(dd)) {
+ dd->pdata->master_id = 0;
+ return;
+ };
+
+ /* on failure try again later */
+ if (msm_spi_clk_path_postponed_register(dd))
+ return;
+
+ if (dd->pdata->active_only)
+ msm_spi_clk_path_vote(dd);
+}
+
static int msm_spi_calculate_size(int *fifo_size,
int *block_size,
int block,
@@ -1284,7 +1458,7 @@
}
if (tr->cs_change &&
- ((bpw != 8) || (bpw != 16) || (bpw != 32)))
+ ((bpw != 8) && (bpw != 16) && (bpw != 32)))
return false;
}
@@ -2359,49 +2533,148 @@
return 0;
}
-/**
- * msm_spi_dt_to_pdata: copy device-tree data to platfrom data struct
- */
-struct msm_spi_platform_data *
-__init msm_spi_dt_to_pdata(struct platform_device *pdev)
+enum msm_spi_dt_entry_status {
+ DT_REQ, /* Required: fail if missing */
+ DT_SGST, /* Suggested: warn if missing */
+ DT_OPT, /* Optional: don't warn if missing */
+};
+
+enum msm_spi_dt_entry_type {
+ DT_U32,
+ DT_GPIO,
+ DT_BOOL,
+};
+
+struct msm_spi_dt_to_pdata_map {
+ const char *dt_name;
+ void *ptr_data;
+ enum msm_spi_dt_entry_status status;
+ enum msm_spi_dt_entry_type type;
+ int default_val;
+};
+
+static int __init msm_spi_dt_to_pdata_populate(struct platform_device *pdev,
+ struct msm_spi_platform_data *pdata,
+ struct msm_spi_dt_to_pdata_map *itr)
{
+ int ret, err = 0;
struct device_node *node = pdev->dev.of_node;
+
+ for (; itr->dt_name ; ++itr) {
+ switch (itr->type) {
+ case DT_GPIO:
+ ret = of_get_named_gpio(node, itr->dt_name, 0);
+ if (ret >= 0) {
+ *((int *) itr->ptr_data) = ret;
+ ret = 0;
+ }
+ break;
+ case DT_U32:
+ ret = of_property_read_u32(node, itr->dt_name,
+ (u32 *) itr->ptr_data);
+ break;
+ case DT_BOOL:
+ *((bool *) itr->ptr_data) =
+ of_property_read_bool(node, itr->dt_name);
+ ret = 0;
+ break;
+ default:
+ dev_err(&pdev->dev, "%d is an unknown DT entry type\n",
+ itr->type);
+ ret = -EBADE;
+ }
+
+ dev_dbg(&pdev->dev, "DT entry ret:%d name:%s val:%d\n",
+ ret, itr->dt_name, *((int *)itr->ptr_data));
+
+ if (ret) {
+ *((int *)itr->ptr_data) = itr->default_val;
+
+ if (itr->status < DT_OPT) {
+ dev_err(&pdev->dev, "Missing '%s' DT entry\n",
+ itr->dt_name);
+
+ /* cont on err to dump all missing entries */
+ if (itr->status == DT_REQ && !err)
+ err = ret;
+ }
+ }
+ }
+
+ return err;
+}
+
+/**
+ * msm_spi_dt_to_pdata: create pdata and read gpio config from device tree
+ */
+struct msm_spi_platform_data * __init msm_spi_dt_to_pdata(
+ struct platform_device *pdev, struct msm_spi *dd)
+{
+ int i;
struct msm_spi_platform_data *pdata;
- int rc;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
pr_err("Unable to allocate platform data\n");
return NULL;
+ } else {
+ struct msm_spi_dt_to_pdata_map map[] = {
+ {"spi-max-frequency",
+ &pdata->max_clock_speed, DT_SGST, DT_U32, 0},
+ {"qcom,infinite-mode",
+ &pdata->infinite_mode, DT_OPT, DT_U32, 0},
+ {"qcom,active-only",
+ &pdata->active_only, DT_OPT, DT_BOOL, 0},
+ {"qcom,master-id",
+ &pdata->master_id, DT_SGST, DT_U32, 0},
+ {"qcom,ver-reg-exists",
+ &pdata->ver_reg_exists, DT_OPT, DT_BOOL, 0},
+ {"qcom,use-bam",
+ &pdata->use_bam, DT_OPT, DT_BOOL, 0},
+ {"qcom,bam-consumer-pipe-index",
+ &pdata->bam_consumer_pipe_index, DT_OPT, DT_U32, 0},
+ {"qcom,bam-producer-pipe-index",
+ &pdata->bam_producer_pipe_index, DT_OPT, DT_U32, 0},
+ {"qcom,gpio-clk",
+ &dd->spi_gpios[0], DT_OPT, DT_GPIO, -1},
+ {"qcom,gpio-miso",
+ &dd->spi_gpios[1], DT_OPT, DT_GPIO, -1},
+ {"qcom,gpio-mosi",
+ &dd->spi_gpios[2], DT_OPT, DT_GPIO, -1},
+ {"qcom,gpio-cs0",
+ &dd->cs_gpios[0].gpio_num, DT_OPT, DT_GPIO, -1},
+ {"qcom,gpio-cs1",
+ &dd->cs_gpios[1].gpio_num, DT_OPT, DT_GPIO, -1},
+ {"qcom,gpio-cs2",
+ &dd->cs_gpios[2].gpio_num, DT_OPT, DT_GPIO, -1},
+ {"qcom,gpio-cs3",
+ &dd->cs_gpios[3].gpio_num, DT_OPT, DT_GPIO, -1},
+ {NULL, NULL, 0, 0, 0},
+ };
+
+ if (msm_spi_dt_to_pdata_populate(pdev, pdata, map)) {
+ devm_kfree(&pdev->dev, pdata);
+ return NULL;
+ }
}
- of_property_read_u32(node, "spi-max-frequency",
- &pdata->max_clock_speed);
- of_property_read_u32(node, "qcom,infinite-mode",
- &pdata->infinite_mode);
-
- pdata->ver_reg_exists = of_property_read_bool(node
- , "qcom,ver-reg-exists");
-
- pdata->use_bam = of_property_read_bool(node, "qcom,use-bam");
-
if (pdata->use_bam) {
- rc = of_property_read_u32(node, "qcom,bam-consumer-pipe-index",
- &pdata->bam_consumer_pipe_index);
- if (rc) {
+ if (!pdata->bam_consumer_pipe_index) {
dev_warn(&pdev->dev,
"missing qcom,bam-consumer-pipe-index entry in device-tree\n");
pdata->use_bam = false;
}
- rc = of_property_read_u32(node, "qcom,bam-producer-pipe-index",
- &pdata->bam_producer_pipe_index);
- if (rc) {
+ if (pdata->bam_producer_pipe_index) {
dev_warn(&pdev->dev,
"missing qcom,bam-producer-pipe-index entry in device-tree\n");
pdata->use_bam = false;
}
}
+
+ for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i)
+ dd->cs_gpios[i].valid = (dd->cs_gpios[i].gpio_num >= 0);
+
return pdata;
}
@@ -2461,7 +2734,6 @@
int clk_enabled = 0;
int pclk_enabled = 0;
struct msm_spi_platform_data *pdata;
- enum of_gpio_flags flags;
master = spi_alloc_master(&pdev->dev, sizeof(struct msm_spi));
if (!master) {
@@ -2481,7 +2753,7 @@
if (pdev->dev.of_node) {
dd->qup_ver = SPI_QUP_VERSION_BFAM;
master->dev.of_node = pdev->dev.of_node;
- pdata = msm_spi_dt_to_pdata(pdev);
+ pdata = msm_spi_dt_to_pdata(pdev, dd);
if (!pdata) {
rc = -ENOMEM;
goto err_probe_exit;
@@ -2493,18 +2765,6 @@
"using default bus_num %d\n", pdev->id);
else
master->bus_num = pdev->id = rc;
-
- for (i = 0; i < ARRAY_SIZE(spi_rsrcs); ++i) {
- dd->spi_gpios[i] = of_get_gpio_flags(pdev->dev.of_node,
- i, &flags);
- }
-
- for (i = 0; i < ARRAY_SIZE(spi_cs_rsrcs); ++i) {
- dd->cs_gpios[i].gpio_num = of_get_named_gpio_flags(
- pdev->dev.of_node, "cs-gpios",
- i, &flags);
- dd->cs_gpios[i].valid = 0;
- }
} else {
pdata = pdev->dev.platform_data;
dd->qup_ver = SPI_QUP_VERSION_NONE;
@@ -2808,6 +3068,8 @@
msm_spi_disable_irqs(dd);
clk_disable_unprepare(dd->clk);
clk_disable_unprepare(dd->pclk);
+ if (!dd->pdata->active_only)
+ msm_spi_clk_path_unvote(dd);
/* Free the spi clk, miso, mosi, cs gpio */
if (dd->pdata && dd->pdata->gpio_release)
@@ -2858,10 +3120,14 @@
if (ret)
return ret;
+ msm_spi_clk_path_init(dd);
+ if (!dd->pdata->active_only)
+ msm_spi_clk_path_vote(dd);
clk_prepare_enable(dd->clk);
clk_prepare_enable(dd->pclk);
msm_spi_enable_irqs(dd);
dd->suspended = 0;
+
resume_exit:
return 0;
}
@@ -2917,6 +3183,7 @@
pm_runtime_set_suspended(&pdev->dev);
clk_put(dd->clk);
clk_put(dd->pclk);
+ msm_spi_clk_path_teardown(dd);
destroy_workqueue(dd->workqueue);
platform_set_drvdata(pdev, 0);
spi_unregister_master(master);
diff --git a/drivers/spi/spi_qsd.h b/drivers/spi/spi_qsd.h
index fd1adf0..90d7481 100644
--- a/drivers/spi/spi_qsd.h
+++ b/drivers/spi/spi_qsd.h
@@ -173,6 +173,13 @@
#define SPI_BAM_MAX_DESC_NUM 32
#define SPI_MAX_TRFR_BTWN_RESETS ((64 * 1024) - 16) /* 64KB - 16byte */
+enum msm_spi_clk_path_vec_idx {
+ MSM_SPI_CLK_PATH_SUSPEND_VEC = 0,
+ MSM_SPI_CLK_PATH_RESUME_VEC = 1,
+};
+#define MSM_SPI_CLK_PATH_AVRG_BW(dd) (dd->pdata->max_clock_speed * 8)
+#define MSM_SPI_CLK_PATH_BRST_BW(dd) (dd->pdata->max_clock_speed * 8)
+
static char const * const spi_rsrcs[] = {
"spi_clk",
"spi_miso",
@@ -253,6 +260,22 @@
};
#endif
+/**
+ * qup_i2c_clk_path_vote: data to use bus scaling driver for clock path vote
+ *
+ * @client_hdl when zero, client is not registered with the bus scaling driver,
+ * and bus scaling functionality should not be used. When non zero, it
+ * is a bus scaling client id and may be used to vote for clock path.
+ * @reg_err when true, registration error was detected and an error message was
+ * logged. i2c will attempt to re-register but will log error only once.
+ * once registration succeed, the flag is set to false.
+ */
+struct qup_i2c_clk_path_vote {
+ u32 client_hdl;
+ struct msm_bus_scale_pdata *pdata;
+ bool reg_err;
+};
+
struct msm_spi_bam_pipe {
struct sps_pipe *handle;
struct sps_connect config;
@@ -284,6 +307,7 @@
struct completion transfer_complete;
struct clk *clk; /* core clock */
struct clk *pclk; /* interface clock */
+ struct qup_i2c_clk_path_vote clk_path_vote;
unsigned long mem_phys_addr;
size_t mem_size;
int input_fifo_size;
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index a27eb09..6aeb26e 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -37,6 +37,8 @@
#include <linux/regulator/consumer.h>
#include <linux/power_supply.h>
#include <linux/qpnp/qpnp-adc.h>
+#include <linux/cdev.h>
+#include <linux/completion.h>
#include <mach/rpm-regulator.h>
#include <mach/rpm-regulator-smd.h>
@@ -134,6 +136,7 @@
*
*/
#define QSCRATCH_REG_OFFSET (0x000F8800)
+#define QSCRATCH_CTRL_REG (QSCRATCH_REG_OFFSET + 0x04)
#define QSCRATCH_GENERAL_CFG (QSCRATCH_REG_OFFSET + 0x08)
#define HS_PHY_CTRL_REG (QSCRATCH_REG_OFFSET + 0x10)
#define PARAMETER_OVERRIDE_X_REG (QSCRATCH_REG_OFFSET + 0x14)
@@ -218,6 +221,15 @@
unsigned long lpm_flags;
#define MDWC3_CORECLK_OFF BIT(0)
#define MDWC3_TCXO_SHUTDOWN BIT(1)
+
+ u32 qscratch_ctl_val;
+ dev_t ext_chg_dev;
+ struct cdev ext_chg_cdev;
+ struct class *ext_chg_class;
+ struct device *ext_chg_device;
+ bool ext_chg_opened;
+ bool ext_chg_active;
+ struct completion ext_chg_wait;
};
#define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */
@@ -1362,6 +1374,11 @@
dwc3_msm_read_reg(msm->base, CGCTL_REG) | 0x18);
dwc3_msm_ss_phy_reg_init(msm);
+ /*
+ * This is required to restore the POR value after userspace
+ * is done with charger detection.
+ */
+ msm->qscratch_ctl_val = dwc3_msm_read_reg(msm->base, QSCRATCH_CTRL_REG);
}
static void dwc3_msm_block_reset(bool core_reset)
@@ -1469,6 +1486,8 @@
{
u32 chg_ctrl;
+ dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
+ mdwc->qscratch_ctl_val);
/* Clear charger detecting control bits */
dwc3_msm_write_reg(mdwc->base, CHARGING_DET_CTRL_REG, 0x0);
@@ -1562,9 +1581,14 @@
case USB_CHG_STATE_DETECTED:
dwc3_chg_block_reset(mdwc);
/* Enable VDP_SRC */
- if (mdwc->charger.chg_type == DWC3_DCP_CHARGER)
+ if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
dwc3_msm_write_readback(mdwc->base,
CHARGING_DET_CTRL_REG, 0x1F, 0x10);
+ if (mdwc->ext_chg_opened) {
+ init_completion(&mdwc->ext_chg_wait);
+ mdwc->ext_chg_active = true;
+ }
+ }
dev_dbg(mdwc->dev, "chg_type = %s\n",
chg_to_string(mdwc->charger.chg_type));
mdwc->charger.notify_detection_complete(mdwc->otg_xceiv->otg,
@@ -1626,6 +1650,10 @@
(mdwc->charger.chg_type == DWC3_PROPRIETARY_CHARGER));
host_bus_suspend = mdwc->host_mode == 1;
+ if (!dcp && !host_bus_suspend)
+ dwc3_msm_write_reg(mdwc->base, QSCRATCH_CTRL_REG,
+ mdwc->qscratch_ctl_val);
+
/* Sequence to put SSPHY in low power state:
* 1. Clear REF_SS_PHY_EN in SS_PHY_CTRL_REG
* 2. Clear REF_USE_PAD in SS_PHY_CTRL_REG
@@ -1850,6 +1878,30 @@
return 0;
}
+static void dwc3_wait_for_ext_chg_done(struct dwc3_msm *mdwc)
+{
+ unsigned long t;
+
+ /*
+ * Defer next cable connect event till external charger
+ * detection is completed.
+ */
+
+ if (mdwc->ext_chg_active && (mdwc->ext_xceiv.bsv ||
+ !mdwc->ext_xceiv.id)) {
+
+ dev_dbg(mdwc->dev, "before ext chg wait\n");
+
+ t = wait_for_completion_timeout(&mdwc->ext_chg_wait,
+ msecs_to_jiffies(3000));
+ if (!t)
+ dev_err(mdwc->dev, "ext chg wait timeout\n");
+ else
+ dev_dbg(mdwc->dev, "ext chg wait done\n");
+ }
+
+}
+
static void dwc3_resume_work(struct work_struct *w)
{
struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
@@ -1859,9 +1911,11 @@
/* handle any event that was queued while work was already running */
if (!atomic_read(&mdwc->in_lpm)) {
dev_dbg(mdwc->dev, "%s: notifying xceiv event\n", __func__);
- if (mdwc->otg_xceiv)
+ if (mdwc->otg_xceiv) {
+ dwc3_wait_for_ext_chg_done(mdwc);
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_XCEIV_STATE);
+ }
return;
}
@@ -1874,9 +1928,11 @@
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_PHY_RESUME);
pm_runtime_put_noidle(mdwc->dev);
- if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability))
+ if (mdwc->otg_xceiv && (mdwc->ext_xceiv.otg_capability)) {
+ dwc3_wait_for_ext_chg_done(mdwc);
mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
DWC3_EVENT_XCEIV_STATE);
+ }
}
}
@@ -2089,6 +2145,7 @@
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_TYPE,
POWER_SUPPLY_PROP_SCOPE,
};
@@ -2261,6 +2318,131 @@
static DEVICE_ATTR(adc_enable, S_IRUGO | S_IWUSR, adc_enable_show,
adc_enable_store);
+static int dwc3_msm_ext_chg_open(struct inode *inode, struct file *file)
+{
+ struct dwc3_msm *mdwc = context;
+
+ pr_debug("dwc3-msm ext chg open\n");
+
+ mdwc->ext_chg_opened = true;
+ return 0;
+}
+
+static ssize_t
+dwc3_msm_ext_chg_write(struct file *file, const char __user *ubuf,
+ size_t size, loff_t *pos)
+{
+ struct dwc3_msm *mdwc = context;
+ char kbuf[16];
+
+ memset(kbuf, 0x00, sizeof(kbuf));
+ if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, size)))
+ return -EFAULT;
+
+ pr_debug("%s: buf = %s\n", __func__, kbuf);
+
+ if (!strncmp(kbuf, "enable", 6)) {
+ pr_info("%s: on\n", __func__);
+ if (mdwc->charger.chg_type == DWC3_DCP_CHARGER) {
+ pm_runtime_get_sync(mdwc->dev);
+ } else {
+ mdwc->ext_chg_active = false;
+ complete(&mdwc->ext_chg_wait);
+ return -ENODEV;
+ }
+ } else if (!strncmp(kbuf, "disable", 7)) {
+ pr_info("%s: off\n", __func__);
+ mdwc->ext_chg_active = false;
+ complete(&mdwc->ext_chg_wait);
+ pm_runtime_put(mdwc->dev);
+ } else {
+ return -EINVAL;
+ }
+
+ return size;
+}
+
+static int dwc3_msm_ext_chg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ unsigned long vsize = vma->vm_end - vma->vm_start;
+ int ret;
+
+ pr_debug("%s: size = %lu %x\n", __func__, vsize, (int) vma->vm_pgoff);
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+ vsize, vma->vm_page_prot);
+ if (ret < 0)
+ pr_err("%s: failed with return val %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int dwc3_msm_ext_chg_release(struct inode *inode, struct file *file)
+{
+ struct dwc3_msm *mdwc = context;
+
+ pr_debug("dwc3-msm ext chg release\n");
+
+ mdwc->ext_chg_opened = false;
+
+ return 0;
+}
+
+static const struct file_operations dwc3_msm_ext_chg_fops = {
+ .owner = THIS_MODULE,
+ .open = dwc3_msm_ext_chg_open,
+ .write = dwc3_msm_ext_chg_write,
+ .mmap = dwc3_msm_ext_chg_mmap,
+ .release = dwc3_msm_ext_chg_release,
+};
+
+static int dwc3_msm_setup_cdev(struct dwc3_msm *mdwc)
+{
+ int ret;
+
+ ret = alloc_chrdev_region(&mdwc->ext_chg_dev, 0, 1, "usb_ext_chg");
+ if (ret < 0) {
+ pr_err("Fail to allocate usb ext char dev region\n");
+ return ret;
+ }
+ mdwc->ext_chg_class = class_create(THIS_MODULE, "dwc_ext_chg");
+ if (ret < 0) {
+ pr_err("Fail to create usb ext chg class\n");
+ goto unreg_chrdev;
+ }
+ cdev_init(&mdwc->ext_chg_cdev, &dwc3_msm_ext_chg_fops);
+ mdwc->ext_chg_cdev.owner = THIS_MODULE;
+
+ ret = cdev_add(&mdwc->ext_chg_cdev, mdwc->ext_chg_dev, 1);
+ if (ret < 0) {
+ pr_err("Fail to add usb ext chg cdev\n");
+ goto destroy_class;
+ }
+ mdwc->ext_chg_device = device_create(mdwc->ext_chg_class,
+ NULL, mdwc->ext_chg_dev, NULL,
+ "usb_ext_chg");
+ if (IS_ERR(mdwc->ext_chg_device)) {
+ pr_err("Fail to create usb ext chg device\n");
+ ret = PTR_ERR(mdwc->ext_chg_device);
+ mdwc->ext_chg_device = NULL;
+ goto del_cdev;
+ }
+
+ pr_debug("dwc3 msm ext chg cdev setup success\n");
+ return 0;
+
+del_cdev:
+ cdev_del(&mdwc->ext_chg_cdev);
+destroy_class:
+ class_destroy(mdwc->ext_chg_class);
+unreg_chrdev:
+ unregister_chrdev_region(mdwc->ext_chg_dev, 1);
+
+ return ret;
+}
+
static int __devinit dwc3_msm_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@@ -2288,6 +2470,7 @@
INIT_WORK(&msm->restart_usb_work, dwc3_restart_usb_work);
INIT_WORK(&msm->id_work, dwc3_id_work);
INIT_DELAYED_WORK(&msm->init_adc_work, dwc3_init_adc_work);
+ init_completion(&msm->ext_chg_wait);
msm->xo_clk = clk_get(&pdev->dev, "xo");
if (IS_ERR(msm->xo_clk)) {
@@ -2651,6 +2834,11 @@
}
msm->otg_xceiv = NULL;
}
+ if (msm->ext_xceiv.otg_capability && msm->charger.start_detection) {
+ ret = dwc3_msm_setup_cdev(msm);
+ if (ret)
+ dev_err(&pdev->dev, "Fail to setup dwc3 setup cdev\n");
+ }
wake_lock_init(&msm->wlock, WAKE_LOCK_SUSPEND, "msm_dwc3");
wake_lock(&msm->wlock);
@@ -2703,6 +2891,13 @@
{
struct dwc3_msm *msm = platform_get_drvdata(pdev);
+ if (!msm->ext_chg_device) {
+ device_destroy(msm->ext_chg_class, msm->ext_chg_dev);
+ cdev_del(&msm->ext_chg_cdev);
+ class_destroy(msm->ext_chg_class);
+ unregister_chrdev_region(msm->ext_chg_dev, 1);
+ }
+
if (msm->id_adc_detect)
qpnp_adc_tm_usbid_end();
if (dwc3_debugfs_root)
@@ -2791,8 +2986,27 @@
static int dwc3_msm_runtime_idle(struct device *dev)
{
+ struct dwc3_msm *mdwc = dev_get_drvdata(dev);
+
dev_dbg(dev, "DWC3-msm runtime idle\n");
+ if (mdwc->ext_chg_active) {
+ dev_dbg(dev, "Deferring LPM\n");
+ /*
+ * Charger detection may happen in user space.
+ * Delay entering LPM by 3 sec. Otherwise we
+ * have to exit LPM when user space begins
+ * charger detection.
+ *
+ * This timer will be canceled when user space
+ * votes against LPM by incrementing PM usage
+ * counter. We enter low power mode when
+ * PM usage counter is decremented.
+ */
+ pm_schedule_suspend(dev, 3000);
+ return -EAGAIN;
+ }
+
return 0;
}
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 3cad3ce..8d8c30e 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -16,6 +16,8 @@
#define MSM_USB_BASE (udc->regs)
+#define CI13XXX_MSM_MAX_ITC_LEVEL 6
+
struct ci13xxx_udc_context {
int irq;
void __iomem *regs;
@@ -177,7 +179,7 @@
CI13XXX_ZERO_ITC |
CI13XXX_DISABLE_STREAMING |
CI13XXX_IS_OTG,
-
+ .nz_itc = 0,
.notify_event = ci13xxx_msm_notify_event,
};
@@ -230,10 +232,21 @@
static int ci13xxx_msm_probe(struct platform_device *pdev)
{
struct resource *res;
- int ret;
+ int ret, rc;
+ int itc_level = 0;
dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n");
+ if (pdev->dev.of_node) {
+ rc = of_property_read_u32(pdev->dev.of_node, "qcom,itc-level",
+ &itc_level);
+ /* Acceptable values for nz_itc are: 0,1,2,4,8,16,32,64 */
+ if (itc_level > CI13XXX_MSM_MAX_ITC_LEVEL || rc)
+ ci13xxx_msm_udc_driver.nz_itc = 0;
+ else
+ ci13xxx_msm_udc_driver.nz_itc = 1 << itc_level;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get platform resource mem\n");
@@ -313,9 +326,18 @@
writel_relaxed(val, USB_GENCONFIG);
}
+static const struct of_device_id ci13xx_msm_dt_match[] = {
+ { .compatible = "qcom,ci13xxx_msm",
+ },
+ {}
+};
+
static struct platform_driver ci13xxx_msm_driver = {
.probe = ci13xxx_msm_probe,
- .driver = { .name = "msm_hsusb", },
+ .driver = {
+ .name = "msm_hsusb",
+ .of_match_table = ci13xx_msm_dt_match,
+ },
.remove = ci13xxx_msm_remove,
};
MODULE_ALIAS("platform:msm_hsusb");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 939eb6d..e7074a2 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -367,7 +367,10 @@
* 8 micro frames. If CPU can handle interrupts at faster rate, ITC
* can be set to lesser value to gain performance.
*/
- if (udc->udc_driver->flags & CI13XXX_ZERO_ITC)
+ if (udc->udc_driver->nz_itc)
+ hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK,
+ USBCMD_ITC(udc->udc_driver->nz_itc));
+ else if (udc->udc_driver->flags & CI13XXX_ZERO_ITC)
hw_cwrite(CAP_USBCMD, USBCMD_ITC_MASK, USBCMD_ITC(0));
if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) {
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 4c5b38d..09404c8 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -129,6 +129,7 @@
struct ci13xxx_udc_driver {
const char *name;
unsigned long flags;
+ unsigned int nz_itc;
#define CI13XXX_REGS_SHARED BIT(0)
#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1)
#define CI13XXX_PULLUP_ON_VBUS BIT(2)
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index 9dd9978..edcafcc 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -848,6 +848,7 @@
d->rx_req->context = port;
d->rx_req->complete = gbam_endless_rx_complete;
d->rx_req->length = 0;
+ d->rx_req->no_interrupt = 1;
sps_params = (MSM_SPS_MODE | d->src_pipe_idx |
MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
d->rx_req->udc_priv = sps_params;
@@ -863,6 +864,7 @@
d->tx_req->context = port;
d->tx_req->complete = gbam_endless_tx_complete;
d->tx_req->length = 0;
+ d->tx_req->no_interrupt = 1;
sps_params = (MSM_SPS_MODE | d->dst_pipe_idx |
MSM_VENDOR_ID) & ~MSM_IS_FINITE_TRANSFER;
d->tx_req->udc_priv = sps_params;
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index 5c7e52f..d470edf 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -296,6 +296,7 @@
d->rx_req->context = port;
d->rx_req->complete = bam_data_endless_rx_complete;
d->rx_req->length = 0;
+ d->rx_req->no_interrupt = 1;
sps_params = (SPS_PARAMS_SPS_MODE | d->src_pipe_idx |
MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
d->rx_req->udc_priv = sps_params;
@@ -306,6 +307,7 @@
d->tx_req->context = port;
d->tx_req->complete = bam_data_endless_tx_complete;
d->tx_req->length = 0;
+ d->tx_req->no_interrupt = 1;
sps_params = (SPS_PARAMS_SPS_MODE | d->dst_pipe_idx |
MSM_VENDOR_ID) & ~SPS_PARAMS_TBE;
d->tx_req->udc_priv = sps_params;
diff --git a/drivers/video/msm/mdss/dsi_io_v2.c b/drivers/video/msm/mdss/dsi_io_v2.c
index cbdd241..273fb54 100644
--- a/drivers/video/msm/mdss/dsi_io_v2.c
+++ b/drivers/video/msm/mdss/dsi_io_v2.c
@@ -437,5 +437,9 @@
void msm_dsi_phy_off(unsigned char *ctrl_base)
{
+ MIPI_OUTP(ctrl_base + DSI_DSIPHY_PLL_CTRL_5, 0x05f);
+ MIPI_OUTP(ctrl_base + DSI_DSIPHY_REGULATOR_CTRL_0, 0x02);
MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_0, 0x00);
+ MIPI_OUTP(ctrl_base + DSI_DSIPHY_CTRL_1, 0x7f);
+ MIPI_OUTP(ctrl_base + DSI_CLK_CTRL, 0);
}
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 734756c..98e7e29 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -125,7 +125,7 @@
if (enable)
INIT_COMPLETION(mdp3_session->vsync_comp);
else
- complete_all(&mdp3_session->vsync_comp);
+ complete(&mdp3_session->vsync_comp);
spin_unlock_irqrestore(&mdp3_session->vsync_lock, flag);
return 0;
}
diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c
index afabc20..366209b 100644
--- a/drivers/video/msm/mdss/mdss_dsi.c
+++ b/drivers/video/msm/mdss/mdss_dsi.c
@@ -417,7 +417,7 @@
mdss_dsi_clk_ctrl(ctrl_pdata, 0);
/* disable DSI phy */
- mdss_dsi_phy_enable(ctrl_pdata->ctrl_base, 0);
+ mdss_dsi_phy_enable(ctrl_pdata, 0);
mdss_dsi_disable_bus_clocks(ctrl_pdata);
diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h
index f612751..965a23f 100644
--- a/drivers/video/msm/mdss/mdss_dsi.h
+++ b/drivers/video/msm/mdss/mdss_dsi.h
@@ -412,7 +412,7 @@
int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable);
-void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on);
+void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on);
void mdss_dsi_phy_init(struct mdss_panel_data *pdata);
void mdss_dsi_phy_sw_reset(unsigned char *ctrl_base);
void mdss_dsi_cmd_test_pattern(struct mdss_panel_data *pdata);
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index e16f2df..d9fffa8 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -634,8 +634,11 @@
mfd->op_enable = false;
curr_pwr_state = mfd->panel_power_on;
+ mutex_lock(&mfd->bl_lock);
+ mdss_fb_set_backlight(mfd, 0);
mfd->panel_power_on = false;
bl_updated = 0;
+ mutex_unlock(&mfd->bl_lock);
ret = mfd->mdp.off_fnc(mfd);
if (ret)
diff --git a/drivers/video/msm/mdss/mdss_mdp_pp.c b/drivers/video/msm/mdss/mdss_mdp_pp.c
index 5d7a0c9..963d3fb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_pp.c
+++ b/drivers/video/msm/mdss/mdss_mdp_pp.c
@@ -288,7 +288,8 @@
struct pp_sts_type *pp_sts,
struct mdp_sharp_cfg *sharp_config);
static int mdss_ad_init_checks(struct msm_fb_data_type *mfd);
-static struct mdss_ad_info *mdss_mdp_get_ad(struct msm_fb_data_type *mfd);
+static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
+ struct mdss_ad_info **ad);
static int pp_update_ad_input(struct msm_fb_data_type *mfd);
static void pp_ad_vsync_handler(struct mdss_mdp_ctl *ctl, ktime_t t);
static void pp_ad_cfg_write(struct mdss_ad_info *ad);
@@ -2548,7 +2549,7 @@
hist_info = &mdss_pp_res->dspp_hist[dspp_num];
mutex_lock(&hist_info->hist_mutex);
for (j = 0; j < HIST_V_SIZE; j++)
- hist_concat[i] += hist_info->data[i];
+ hist_concat[j] += hist_info->data[j];
mutex_unlock(&hist_info->hist_mutex);
}
hist_data_addr = hist_concat;
@@ -2731,8 +2732,12 @@
}
mixer_num = mdss_mdp_get_ctl_mixers(mfd->index, mixer_id);
- if (!mixer_num || mixer_num > MDSS_AD_MAX_MIXERS) {
- pr_err("invalid mixer_num, %d", mixer_num);
+ if (!mixer_num) {
+ pr_debug("no mixers connected, %d", mixer_num);
+ return -EHOSTDOWN;
+ }
+ if (mixer_num > MDSS_AD_MAX_MIXERS) {
+ pr_warn("too many mixers, not supported, %d", mixer_num);
return ret;
}
@@ -2747,9 +2752,10 @@
return mixer_id[0];
}
-static struct mdss_ad_info *mdss_mdp_get_ad(struct msm_fb_data_type *mfd)
+static int mdss_mdp_get_ad(struct msm_fb_data_type *mfd,
+ struct mdss_ad_info **ret_ad)
{
- int ad_num;
+ int ad_num, ret = 0;
struct mdss_data_type *mdata;
struct mdss_ad_info *ad = NULL;
mdata = mfd_to_mdata(mfd);
@@ -2757,11 +2763,15 @@
ad_num = mdss_ad_init_checks(mfd);
if (ad_num >= 0)
ad = &mdata->ad_cfgs[ad_num];
- return ad;
+ else
+ ret = ad_num;
+ *ret_ad = ad;
+ return ret;
}
static int pp_update_ad_input(struct msm_fb_data_type *mfd)
{
+ int ret;
struct mdss_ad_info *ad;
struct mdss_ad_input input;
struct mdss_mdp_ctl *ctl;
@@ -2772,7 +2782,9 @@
if (!ctl)
return -EINVAL;
- ad = mdss_mdp_get_ad(mfd);
+ ret = mdss_mdp_get_ad(mfd, &ad);
+ if (ret)
+ return ret;
if (!ad || ad->cfg.mode == MDSS_AD_MODE_AUTO_BL)
return -EINVAL;
@@ -2795,9 +2807,9 @@
int lin_ret = -1, inv_ret = -1, ret = 0;
u32 ratio_temp, shift = 0;
- ad = mdss_mdp_get_ad(mfd);
- if (!ad)
- return -EINVAL;
+ ret = mdss_mdp_get_ad(mfd, &ad);
+ if (ret)
+ return ret;
mutex_lock(&ad->lock);
if (init_cfg->ops & MDP_PP_AD_INIT) {
@@ -2862,9 +2874,9 @@
struct mdss_mdp_ctl *ctl;
u32 bl;
- ad = mdss_mdp_get_ad(mfd);
- if (!ad)
- return -EINVAL;
+ ret = mdss_mdp_get_ad(mfd, &ad);
+ if (ret)
+ return ret;
mutex_lock(&ad->lock);
if ((!PP_AD_STATE_IS_INITCFG(ad->state) &&
@@ -3074,9 +3086,9 @@
char __iomem *base;
u32 bypass = MDSS_PP_AD_BYPASS_DEF, bl;
- ad = mdss_mdp_get_ad(mfd);
- if (!ad)
- return -EINVAL;
+ ret = mdss_mdp_get_ad(mfd, &ad);
+ if (ret)
+ return ret;
base = ad->base;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index d4eb716..aab67df 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -287,42 +287,66 @@
wmb();
}
-void mdss_dsi_phy_enable(unsigned char *ctrl_base, int on)
+void mdss_dsi_phy_enable(struct mdss_dsi_ctrl_pdata *ctrl, int on)
{
+ static struct mdss_dsi_ctrl_pdata *left_ctrl;
+
+ if (ctrl == NULL) {
+ pr_err("%s: Invalid input data\n", __func__);
+ return;
+ }
+
+ if (!left_ctrl
+ && ctrl->shared_pdata.broadcast_enable)
+ if ((ctrl->panel_data).panel_info.pdest
+ == DISPLAY_1)
+ left_ctrl = ctrl;
+
if (on) {
- MIPI_OUTP(ctrl_base + 0x03cc, 0x03);
+ MIPI_OUTP(ctrl->ctrl_base + 0x03cc, 0x03);
wmb();
usleep(100);
- MIPI_OUTP(ctrl_base + 0x0220, 0x006);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x006);
wmb();
usleep(100);
- MIPI_OUTP(ctrl_base + 0x0268, 0x001);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0268, 0x001);
wmb();
usleep(100);
- MIPI_OUTP(ctrl_base + 0x0268, 0x000);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0268, 0x000);
wmb();
usleep(100);
- MIPI_OUTP(ctrl_base + 0x0220, 0x007);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x007);
wmb();
- MIPI_OUTP(ctrl_base + 0x03cc, 0x01);
+ MIPI_OUTP(ctrl->ctrl_base + 0x03cc, 0x01);
wmb();
usleep(100);
/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
- MIPI_OUTP(ctrl_base + 0x0470, 0x07e);
- MIPI_OUTP(ctrl_base + 0x0470, 0x06e);
- MIPI_OUTP(ctrl_base + 0x0470, 0x06c);
- MIPI_OUTP(ctrl_base + 0x0470, 0x064);
- MIPI_OUTP(ctrl_base + 0x0470, 0x065);
- MIPI_OUTP(ctrl_base + 0x0470, 0x075);
- MIPI_OUTP(ctrl_base + 0x0470, 0x077);
- MIPI_OUTP(ctrl_base + 0x0470, 0x07f);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x07e);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x06e);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x06c);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x064);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x065);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x075);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x077);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x07f);
wmb();
-
} else {
- MIPI_OUTP(ctrl_base + 0x0220, 0x006);
- MIPI_OUTP(ctrl_base + 0x0470, 0x000);
- MIPI_OUTP(ctrl_base + 0x0598, 0x000);
+ if (left_ctrl &&
+ (ctrl->panel_data.panel_info.pdest
+ == DISPLAY_1))
+ return;
+
+ if (left_ctrl &&
+ (ctrl->panel_data.panel_info.pdest
+ == DISPLAY_2)) {
+ MIPI_OUTP(left_ctrl->ctrl_base + 0x0220, 0x006);
+ MIPI_OUTP(left_ctrl->ctrl_base + 0x0470, 0x000);
+ MIPI_OUTP(left_ctrl->ctrl_base + 0x0598, 0x000);
+ }
+ MIPI_OUTP(ctrl->ctrl_base + 0x0220, 0x006);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0470, 0x000);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0598, 0x000);
wmb();
}
}
diff --git a/include/linux/mfd/pm8xxx/batterydata-lib.h b/include/linux/mfd/pm8xxx/batterydata-lib.h
index 47a2b7b..644eede 100644
--- a/include/linux/mfd/pm8xxx/batterydata-lib.h
+++ b/include/linux/mfd/pm8xxx/batterydata-lib.h
@@ -75,6 +75,7 @@
BATT_DESAY,
BATT_OEM,
BATT_QRD_4V35_2000MAH,
+ BATT_QRD_4V2_1300MAH,
};
/**
@@ -116,6 +117,7 @@
extern struct bms_battery_data desay_5200_data;
extern struct bms_battery_data oem_batt_data;
extern struct bms_battery_data QRD_4v35_2000mAh_data;
+extern struct bms_battery_data qrd_4v2_1300mah_data;
int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp);
int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc);
diff --git a/include/linux/mfd/pm8xxx/pwm.h b/include/linux/mfd/pm8xxx/pwm.h
index 6d95e3a..47ebe06 100644
--- a/include/linux/mfd/pm8xxx/pwm.h
+++ b/include/linux/mfd/pm8xxx/pwm.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -32,6 +32,9 @@
#define PM_PWM_LUT_NO_TABLE 0x100
+#define PM_PWM_BANK_LO 0x1000
+#define PM_PWM_BANK_HI 0x2000
+
/**
* PWM frequency/period control
*
diff --git a/include/media/msmb_isp.h b/include/media/msmb_isp.h
index 25d528d7..4d36688 100644
--- a/include/media/msmb_isp.h
+++ b/include/media/msmb_isp.h
@@ -375,6 +375,7 @@
#define V4L2_PIX_FMT_QRGGB12 v4l2_fourcc('Q', 'R', 'G', '2')
#define V4L2_PIX_FMT_NV14 v4l2_fourcc('N', 'V', '1', '4')
#define V4L2_PIX_FMT_NV41 v4l2_fourcc('N', 'V', '4', '1')
+#define V4L2_PIX_FMT_META v4l2_fourcc('Q', 'M', 'E', 'T')
#define VIDIOC_MSM_VFE_REG_CFG \
_IOWR('V', BASE_VIDIOC_PRIVATE, struct msm_vfe_cfg_cmd2)
diff --git a/include/media/msmb_ispif.h b/include/media/msmb_ispif.h
index c9eb12a..61dfd52 100644
--- a/include/media/msmb_ispif.h
+++ b/include/media/msmb_ispif.h
@@ -1,8 +1,10 @@
#ifndef MSM_CAM_ISPIF_H
#define MSM_CAM_ISPIF_H
-#define CSID_VERSION_V2 0x02000011
-#define CSID_VERSION_V3 0x30000000
+#define CSID_VERSION_V20 0x02000011
+#define CSID_VERSION_V22 0x02001000
+#define CSID_VERSION_V30 0x30000000
+#define CSID_VERSION_V3 0x30000000
enum msm_ispif_vfe_intf {
VFE0,
diff --git a/sound/soc/codecs/wcd9320.c b/sound/soc/codecs/wcd9320.c
index 67c03d6..a4f3c21 100644
--- a/sound/soc/codecs/wcd9320.c
+++ b/sound/soc/codecs/wcd9320.c
@@ -5885,6 +5885,9 @@
TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_RESET_B1_CTL, 0x00),
TAIKO_REG_VAL(TAIKO_A_CDC_CLK_OTHR_CTL, 0x00),
TAIKO_REG_VAL(TAIKO_A_CDC_CONN_MAD, 0x01),
+
+ /* Set HPH Path to low power mode */
+ TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x55),
};
static const struct wcd9xxx_reg_mask_val taiko_1_0_reg_defaults[] = {
@@ -5912,8 +5915,6 @@
* Rx PA bring up.
*/
TAIKO_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
- /* Reduce HPH DAC bias to 70% */
- TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
/*Reduce EAR DAC bias to 70% */
TAIKO_REG_VAL(TAIKO_A_RX_EAR_BIAS_PA, 0x76),
/* Reduce LINE DAC bias to 70% */
@@ -5955,7 +5956,6 @@
TAIKO_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x51),
TAIKO_REG_VAL(TAIKO_A_NCP_DTEST, 0x10),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CHOP_CTL, 0xA4),
- TAIKO_REG_VAL(TAIKO_A_RX_HPH_BIAS_PA, 0x7A),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_OCP_CTL, 0x69),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CNP_WG_CTL, 0xDA),
TAIKO_REG_VAL(TAIKO_A_RX_HPH_CNP_WG_TIME, 0x15),
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index e853061..3c226f7 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -677,7 +677,7 @@
&mbhc->hph_pa_dac_state)) {
pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL,
- 0xC0, 0xC0);
+ 0x80, 0x80);
}
if (test_and_clear_bit(WCD9XXX_HPHR_PA_OFF_ACK,
diff --git a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
index a1c1aef..4a20af1 100644
--- a/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-compr-q6-v2.c
@@ -150,7 +150,7 @@
* check for underrun
*/
if (runtime->status->hw_ptr >= runtime->control->appl_ptr) {
- pr_err("render stopped");
+ pr_info("render stopped");
runtime->render_flag |= SNDRV_RENDER_STOPPED;
break;
}
@@ -519,12 +519,14 @@
}
}
atomic_set(&prtd->start, 0);
+ runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
atomic_set(&prtd->start, 0);
+ runtime->render_flag &= ~SNDRV_RENDER_STOPPED;
break;
default:
ret = -EINVAL;
@@ -745,7 +747,7 @@
int dir = -1;
prtd->mmap_flag = 1;
-
+ runtime->render_flag = SNDRV_NON_DMA_MODE;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
else