Merge "msm: mdss: Reveal finer error details for Assertive Display"
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/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 7ed873f..8c87eac 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -4,7 +4,10 @@
are compatable with MIPI display serial interface specification.
Required properties:
-- compatible: Must be "qcom,mdss-dsi-panel"
+- compatible: Specifies the version for DSI HW. that
+ this panel will be worked with
+ "qcom,mdss-dsi-panel" = DSI v6.0
+ "qcom,dsi-panel-v2" = DSI V2.0
- status: A string that has to be set to "okay/ok" to enable
the panel driver. By default this property will be
set to "disable". Will be set to "ok/okay" status
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/regulator/gdsc-regulator.txt b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
index d58fa90..37140b7 100644
--- a/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/gdsc-regulator.txt
@@ -12,9 +12,12 @@
Optional properties:
- parent-supply: phandle to the parent supply/regulator node
- qcom,clock-names: List of string names for core clocks
- - qcom,retain-mems: Presence denotes a hardware requirement to leave the
- forced memory retention signals in the core's clock
- branch control register asserted.
+ - qcom,retain-mem: Presence denotes a hardware requirement to leave the
+ forced core memory retention signals in the core's clock
+ branch control registers asserted.
+ - qcom,retain-periph: Presence denotes a hardware requirement to leave the
+ forced periph memory retention signal in the core's clock
+ branch control registers asserted.
- qcom,skip-logic-collapse: Presence denotes a requirement to leave power to
the core's logic enabled.
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/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 c74e59d..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";
@@ -136,6 +144,21 @@
#interrupt-cells = <3>;
};
+ i2c_0: i2c@f9925000 { /* BLSP1 QUP3 */
+ cell-index = <0>;
+ compatible = "qcom,i2c-qup";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0xf9925000 0x1000>;
+ interrupt-names = "qup_err_intr";
+ interrupts = <0 97 0>;
+ qcom,i2c-bus-freq = <100000>;
+ qcom,i2c-src-freq = <50000000>;
+ qcom,sda-gpio = <&msmgpio 10 0>;
+ qcom,scl-gpio = <&msmgpio 11 0>;
+ };
+
usb3: qcom,ssusb@f9200000 {
compatible = "qcom,dwc-usb3-msm";
reg = <0xf9200000 0xfc000>,
diff --git a/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
new file mode 100644
index 0000000..b9ed050
--- /dev/null
+++ b/arch/arm/boot/dts/dsi-v2-panel-hx8379a-wvga-video.dtsi
@@ -0,0 +1,117 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/ {
+ qcom,dsi_v2_hx8379a_wvga_video {
+ compatible = "qcom,dsi-panel-v2";
+ label = "HX8379A WVGA video mode dsi panel";
+ qcom,dsi-ctrl-phandle = <&mdss_dsi0>;
+ qcom,rst-gpio = <&msmgpio 41 0>;
+ vdda-supply = <&pm8110_l19>;
+ vddio-supply=<&pm8110_l14>;
+ qcom,mdss-pan-res = <480 800>;
+ qcom,mdss-pan-bpp = <24>;
+ qcom,mdss-pan-dest = "display_1";
+ qcom,mdss-pan-porch-values = <90 17 90 2 3 11>;
+ qcom,mdss-pan-underflow-clr = <0xff>;
+ qcom,mdss-pan-bl-levels = <1 255>;
+ qcom,mdss-pan-bl-ctrl = "bl_ctrl_wled";
+ qcom,mdss-pan-dsi-mode = <0>;
+ qcom,mdss-pan-dsi-h-pulse-mode = <1>;
+ qcom,mdss-pan-dsi-h-power-stop = <0 0 0>;
+ qcom,mdss-pan-dsi-bllp-power-stop = <1 1>;
+ qcom,mdss-pan-dsi-traffic-mode = <2>;
+ qcom,mdss-pan-dsi-dst-format = <3>;
+ qcom,mdss-pan-dsi-vc = <0>;
+ qcom,mdss-pan-dsi-rgb-swap = <0>;
+ qcom,mdss-pan-dsi-data-lanes = <1 1 0 0>;
+ qcom,mdss-pan-dsi-dlane-swap = <1>;
+ qcom,mdss-pan-dsi-t-clk = <0x1b 0x04>;
+ qcom,mdss-pan-dsi-stream = <0>;
+ qcom,mdss-pan-dsi-mdp-tr = <0x0>;/*todo*/
+ qcom,mdss-pan-dsi-dma-tr = <0x04>;
+ qcom,mdss-pan-dsi-frame-rate = <60>;
+ qcom,panel-phy-regulatorSettings =[09 08 05 00 20 03];
+ qcom,panel-phy-timingSettings = [5D 12 0C 00 33 39
+ 10 16 15 03 04 00];
+ qcom,panel-phy-strengthCtrl = [ff 06];
+ qcom,panel-phy-bistCtrl = [03 03 00 00 0f 00];
+ qcom,panel-phy-laneConfig =
+ [80 45 00 00 01 66 /*lane0**/
+ 80 45 00 00 01 66 /*lane1*/
+ 80 45 00 00 01 66 /*lane2*/
+ 80 45 00 00 01 66 /*lane3*/
+ 40 67 00 00 01 88]; /*Clk*/
+
+ qcom,on-cmds-dsi-state = "DSI_LP_MODE";
+ qcom,panel-on-cmds = [
+ 29 01 00 00 01 04
+ B9 FF 83 79
+ 23 01 00 00 01 02
+ BA 51
+ 29 01 00 00 01 14
+ B1 00 50 44
+ EA 8D 08 11
+ 0F 0F 24 2C
+ 9A 1A 42 0B
+ 6E F1 00 E6
+ 29 01 00 00 01 0e
+ B2 00 00 3C
+ 08 04 19 22
+ 00 FF 08 04
+ 19 20
+ 29 01 00 00 01 20
+ B4 80 08 00
+ 32 10 03 32
+ 13 70 32 10
+ 08 37 01 28
+ 05 37 08 3C
+ 20 44 44 08
+ 00 40 08 28
+ 08 30 30 04
+ 23 01 00 00 01 02
+ cc 02
+ 29 01 00 00 01 30
+ D5 00 00 08
+ 00 01 05 00
+ 03 00 88 88
+ 88 88 23 01
+ 67 45 02 13
+ 88 88 88 88
+ 88 88 88 88
+ 88 88 54 76
+ 10 32 31 20
+ 88 88 88 88
+ 88 88 00 00
+ 00 00 00 00
+ 29 01 00 00 01 24
+ E0 79 00 00
+ 02 1C 1F 33
+ 28 3E 07 0E
+ 0F 15 17 16
+ 16 13 19 00
+ 00 02 1C 1F
+ 33 28 3E 07
+ 0E 0F 15 17
+ 16 16 13 19
+ 29 01 00 00 01 05
+ B6 00 A6 00 A6
+ 05 01 00 00 96 02
+ 11 00
+ 05 01 00 00 78 02
+ 29 00
+ ];
+ qcom,panel-off-cmds = [05 01 00 00 32 02 28 00
+ 05 01 00 00 78 02 10 00];
+ qcom,off-cmds-dsi-state = "DSI_LP_MODE";
+ };
+};
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/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 deeb051..5f9365a 100644
--- a/arch/arm/boot/dts/msm8610-qrd.dts
+++ b/arch/arm/boot/dts/msm8610-qrd.dts
@@ -13,6 +13,7 @@
/dts-v1/;
/include/ "msm8610.dtsi"
+/include/ "dsi-v2-panel-hx8379a-wvga-video.dtsi"
/ {
model = "Qualcomm MSM 8610 QRD";
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 5ae8808..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 {
@@ -1633,6 +1635,7 @@
&gdsc_mdss {
qcom,clock-names = "core_clk", "lut_clk";
+ qcom,retain-periph;
status = "ok";
};
@@ -1649,7 +1652,8 @@
&gdsc_oxili_gx {
qcom,clock-names = "core_clk";
- qcom,retain-mems;
+ qcom,retain-mem;
+ qcom,retain-periph;
status = "ok";
};
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..d617c27 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -244,9 +244,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 +516,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/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..7420092 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
@@ -365,15 +360,6 @@
CONFIG_QPNP_POWER_ON=y
CONFIG_QPNP_VIBRATOR=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 +399,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..3798987 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
@@ -438,12 +433,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..fc34d53 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
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index d11773f..d3c8b77 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
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 154a368..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
@@ -373,6 +374,7 @@
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 2605234..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
@@ -379,6 +380,7 @@
CONFIG_HID_APPLE=y
CONFIG_HID_MAGICMOUSE=y
CONFIG_HID_MICROSOFT=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_SUSPEND=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=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/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/acpuclock-8226.c b/arch/arm/mach-msm/acpuclock-8226.c
index 733c7a8..0028d6e 100644
--- a/arch/arm/mach-msm/acpuclock-8226.c
+++ b/arch/arm/mach-msm/acpuclock-8226.c
@@ -87,7 +87,6 @@
static struct acpuclk_drv_data drv_data = {
.freq_tbl = acpu_freq_tbl_8226,
- .current_speed = &(struct clkctl_acpu_speed){ 0 },
.bus_scale = &bus_client_pdata,
.vdd_max_cpu = CPR_CORNER_TURBO,
.src_clocks = {
diff --git a/arch/arm/mach-msm/acpuclock-9625.c b/arch/arm/mach-msm/acpuclock-9625.c
index 42659f9..a4a5b2a 100644
--- a/arch/arm/mach-msm/acpuclock-9625.c
+++ b/arch/arm/mach-msm/acpuclock-9625.c
@@ -65,7 +65,6 @@
static struct acpuclk_drv_data drv_data = {
.freq_tbl = acpu_freq_tbl,
- .current_speed = &(struct clkctl_acpu_speed){ 0 },
.bus_scale = &bus_client_pdata,
.vdd_max_cpu = LVL_HIGH,
.vdd_max_mem = 1050000,
diff --git a/arch/arm/mach-msm/acpuclock-cortex.c b/arch/arm/mach-msm/acpuclock-cortex.c
index afa6909..2c3f97b 100644
--- a/arch/arm/mach-msm/acpuclock-cortex.c
+++ b/arch/arm/mach-msm/acpuclock-cortex.c
@@ -138,6 +138,49 @@
pr_warn("acpu rcg didn't update its configuration\n");
}
+static struct clkctl_acpu_speed *__init find_cur_cpu_level(void)
+{
+ struct clkctl_acpu_speed *f, *max = priv->freq_tbl;
+ void __iomem *apcs_rcg_config = priv->apcs_rcg_config;
+ struct acpuclk_reg_data *r = &priv->reg_data;
+ u32 regval, div, src;
+ unsigned long rate;
+ struct clk *parent;
+
+ regval = readl_relaxed(apcs_rcg_config);
+ src = regval & r->cfg_src_mask;
+ src >>= r->cfg_src_shift;
+
+ div = regval & r->cfg_div_mask;
+ div >>= r->cfg_div_shift;
+ /* No support for half-integer dividers */
+ div = div > 1 ? (div + 1) / 2 : 0;
+
+ for (f = priv->freq_tbl; f->khz; f++) {
+ if (f->use_for_scaling)
+ max = f;
+
+ if (f->src_sel != src || f->src_div != div)
+ continue;
+
+ parent = priv->src_clocks[f->src].clk;
+ rate = parent->rate / (div ? div : 1);
+ if (f->khz * 1000 == rate)
+ break;
+ }
+
+ if (f->khz)
+ return f;
+
+ pr_err("CPUs are running at an unknown rate. Defaulting to %u KHz.\n",
+ max->khz);
+
+ /* Change to a safe frequency */
+ select_clk_source_div(priv, priv->freq_tbl);
+ /* Default to largest frequency */
+ return max;
+}
+
static int set_speed_atomic(struct clkctl_acpu_speed *tgt_s)
{
struct clkctl_acpu_speed *strt_s = priv->current_speed;
@@ -231,7 +274,7 @@
strt_s = priv->current_speed;
/* Return early if rate didn't change */
- if (rate == strt_s->khz)
+ if (rate == strt_s->khz && reason != SETRATE_INIT)
goto out;
/* Find target frequency */
@@ -244,7 +287,7 @@
}
/* Increase VDD levels if needed */
- if ((reason == SETRATE_CPUFREQ || reason == SETRATE_INIT)
+ if ((reason == SETRATE_CPUFREQ)
&& (tgt_s->khz > strt_s->khz)) {
rc = increase_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
if (rc)
@@ -274,7 +317,7 @@
set_bus_bw(tgt_s->bw_level);
/* Drop VDD levels if we can. */
- if (tgt_s->khz < strt_s->khz)
+ if (tgt_s->khz < strt_s->khz || reason == SETRATE_INIT)
decrease_vdd(tgt_s->vdd_cpu, tgt_s->vdd_mem);
out:
@@ -328,8 +371,8 @@
int __init acpuclk_cortex_init(struct platform_device *pdev,
struct acpuclk_drv_data *data)
{
- unsigned long max_cpu_khz = 0;
- int i, rc;
+ int rc;
+ int parent;
priv = data;
mutex_init(&priv->lock);
@@ -343,46 +386,41 @@
BUG();
}
- /* Improve boot time by ramping up CPU immediately */
- for (i = 0; priv->freq_tbl[i].khz != 0; i++)
- if (priv->freq_tbl[i].use_for_scaling)
- max_cpu_khz = priv->freq_tbl[i].khz;
-
/* Initialize regulators */
rc = increase_vdd(priv->vdd_max_cpu, priv->vdd_max_mem);
if (rc)
- goto err_vdd;
+ return rc;
if (priv->vdd_mem) {
rc = regulator_enable(priv->vdd_mem);
if (rc) {
dev_err(&pdev->dev, "regulator_enable for mem failed\n");
- goto err_vdd;
+ return rc;
}
}
rc = regulator_enable(priv->vdd_cpu);
if (rc) {
dev_err(&pdev->dev, "regulator_enable for cpu failed\n");
- goto err_vdd_cpu;
+ return rc;
}
- /*
- * Select a state which is always a valid transition to align SW with
- * the HW configuration set by the bootloaders.
- */
- acpuclk_cortex_set_rate(0, acpuclk_cortex_data.power_collapse_khz,
- SETRATE_INIT);
- acpuclk_cortex_set_rate(0, max_cpu_khz, SETRATE_INIT);
+ priv->current_speed = find_cur_cpu_level();
+ parent = priv->current_speed->src;
+ rc = clk_prepare_enable(priv->src_clocks[parent].clk);
+ if (rc) {
+ dev_err(&pdev->dev, "handoff: prepare_enable failed\n");
+ return rc;
+ }
+
+ rc = acpuclk_cortex_set_rate(0, priv->current_speed->khz, SETRATE_INIT);
+ if (rc) {
+ dev_err(&pdev->dev, "handoff: set rate failed\n");
+ return rc;
+ }
acpuclk_register(&acpuclk_cortex_data);
cpufreq_table_init();
return 0;
-
-err_vdd_cpu:
- if (priv->vdd_mem)
- regulator_disable(priv->vdd_mem);
-err_vdd:
- return rc;
}
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-8084-gpiomux.c b/arch/arm/mach-msm/board-8084-gpiomux.c
index 8d5bb49..27f2e0d 100644
--- a/arch/arm/mach-msm/board-8084-gpiomux.c
+++ b/arch/arm/mach-msm/board-8084-gpiomux.c
@@ -17,6 +17,27 @@
#include <mach/board.h>
#include <mach/gpiomux.h>
+static struct gpiomux_setting gpio_i2c_config = {
+ .func = GPIOMUX_FUNC_3,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+static struct msm_gpiomux_config msm_blsp_configs[] __initdata = {
+ {
+ .gpio = 10, /* BLSP1 QUP3 I2C_SDA */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+ {
+ .gpio = 11, /* BLSP1 QUP3 I2C_SCL */
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &gpio_i2c_config,
+ },
+ },
+};
+
void __init apq8084_init_gpiomux(void)
{
int rc;
@@ -26,4 +47,6 @@
pr_err("%s failed %d\n", __func__, rc);
return;
}
+
+ msm_gpiomux_install(msm_blsp_configs, ARRAY_SIZE(msm_blsp_configs));
}
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-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 6491452..378edc8 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -485,7 +485,7 @@
msm_gpiomux_install(msm_auxpcm_configs,
ARRAY_SIZE(msm_auxpcm_configs));
- if (of_board_is_cdp() || of_board_is_mtp())
+ if (of_board_is_cdp() || of_board_is_mtp() || of_board_is_xpm())
msm_gpiomux_install(usb_otg_sw_configs,
ARRAY_SIZE(usb_otg_sw_configs));
}
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-8084.c b/arch/arm/mach-msm/clock-8084.c
index 1af026b..bec9f1b4 100644
--- a/arch/arm/mach-msm/clock-8084.c
+++ b/arch/arm/mach-msm/clock-8084.c
@@ -75,12 +75,13 @@
CLK_DUMMY("", usb_hsic_system_clk_src.c, "", OFF),
CLK_DUMMY("", gcc_bam_dma_ahb_clk.c, "", OFF),
CLK_DUMMY("", gcc_bam_dma_inactivity_timers_clk.c, "", OFF),
- CLK_DUMMY("", gcc_blsp1_ahb_clk.c, "", OFF),
+ CLK_DUMMY("iface_clk", gcc_blsp1_ahb_clk.c, "f9925000.i2c", OFF),
CLK_DUMMY("", gcc_blsp1_qup1_i2c_apps_clk.c, "", OFF),
CLK_DUMMY("", gcc_blsp1_qup1_spi_apps_clk.c, "", OFF),
CLK_DUMMY("", gcc_blsp1_qup2_i2c_apps_clk.c, "", OFF),
CLK_DUMMY("", gcc_blsp1_qup2_spi_apps_clk.c, "", OFF),
- CLK_DUMMY("", gcc_blsp1_qup3_i2c_apps_clk.c, "", OFF),
+ CLK_DUMMY("core_clk", gcc_blsp1_qup3_i2c_apps_clk.c, "f9925000.i2c",
+ OFF),
CLK_DUMMY("", gcc_blsp1_qup3_spi_apps_clk.c, "", OFF),
CLK_DUMMY("", gcc_blsp1_qup4_i2c_apps_clk.c, "", OFF),
CLK_DUMMY("", gcc_blsp1_qup4_spi_apps_clk.c, "", OFF),
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 1477541..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),
},
@@ -2846,11 +2846,6 @@
},
.num_fmax = VDD_SR2_PLL_NUM,
CLK_INIT(a7sspll.c),
- /*
- * Need to skip handoff of the acpu pll to avoid
- * turning off the pll when the cpu is using it
- */
- .flags = CLKFLAG_SKIP_HANDOFF,
},
};
@@ -2873,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);
@@ -3241,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 e34b539..58c5745 100644
--- a/arch/arm/mach-msm/clock-8610.c
+++ b/arch/arm/mach-msm/clock-8610.c
@@ -577,11 +577,6 @@
},
.num_fmax = VDD_SR2_PLL_NUM,
CLK_INIT(a7sspll.c),
- /*
- * Need to skip handoff of the acpu pll to avoid
- * turning off the pll when the cpu is using it
- */
- .flags = CLKFLAG_SKIP_HANDOFF,
},
};
@@ -1833,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,
};
@@ -3002,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 3277d75..facd6ba 100644
--- a/arch/arm/mach-msm/clock-9625.c
+++ b/arch/arm/mach-msm/clock-9625.c
@@ -390,10 +390,6 @@
PLL_F_END
};
-/*
- * Need to skip handoff of the acpu pll to avoid handoff code
- * to turn off the pll when the acpu is running off this pll.
- */
static struct pll_clk apcspll_clk_src = {
.mode_reg = (void __iomem *)APCS_CPU_PLL_MODE_REG,
.l_reg = (void __iomem *)APCS_CPU_PLL_L_REG,
@@ -415,7 +411,6 @@
.dbg_name = "apcspll_clk_src",
.ops = &clk_ops_local_pll,
CLK_INIT(apcspll_clk_src.c),
- .flags = CLKFLAG_SKIP_HANDOFF,
},
};
@@ -1579,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/clock-pll.c b/arch/arm/mach-msm/clock-pll.c
index fcdcb29..908107e 100644
--- a/arch/arm/mach-msm/clock-pll.c
+++ b/arch/arm/mach-msm/clock-pll.c
@@ -294,13 +294,7 @@
{
struct pll_freq_tbl *nf;
struct pll_clk *pll = to_pll_clk(c);
- u32 mode;
-
- mode = readl_relaxed(PLL_MODE_REG(pll));
-
- /* Don't change PLL's rate if it is enabled */
- if ((mode & PLL_MODE_MASK) == PLL_MODE_MASK)
- return -EBUSY;
+ unsigned long flags;
for (nf = pll->freq_tbl; nf->freq_hz != PLL_FREQ_END
&& nf->freq_hz != rate; nf++)
@@ -309,12 +303,24 @@
if (nf->freq_hz == PLL_FREQ_END)
return -EINVAL;
+ /*
+ * Ensure PLL is off before changing rate. For optimization reasons,
+ * assume no downstream clock is using actively using it.
+ */
+ spin_lock_irqsave(&c->lock, flags);
+ if (c->count)
+ c->ops->disable(c);
+
writel_relaxed(nf->l_val, PLL_L_REG(pll));
writel_relaxed(nf->m_val, PLL_M_REG(pll));
writel_relaxed(nf->n_val, PLL_N_REG(pll));
__pll_config_reg(PLL_CONFIG_REG(pll), nf, &pll->masks);
+ if (c->count)
+ c->ops->enable(c);
+
+ spin_unlock_irqrestore(&c->lock, flags);
return 0;
}
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/gdsc.c b/arch/arm/mach-msm/gdsc.c
index 0963e27..774548c 100644
--- a/arch/arm/mach-msm/gdsc.c
+++ b/arch/arm/mach-msm/gdsc.c
@@ -47,7 +47,8 @@
void __iomem *gdscr;
struct clk **clocks;
int clock_count;
- bool toggle_mems;
+ bool toggle_mem;
+ bool toggle_periph;
bool toggle_logic;
bool resets_asserted;
};
@@ -86,11 +87,11 @@
sc->resets_asserted = false;
}
- if (sc->toggle_mems) {
- for (i = 0; i < sc->clock_count; i++) {
+ for (i = 0; i < sc->clock_count; i++) {
+ if (sc->toggle_mem)
clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
+ if (sc->toggle_periph)
clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
- }
}
/*
@@ -127,11 +128,11 @@
sc->resets_asserted = true;
}
- if (sc->toggle_mems) {
- for (i = 0; i < sc->clock_count; i++) {
+ for (i = 0; i < sc->clock_count; i++) {
+ if (sc->toggle_mem)
clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+ if (sc->toggle_periph)
clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
- }
}
return ret;
@@ -150,7 +151,7 @@
struct resource *res;
struct gdsc *sc;
uint32_t regval;
- bool retain_mems;
+ bool retain_mem, retain_periph;
int i, ret;
sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
@@ -222,18 +223,23 @@
regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
writel_relaxed(regval, sc->gdscr);
- retain_mems = of_property_read_bool(pdev->dev.of_node,
- "qcom,retain-mems");
+ retain_mem = of_property_read_bool(pdev->dev.of_node,
+ "qcom,retain-mem");
+ retain_periph = of_property_read_bool(pdev->dev.of_node,
+ "qcom,retain-periph");
for (i = 0; i < sc->clock_count; i++) {
- if (retain_mems || (regval & PWR_ON_MASK)) {
+ if (retain_mem || (regval & PWR_ON_MASK))
clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
- clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
- } else {
+ else
clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);
+
+ if (retain_periph || (regval & PWR_ON_MASK))
+ clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
+ else
clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
- }
}
- sc->toggle_mems = !retain_mems;
+ sc->toggle_mem = !retain_mem;
+ sc->toggle_periph = !retain_periph;
sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
"qcom,skip-logic-collapse");
if (!sc->toggle_logic) {
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/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index bc76f56..a3e993d 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -298,7 +298,7 @@
* Resets the USB BAM that has A2 pipes
*
*/
-int usb_bam_a2_reset(void);
+int usb_bam_a2_reset(bool to_reconnect);
/**
* Indicates if the client of the USB BAM is ready to start
@@ -308,6 +308,14 @@
*
*/
int usb_bam_client_ready(bool ready);
+
+/**
+* Returns upon reset completion if reset is in progress
+* immediately otherwise.
+*
+*/
+void usb_bam_reset_complete(void);
+
/**
* Returns qdss index from the connections array.
*
@@ -403,7 +411,7 @@
return -ENODEV;
}
-static inline int usb_bam_a2_reset(void)
+static inline int usb_bam_a2_reset(bool to_reconnect)
{
return -ENODEV;
}
@@ -413,6 +421,11 @@
return -ENODEV;
}
+static inline void usb_bam_reset_complete(void)
+{
+ return;
+}
+
static inline int usb_bam_get_qdss_idx(u8 num)
{
return -ENODEV;
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/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/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index 4a9a97a..f39334a 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -441,7 +441,7 @@
if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
!drvdata->reset_flush_race) {
coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
- coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
+ coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
drvdata->usbch = usb_qdss_open("qdss", drvdata,
usb_notifier);
@@ -676,7 +676,7 @@
} else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
if (drvdata->out_mode == TMC_ETR_OUT_MODE_MEM &&
!drvdata->reset_flush_race) {
- coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
+ coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
} else if (drvdata->out_mode == TMC_ETR_OUT_MODE_USB) {
tmc_etr_bam_disable(drvdata);
@@ -996,7 +996,7 @@
if (!drvdata->reset_flush_race) {
coresight_cti_map_trigout(drvdata->cti_flush, 3, 0);
- coresight_cti_map_trigin(drvdata->cti_reset, 0, 0);
+ coresight_cti_map_trigin(drvdata->cti_reset, 2, 0);
}
tmc_etr_bam_disable(drvdata);
@@ -1020,7 +1020,7 @@
spin_unlock_irqrestore(&drvdata->spinlock, flags);
if (!drvdata->reset_flush_race) {
- coresight_cti_unmap_trigin(drvdata->cti_reset, 0, 0);
+ coresight_cti_unmap_trigin(drvdata->cti_reset, 2, 0);
coresight_cti_unmap_trigout(drvdata->cti_flush, 3, 0);
}
diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c
index 459a79c..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.
@@ -166,6 +164,15 @@
/* version of pfp microcode that supports sync_lock
between CPU and GPU for IOMMU-v0 programming */
unsigned int sync_lock_pfp_ver;
+ /* PM4 jump table index */
+ unsigned int pm4_jt_idx;
+ /* PM4 jump table load addr */
+ unsigned int pm4_jt_addr;
+ /* PFP jump table index */
+ unsigned int pfp_jt_idx;
+ /* PFP jump table load addr */
+ unsigned int pfp_jt_addr;
+
} adreno_gpulist[] = {
{ ADRENO_REV_A200, 0, 2, ANY_ID, ANY_ID,
"yamato_pm4.fw", "yamato_pfp.fw", &adreno_a2xx_gpudev,
@@ -202,10 +209,11 @@
512, 0, 2, SZ_512K, 0x3FF037, 0x3FF016 },
{ ADRENO_REV_A330, 3, 3, 0, ANY_ID,
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
- 512, 0, 2, SZ_1M, NO_VER, NO_VER },
+ 512, 0, 2, SZ_1M, NO_VER, NO_VER, 0x8AD, 0x2E4, 0x201, 0x200 },
{ ADRENO_REV_A305B, 3, 0, 5, 0x10,
"a330_pm4.fw", "a330_pfp.fw", &adreno_a3xx_gpudev,
- 512, 0, 2, SZ_128K, NO_VER, NO_VER },
+ 512, 0, 2, SZ_128K, NO_VER, NO_VER, 0x8AD, 0x2E4,
+ 0x201, 0x200 },
{ ADRENO_REV_A305C, 3, 0, 5, 0x20,
"a300_pm4.fw", "a300_pfp.fw", &adreno_a3xx_gpudev,
512, 0, 2, SZ_128K, 0x3FF037, 0x3FF016 },
@@ -534,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;
}
@@ -1118,6 +1128,10 @@
adreno_dev->pix_shader_start = adreno_gpulist[i].pix_shader_start;
adreno_dev->instruction_size = adreno_gpulist[i].instruction_size;
adreno_dev->gmem_size = adreno_gpulist[i].gmem_size;
+ adreno_dev->pm4_jt_idx = adreno_gpulist[i].pm4_jt_idx;
+ adreno_dev->pm4_jt_addr = adreno_gpulist[i].pm4_jt_addr;
+ adreno_dev->pfp_jt_idx = adreno_gpulist[i].pfp_jt_idx;
+ adreno_dev->pfp_jt_addr = adreno_gpulist[i].pfp_jt_addr;
adreno_dev->gpulist_index = i;
}
@@ -1785,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++;
@@ -1820,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);
@@ -2175,10 +2193,70 @@
}
}
+/**
+ * adreno_soft_reset() - Do a soft reset of the GPU hardware
+ * @device: KGSL device to soft reset
+ *
+ * "soft reset" the GPU hardware - this is a fast path GPU reset
+ * The GPU hardware is reset but we never pull power so we can skip
+ * a lot of the standard adreno_stop/adreno_start sequence
+ */
+int adreno_soft_reset(struct kgsl_device *device)
+{
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+ int ret;
+
+ /* If the jump table index is 0 soft reset is not supported */
+ if ((!adreno_dev->pm4_jt_idx) || (!adreno_dev->gpudev->soft_reset)) {
+ dev_WARN_ONCE(device->dev, 1, "Soft reset not supported");
+ return -EINVAL;
+ }
+
+ adreno_dev->drawctxt_active = NULL;
+
+ /* Stop the ringbuffer */
+ adreno_ringbuffer_stop(&adreno_dev->ringbuffer);
+
+ /* Delete the idle timer */
+ del_timer_sync(&device->idle_timer);
+
+ /* Make sure we are totally awake */
+ kgsl_pwrctrl_enable(device);
+
+ /* Reset the GPU */
+ adreno_dev->gpudev->soft_reset(adreno_dev);
+
+ /* Reinitialize the GPU */
+ adreno_dev->gpudev->start(adreno_dev);
+
+ /* Enable IRQ */
+ kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
+ device->ftbl->irqctrl(device, 1);
+
+ /*
+ * Restart the ringbuffer - we can go down the warm start path because
+ * power was never yanked
+ */
+ ret = adreno_ringbuffer_warm_start(&adreno_dev->ringbuffer);
+ if (ret)
+ return ret;
+
+ device->reset_counter++;
+
+ return 0;
+}
+
static int
_adreno_ft_restart_device(struct kgsl_device *device,
struct kgsl_context *context)
{
+ /* If device soft reset fails try hard reset */
+ if (adreno_soft_reset(device))
+ KGSL_DEV_ERR_ONCE(device, "Device soft reset failed\n");
+ else
+ /* Soft reset is successful */
+ goto reset_done;
+
/* restart device */
if (adreno_stop(device)) {
KGSL_FT_ERR(device, "Device stop failed\n");
@@ -2195,6 +2273,7 @@
return 1;
}
+reset_done:
if (context) {
struct adreno_context *adreno_context = context->devctxt;
kgsl_mmu_setstate(&device->mmu, adreno_context->pagetable,
@@ -2301,6 +2380,7 @@
struct adreno_context *last_active_ctx = adreno_dev->drawctxt_active;
unsigned int long_ib = 0;
static int no_context_ft;
+ struct kgsl_mmu *mmu = &device->mmu;
context = idr_find(&device->context_idr, ft_data->context_id);
if (context == NULL) {
@@ -2374,12 +2454,13 @@
/* Do not try the reply if hang is due to a pagefault */
if (adreno_context && adreno_context->pagefault) {
+ /* Resume MMU */
+ mmu->mmu_ops->mmu_pagefault_resume(mmu);
if ((ft_data->context_id == adreno_context->id) &&
(ft_data->global_eop == adreno_context->pagefault_ts)) {
ft_data->ft_policy &= ~KGSL_FT_REPLAY;
KGSL_FT_ERR(device, "MMU fault skipping replay\n");
}
-
adreno_context->pagefault = 0;
}
@@ -2637,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);
}
@@ -2828,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));
@@ -3223,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;
@@ -3243,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
@@ -3275,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],
@@ -3310,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;
@@ -3386,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)
{
@@ -3483,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;
@@ -3511,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
@@ -3541,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 816940f..531a77c 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -110,6 +110,10 @@
unsigned int mharb;
struct adreno_gpudev *gpudev;
unsigned int wait_timeout;
+ unsigned int pm4_jt_idx;
+ unsigned int pm4_jt_addr;
+ unsigned int pfp_jt_idx;
+ unsigned int pfp_jt_addr;
unsigned int istore_size;
unsigned int pix_shader_start;
unsigned int instruction_size;
@@ -200,6 +204,7 @@
void (*coresight_disable) (struct kgsl_device *device);
void (*coresight_config_debug_reg) (struct kgsl_device *device,
int debug_reg, unsigned int val);
+ void (*soft_reset)(struct adreno_device *device);
};
/*
@@ -242,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)
@@ -280,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);
@@ -330,6 +336,9 @@
int adreno_perfcounter_put(struct adreno_device *adreno_dev,
unsigned int groupid, unsigned int countable);
+int adreno_soft_reset(struct kgsl_device *device);
+
+
static inline int adreno_is_a200(struct adreno_device *adreno_dev)
{
return (adreno_dev->gpurev == ADRENO_REV_A200);
diff --git a/drivers/gpu/msm/adreno_a3xx.c b/drivers/gpu/msm/adreno_a3xx.c
index 884b72b..29855f7 100644
--- a/drivers/gpu/msm/adreno_a3xx.c
+++ b/drivers/gpu/msm/adreno_a3xx.c
@@ -3461,6 +3461,30 @@
ARRAY_SIZE(a3xx_perfcounter_groups),
};
+/*
+ * a3xx_soft_reset() - Soft reset GPU
+ * @adreno_dev: Pointer to adreno device
+ *
+ * Soft reset the GPU by doing a AHB write of value 1 to RBBM_SW_RESET
+ * register. This is used when we want to reset the GPU without
+ * turning off GFX power rail. The reset when asserted resets
+ * all the HW logic, restores GPU registers to default state and
+ * flushes out pending VBIF transactions.
+ */
+static void a3xx_soft_reset(struct adreno_device *adreno_dev)
+{
+ struct kgsl_device *device = &adreno_dev->dev;
+ unsigned int reg;
+
+ adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 1);
+ /*
+ * Do a dummy read to get a brief read cycle delay for the reset to take
+ * effect
+ */
+ adreno_regread(device, A3XX_RBBM_SW_RESET_CMD, ®);
+ adreno_regwrite(device, A3XX_RBBM_SW_RESET_CMD, 0);
+}
+
/* Defined in adreno_a3xx_snapshot.c */
void *a3xx_snapshot(struct adreno_device *adreno_dev, void *snapshot,
int *remain, int hang);
@@ -3488,4 +3512,5 @@
.coresight_enable = a3xx_coresight_enable,
.coresight_disable = a3xx_coresight_disable,
.coresight_config_debug_reg = a3xx_coresight_config_debug_reg,
+ .soft_reset = a3xx_soft_reset,
};
diff --git a/drivers/gpu/msm/adreno_ringbuffer.c b/drivers/gpu/msm/adreno_ringbuffer.c
index 4e95e93..70223db 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.c
+++ b/drivers/gpu/msm/adreno_ringbuffer.c
@@ -14,6 +14,8 @@
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/log2.h>
+#include <linux/time.h>
+#include <linux/delay.h>
#include "kgsl.h"
#include "kgsl_sharedmem.h"
@@ -64,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));
@@ -242,8 +244,16 @@
return ret;
}
-
-int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device)
+/**
+ * adreno_ringbuffer_load_pm4_ucode() - Load pm4 ucode
+ * @device: Pointer to a KGSL device
+ * @start: Starting index in pm4 ucode to load
+ * @addr: Address to load the pm4 ucode
+ *
+ * Load the pm4 ucode from @start at @addr.
+ */
+int adreno_ringbuffer_load_pm4_ucode(struct kgsl_device *device,
+ unsigned int start, unsigned int addr)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
@@ -258,8 +268,8 @@
adreno_dev->pm4_fw_version);
adreno_regwrite(device, REG_CP_DEBUG, CP_DEBUG_DEFAULT);
- adreno_regwrite(device, REG_CP_ME_RAM_WADDR, 0);
- for (i = 1; i < adreno_dev->pm4_fw_size; i++)
+ adreno_regwrite(device, REG_CP_ME_RAM_WADDR, addr);
+ for (i = start; i < adreno_dev->pm4_fw_size; i++)
adreno_regwrite(device, REG_CP_ME_RAM_DATA,
adreno_dev->pm4_fw[i]);
@@ -297,7 +307,16 @@
return ret;
}
-int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device)
+/**
+ * adreno_ringbuffer_load_pfp_ucode() - Load pfp ucode
+ * @device: Pointer to a KGSL device
+ * @start: Starting index in pfp ucode to load
+ * @addr: Address to load the pfp ucode
+ *
+ * Load the pfp ucode from @start at @addr.
+ */
+int adreno_ringbuffer_load_pfp_ucode(struct kgsl_device *device,
+ unsigned int start, unsigned int addr)
{
struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
int i;
@@ -311,8 +330,9 @@
KGSL_DRV_INFO(device, "loading pfp ucode version: %d\n",
adreno_dev->pfp_fw_version);
- adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr, 0);
- for (i = 1; i < adreno_dev->pfp_fw_size; i++)
+ adreno_regwrite(device, adreno_dev->gpudev->reg_cp_pfp_ucode_addr,
+ addr);
+ for (i = start; i < adreno_dev->pfp_fw_size; i++)
adreno_regwrite(device,
adreno_dev->gpudev->reg_cp_pfp_ucode_data,
adreno_dev->pfp_fw[i]);
@@ -320,7 +340,13 @@
return 0;
}
-int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
+/**
+ * _ringbuffer_start_common() - Ringbuffer start
+ * @rb: Pointer to adreno ringbuffer
+ *
+ * Setup ringbuffer for GPU.
+ */
+int _ringbuffer_start_common(struct adreno_ringbuffer *rb)
{
int status;
/*cp_rb_cntl_u cp_rb_cntl; */
@@ -420,16 +446,6 @@
adreno_regwrite(device, REG_SCRATCH_UMSK,
GSL_RB_MEMPTRS_SCRATCH_MASK);
- /* load the CP ucode */
- status = adreno_ringbuffer_load_pm4_ucode(device);
- if (status != 0)
- return status;
-
- /* load the prefetch parser ucode */
- status = adreno_ringbuffer_load_pfp_ucode(device);
- if (status != 0)
- return status;
-
/* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
if (adreno_is_a305(adreno_dev) || adreno_is_a305c(adreno_dev) ||
adreno_is_a320(adreno_dev))
@@ -457,6 +473,54 @@
return status;
}
+/**
+ * adreno_ringbuffer_warm_start() - Ringbuffer warm start
+ * @rb: Pointer to adreno ringbuffer
+ *
+ * Start the ringbuffer but load only jump tables part of the
+ * microcode.
+ */
+int adreno_ringbuffer_warm_start(struct adreno_ringbuffer *rb)
+{
+ int status;
+ struct kgsl_device *device = rb->device;
+ struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
+
+ /* load the CP ucode */
+ status = adreno_ringbuffer_load_pm4_ucode(device,
+ adreno_dev->pm4_jt_idx, adreno_dev->pm4_jt_addr);
+ if (status != 0)
+ return status;
+
+ /* load the prefetch parser ucode */
+ status = adreno_ringbuffer_load_pfp_ucode(device,
+ adreno_dev->pfp_jt_idx, adreno_dev->pfp_jt_addr);
+ if (status != 0)
+ return status;
+
+ return _ringbuffer_start_common(rb);
+}
+
+int adreno_ringbuffer_start(struct adreno_ringbuffer *rb)
+{
+ int status;
+
+ if (rb->flags & KGSL_FLAGS_STARTED)
+ return 0;
+
+ /* load the CP ucode */
+ status = adreno_ringbuffer_load_pm4_ucode(rb->device, 1, 0);
+ if (status != 0)
+ return status;
+
+ /* load the prefetch parser ucode */
+ status = adreno_ringbuffer_load_pfp_ucode(rb->device, 1, 0);
+ if (status != 0)
+ return status;
+
+ return _ringbuffer_start_common(rb);
+}
+
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb)
{
struct kgsl_device *device = rb->device;
diff --git a/drivers/gpu/msm/adreno_ringbuffer.h b/drivers/gpu/msm/adreno_ringbuffer.h
index 115533e..f59b834 100644
--- a/drivers/gpu/msm/adreno_ringbuffer.h
+++ b/drivers/gpu/msm/adreno_ringbuffer.h
@@ -97,6 +97,8 @@
int adreno_ringbuffer_init(struct kgsl_device *device);
+int adreno_ringbuffer_warm_start(struct adreno_ringbuffer *rb);
+
int adreno_ringbuffer_start(struct adreno_ringbuffer *rb);
void adreno_ringbuffer_stop(struct adreno_ringbuffer *rb);
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_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index eb85900..0bacc5e 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1735,10 +1735,36 @@
return ret;
}
-static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
+void kgsl_iommu_pagefault_resume(struct kgsl_mmu *mmu)
{
struct kgsl_iommu *iommu = mmu->priv;
int i, j;
+
+ if (mmu->fault) {
+ for (i = 0; i < iommu->unit_count; i++) {
+ struct kgsl_iommu_unit *iommu_unit =
+ &iommu->iommu_units[i];
+ for (j = 0; j < iommu_unit->dev_count; j++) {
+ if (iommu_unit->dev[j].fault) {
+ kgsl_iommu_enable_clk(mmu, j);
+ _iommu_lock();
+ KGSL_IOMMU_SET_CTX_REG(iommu,
+ iommu_unit,
+ iommu_unit->dev[j].ctx_id,
+ RESUME, 1);
+ _iommu_unlock();
+ iommu_unit->dev[j].fault = 0;
+ }
+ }
+ }
+ mmu->fault = 0;
+ }
+}
+
+
+static void kgsl_iommu_stop(struct kgsl_mmu *mmu)
+{
+ struct kgsl_iommu *iommu = mmu->priv;
/*
* stop device mmu
*
@@ -1751,25 +1777,7 @@
mmu->flags &= ~KGSL_FLAGS_STARTED;
- if (mmu->fault) {
- for (i = 0; i < iommu->unit_count; i++) {
- struct kgsl_iommu_unit *iommu_unit =
- &iommu->iommu_units[i];
- for (j = 0; j < iommu_unit->dev_count; j++) {
- if (iommu_unit->dev[j].fault) {
- kgsl_iommu_enable_clk(mmu, j);
- _iommu_lock();
- KGSL_IOMMU_SET_CTX_REG(iommu,
- iommu_unit,
- iommu_unit->dev[j].ctx_id,
- RESUME, 1);
- _iommu_unlock();
- iommu_unit->dev[j].fault = 0;
- }
- }
- }
- mmu->fault = 0;
- }
+ kgsl_iommu_pagefault_resume(mmu);
}
/* switch off MMU clocks and cancel any events it has queued */
iommu->clk_event_queued = false;
@@ -1987,6 +1995,7 @@
.mmu_setstate = kgsl_iommu_setstate,
.mmu_device_setstate = kgsl_iommu_default_setstate,
.mmu_pagefault = NULL,
+ .mmu_pagefault_resume = kgsl_iommu_pagefault_resume,
.mmu_get_current_ptbase = kgsl_iommu_get_current_ptbase,
.mmu_enable_clk = kgsl_iommu_enable_clk,
.mmu_disable_clk_on_ts = kgsl_iommu_disable_clk_on_ts,
diff --git a/drivers/gpu/msm/kgsl_mmu.h b/drivers/gpu/msm/kgsl_mmu.h
index a4fffec..27cfc40 100644
--- a/drivers/gpu/msm/kgsl_mmu.h
+++ b/drivers/gpu/msm/kgsl_mmu.h
@@ -141,6 +141,8 @@
void (*mmu_pagefault) (struct kgsl_mmu *mmu);
phys_addr_t (*mmu_get_current_ptbase)
(struct kgsl_mmu *mmu);
+ void (*mmu_pagefault_resume)
+ (struct kgsl_mmu *mmu);
void (*mmu_disable_clk_on_ts)
(struct kgsl_mmu *mmu, uint32_t ts, bool ts_valid);
int (*mmu_enable_clk)
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_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
index ff9c9b8..2c5e136 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c
@@ -38,6 +38,10 @@
.compatible = "qcom,vfe40",
.data = &vfe40_hw_info,
},
+ {
+ .compatible = "qcom,vfe32",
+ .data = &vfe32_hw_info,
+ },
{}
};
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
index cf03c7f..f1f4c17 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h
@@ -419,6 +419,7 @@
struct msm_vfe_error_info error_info;
struct msm_isp_buf_mgr *buf_mgr;
int dump_reg;
+ int vfe_clk_idx;
uint32_t vfe_open_cnt;
};
diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
index 73b4f4d..4c5f258 100644
--- a/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
+++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp32.c
@@ -22,7 +22,7 @@
#include "msm.h"
#include "msm_camera_io_util.h"
-#define VFE32_BURST_LEN 3
+#define VFE32_BURST_LEN 1
#define VFE32_UB_SIZE 1024
#define VFE32_EQUAL_SLICE_UB 204
#define VFE32_WM_BASE(idx) (0x4C + 0x18 * idx)
@@ -40,7 +40,17 @@
(~(ping_pong >> (idx + VFE32_STATS_PING_PONG_OFFSET)) & 0x1))
#define VFE32_CLK_IDX 0
-static struct msm_cam_clk_info msm_vfe32_clk_info[] = {
+static struct msm_cam_clk_info msm_vfe32_1_clk_info[] = {
+ /*vfe32 clock info for B-family: 8610 */
+ {"vfe_clk_src", 266670000},
+ {"vfe_clk", -1},
+ {"vfe_ahb_clk", -1},
+ {"csi_vfe_clk", -1},
+ {"bus_clk", -1},
+};
+
+static struct msm_cam_clk_info msm_vfe32_2_clk_info[] = {
+ /*vfe32 clock info for A-family: 8960 */
{"vfe_clk", 266667000},
{"vfe_pclk", -1},
{"csi_vfe_clk", -1},
@@ -49,6 +59,7 @@
static int msm_vfe32_init_hardware(struct vfe_device *vfe_dev)
{
int rc = -1;
+ vfe_dev->vfe_clk_idx = 0;
rc = msm_isp_init_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
if (rc < 0) {
pr_err("%s: Bandwidth registration Failed!\n", __func__);
@@ -63,10 +74,18 @@
}
}
- rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
- vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 1);
- if (rc < 0)
- goto clk_enable_failed;
+ rc = msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_1_clk_info,
+ vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_1_clk_info), 1);
+ if (rc < 0) {
+ rc = msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_2_clk_info), 1);
+ if (rc < 0)
+ goto clk_enable_failed;
+ else
+ vfe_dev->vfe_clk_idx = 2;
+ } else
+ vfe_dev->vfe_clk_idx = 1;
vfe_dev->vfe_base = ioremap(vfe_dev->vfe_mem->start,
resource_size(vfe_dev->vfe_mem));
@@ -87,8 +106,14 @@
irq_req_failed:
iounmap(vfe_dev->vfe_base);
vfe_remap_failed:
- msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
- vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
+ if (vfe_dev->vfe_clk_idx == 1)
+ msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_1_clk_info), 0);
+ if (vfe_dev->vfe_clk_idx == 2)
+ msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
clk_enable_failed:
regulator_disable(vfe_dev->fs_vfe);
fs_failed:
@@ -102,8 +127,14 @@
free_irq(vfe_dev->vfe_irq->start, vfe_dev);
tasklet_kill(&vfe_dev->vfe_tasklet);
iounmap(vfe_dev->vfe_base);
- msm_cam_clk_enable(&vfe_dev->pdev->dev, msm_vfe32_clk_info,
- vfe_dev->vfe_clk, ARRAY_SIZE(msm_vfe32_clk_info), 0);
+ if (vfe_dev->vfe_clk_idx == 1)
+ msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_1_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_1_clk_info), 0);
+ if (vfe_dev->vfe_clk_idx == 2)
+ msm_cam_clk_enable(&vfe_dev->pdev->dev,
+ msm_vfe32_2_clk_info, vfe_dev->vfe_clk,
+ ARRAY_SIZE(msm_vfe32_2_clk_info), 0);
regulator_disable(vfe_dev->fs_vfe);
msm_isp_deinit_bandwidth_mgr(ISP_VFE0 + vfe_dev->pdev->id);
}
@@ -330,7 +361,18 @@
static void msm_vfe32_axi_reload_wm(
struct vfe_device *vfe_dev, uint32_t reload_mask)
{
- msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
+ if (!vfe_dev->pdev->dev.of_node) {
+ /*vfe32 A-family: 8960*/
+ msm_camera_io_w_mb(reload_mask, vfe_dev->vfe_base + 0x38);
+ } else {
+ /*vfe32 B-family: 8610*/
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x24);
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x28);
+ msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x20);
+ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x18);
+ msm_camera_io_w(0x9AAAAAAA , vfe_dev->vfe_base + 0x600);
+ msm_camera_io_w(reload_mask, vfe_dev->vfe_base + 0x38);
+ }
}
static void msm_vfe32_axi_enable_wm(struct vfe_device *vfe_dev,
@@ -914,14 +956,22 @@
goto vfe_no_resource;
}
- vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
+ if (!vfe_dev->pdev->dev.of_node)
+ vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe_imgwr");
+ else
+ vfe_dev->iommu_ctx[0] = msm_iommu_get_ctx("vfe0");
+
if (!vfe_dev->iommu_ctx[0]) {
pr_err("%s: no iommux ctx resource?\n", __func__);
rc = -ENODEV;
goto vfe_no_resource;
}
- vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
+ if (!vfe_dev->pdev->dev.of_node)
+ vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe_misc");
+ else
+ vfe_dev->iommu_ctx[1] = msm_iommu_get_ctx("vfe0");
+
if (!vfe_dev->iommu_ctx[1]) {
pr_err("%s: no iommux ctx resource?\n", __func__);
rc = -ENODEV;
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/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c
index 29ae7b4..7547464 100644
--- a/drivers/media/platform/msm/vidc/msm_vdec.c
+++ b/drivers/media/platform/msm/vidc/msm_vdec.c
@@ -1251,11 +1251,9 @@
static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
- struct v4l2_control control;
struct hal_nal_stream_format_supported stream_format;
struct hal_enable_picture enable_picture;
struct hal_enable hal_property;/*, prop;*/
- u32 control_idx = 0;
enum hal_property property_id = 0;
u32 property_val = 0;
void *pdata = NULL;
@@ -1357,10 +1355,8 @@
if (!rc && property_id) {
dprintk(VIDC_DBG,
- "Control: HAL property=%d,ctrl_id=%d,ctrl_value=%d\n",
- property_id,
- msm_vdec_ctrls[control_idx].id,
- control.value);
+ "Control: HAL property = %d, ctrl_id = 0x%x, ctrl_value = %d\n",
+ property_id, ctrl->id, ctrl->val);
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, property_id, pdata);
}
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index e5619ea..7fc2595 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -21,7 +21,7 @@
#define MSM_VENC_DVC_NAME "msm_venc_8974"
#define MIN_NUM_OUTPUT_BUFFERS 4
#define MIN_NUM_CAPTURE_BUFFERS 4
-#define MIN_BIT_RATE 64000
+#define MIN_BIT_RATE 32000
#define MAX_BIT_RATE 160000000
#define DEFAULT_BIT_RATE 64000
#define BIT_RATE_STEP 100
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
index ae1e9b7..bea9070 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c
@@ -15,7 +15,8 @@
#include "vidc_hfi_api.h"
#define MAX_DBG_BUF_SIZE 4096
-int msm_vidc_debug = 0x3;
+int msm_vidc_debug = VIDC_ERR | VIDC_WARN;
+int msm_vidc_debug_out = VIDC_OUT_PRINTK;
int msm_fw_debug = 0x18;
int msm_fw_debug_mode = 0x1;
int msm_fw_low_power_mode = 0x1;
@@ -171,6 +172,11 @@
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
+ if (!debugfs_create_u32("debug_output", S_IRUGO | S_IWUSR,
+ parent, &msm_vidc_debug_out)) {
+ dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
+ goto failed_create_dir;
+ }
failed_create_dir:
return dir;
}
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
index ea6dd70..5b572c9 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_debug.h
+++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h
@@ -31,9 +31,15 @@
VIDC_INFO = 0x0004,
VIDC_DBG = 0x0008,
VIDC_PROF = 0x0010,
+ VIDC_PKT = 0x0020,
VIDC_FW = 0x1000,
};
+enum vidc_msg_out {
+ VIDC_OUT_PRINTK = 0,
+ VIDC_OUT_FTRACE,
+};
+
enum msm_vidc_debugfs_event {
MSM_VIDC_DEBUGFS_EVENT_ETB,
MSM_VIDC_DEBUGFS_EVENT_EBD,
@@ -42,6 +48,7 @@
};
extern int msm_vidc_debug;
+extern int msm_vidc_debug_out;
extern int msm_fw_debug;
extern int msm_fw_debug_mode;
extern int msm_fw_low_power_mode;
@@ -49,11 +56,18 @@
#define dprintk(__level, __fmt, arg...) \
do { \
- if (msm_vidc_debug & __level) \
- printk(KERN_DEBUG VIDC_DBG_TAG \
- __fmt, __level, ## arg); \
+ if (msm_vidc_debug & __level) { \
+ if (msm_vidc_debug_out == VIDC_OUT_PRINTK) { \
+ printk(KERN_DEBUG VIDC_DBG_TAG \
+ __fmt, __level, ## arg); \
+ } else if (msm_vidc_debug_out == VIDC_OUT_FTRACE) { \
+ trace_printk(KERN_DEBUG VIDC_DBG_TAG \
+ __fmt, __level, ## arg); \
+ } \
+ } \
} while (0)
+
struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
struct dentry *parent);
struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index ca4ac53..8453b81 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -62,6 +62,23 @@
int ret;
};
+static void venus_hfi_dump_packet(u8 *packet)
+{
+ u32 c = 0, packet_size = *(u32 *)packet;
+ const int row_size = 32;
+ /* row must contain enough for 0xdeadbaad * 8 to be converted into
+ * "de ad ba ab " * 8 + '\0' */
+ char row[3 * row_size];
+
+ for (c = 0; c * row_size < packet_size; ++c) {
+ int bytes_to_read = ((c + 1) * row_size > packet_size) ?
+ packet_size % row_size : row_size;
+ hex_dump_to_buffer(packet + c * row_size, bytes_to_read,
+ row_size, 4, row, sizeof(row), false);
+ dprintk(VIDC_PKT, "%s\n", row);
+ }
+}
+
static void venus_hfi_sim_modify_cmd_packet(u8 *packet)
{
struct hfi_cmd_sys_session_init_packet *sys_init;
@@ -171,8 +188,6 @@
return -EINVAL;
}
- venus_hfi_sim_modify_cmd_packet(packet);
-
queue = (struct hfi_queue_header *) qinfo->q_hdr;
if (!queue) {
@@ -180,6 +195,13 @@
return -ENOENT;
}
+ venus_hfi_sim_modify_cmd_packet(packet);
+
+ if (msm_vidc_debug & VIDC_PKT) {
+ dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
+ venus_hfi_dump_packet(packet);
+ }
+
packet_size_in_words = (*(u32 *)packet) >> 2;
dprintk(VIDC_DBG, "Packet_size in words: %d", packet_size_in_words);
@@ -359,6 +381,10 @@
*pb_tx_req_is_set = (1 == queue->qhdr_tx_req) ? 1 : 0;
venus_hfi_hal_sim_modify_msg_packet(packet);
+ if (msm_vidc_debug & VIDC_PKT) {
+ dprintk(VIDC_PKT, "%s: %p\n", __func__, qinfo);
+ venus_hfi_dump_packet(packet);
+ }
dprintk(VIDC_DBG, "Out : ");
return rc;
}
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/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/ipa.c b/drivers/platform/msm/ipa/ipa.c
index 67c86b9..f4ad172 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -197,6 +197,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 +641,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;
}
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/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index 6b77609..c39de83 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -94,6 +94,7 @@
u8 pipes_enabled_per_bam[MAX_BAMS];
u32 inactivity_timer_ms[MAX_BAMS];
bool is_bam_inactivity[MAX_BAMS];
+ struct completion reset_done;
};
static char *bam_enable_strings[MAX_BAMS] = {
@@ -1554,6 +1555,10 @@
}
peer_handshake_info.client_ready = ready;
+ if (peer_handshake_info.state == USB_BAM_SM_PLUG_ACKED && !ready) {
+ pr_debug("Starting reset sequence");
+ INIT_COMPLETION(ctx.reset_done);
+ }
spin_unlock(&usb_bam_peer_handshake_info_lock);
if (!queue_work(ctx.usb_bam_wq,
@@ -1755,6 +1760,7 @@
case USB_BAM_SM_PLUG_ACKED:
if (!peer_handshake_info.client_ready) {
spin_unlock(&usb_bam_peer_handshake_info_lock);
+ pr_debug("Starting A2 reset sequence");
smsm_change_state(SMSM_APPS_STATE,
SMSM_USB_PLUG_UNPLUG, 0);
spin_lock(&usb_bam_peer_handshake_info_lock);
@@ -1767,6 +1773,8 @@
peer_handshake_info.reset_event.
callback(peer_handshake_info.reset_event.param);
spin_lock(&usb_bam_peer_handshake_info_lock);
+ complete_all(&ctx.reset_done);
+ pr_debug("Finished reset sequence");
peer_handshake_info.state = USB_BAM_SM_INIT;
peer_handshake_info.ack_received = 0;
}
@@ -2054,7 +2062,17 @@
}
EXPORT_SYMBOL(usb_bam_disconnect_ipa);
-int usb_bam_a2_reset(void)
+void usb_bam_reset_complete(void)
+{
+ pr_debug("Waiting for reset compelte");
+ if (wait_for_completion_interruptible_timeout(&ctx.reset_done,
+ 10*HZ) <= 0)
+ pr_warn("Timeout while waiting for reset");
+
+ pr_debug("Finished Waiting for reset complete");
+}
+
+int usb_bam_a2_reset(bool to_reconnect)
{
struct usb_bam_pipe_connect *pipe_connect;
int i;
@@ -2095,6 +2113,9 @@
if (bam != -1 && sps_device_reset(ctx.h_bam[bam]))
pr_err("%s: BAM reset failed\n", __func__);
+ if (!to_reconnect)
+ return ret;
+
/* Reconnect A2 pipes */
for (i = 0; i < ctx.max_connections; i++) {
pipe_connect = &usb_bam_connections[i];
@@ -2574,6 +2595,8 @@
spin_lock_init(&usb_bam_peer_handshake_info_lock);
INIT_WORK(&peer_handshake_info.reset_event.event_w, usb_bam_sm_work);
+ init_completion(&ctx.reset_done);
+ complete(&ctx.reset_done);
ctx.usb_bam_wq = alloc_workqueue("usb_bam_wq",
WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
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 f051af2..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;
}
@@ -2345,7 +2359,7 @@
return rc;
rc = qpnp_chg_masked_write(chip,
- chip->chgr_base + CHGR_BUCK_BCK_VBAT_REG_MODE,
+ chip->buck_base + CHGR_BUCK_BCK_VBAT_REG_MODE,
BUCK_VBAT_REG_NODE_SEL_BIT,
BUCK_VBAT_REG_NODE_SEL_BIT, 1);
if (rc) {
@@ -2675,6 +2689,39 @@
if (rc)
goto fail_chg_enable;
+ /* Check if bat_if is set in DT and make sure VADC is present */
+ spmi_for_each_container_dev(spmi_resource, spmi) {
+ if (!spmi_resource) {
+ pr_err("qpnp_chg: spmi resource absent\n");
+ rc = -ENXIO;
+ goto fail_chg_enable;
+ }
+
+ resource = spmi_get_resource(spmi, spmi_resource,
+ IORESOURCE_MEM, 0);
+ if (!(resource && resource->start)) {
+ pr_err("node %s IO resource absent!\n",
+ spmi->dev.of_node->full_name);
+ rc = -ENXIO;
+ goto fail_chg_enable;
+ }
+
+ rc = qpnp_chg_read(chip, &subtype,
+ resource->start + REG_OFFSET_PERP_SUBTYPE, 1);
+ if (rc) {
+ pr_err("Peripheral subtype read failed rc=%d\n", rc);
+ goto fail_chg_enable;
+ }
+
+ if (subtype == SMBB_BAT_IF_SUBTYPE ||
+ subtype == SMBBP_BAT_IF_SUBTYPE ||
+ subtype == SMBCL_BAT_IF_SUBTYPE){
+ rc = qpnp_vadc_is_ready();
+ if (rc)
+ goto fail_chg_enable;
+ }
+ }
+
spmi_for_each_container_dev(spmi_resource, spmi) {
if (!spmi_resource) {
pr_err("qpnp_chg: spmi resource absent\n");
@@ -2806,10 +2853,6 @@
device_init_wakeup(&spmi->dev, 1);
if (chip->bat_if_base) {
- rc = qpnp_vadc_is_ready();
- if (rc)
- goto fail_chg_enable;
-
chip->batt_psy.name = "battery";
chip->batt_psy.type = POWER_SUPPLY_TYPE_BATTERY;
chip->batt_psy.properties = msm_batt_power_props;
diff --git a/drivers/spi/spi_qsd.c b/drivers/spi/spi_qsd.c
index 1a4c3f3..e91e5d6 100644
--- a/drivers/spi/spi_qsd.c
+++ b/drivers/spi/spi_qsd.c
@@ -43,6 +43,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 +202,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 +1457,7 @@
}
if (tr->cs_change &&
- ((bpw != 8) || (bpw != 16) || (bpw != 32)))
+ ((bpw != 8) && (bpw != 16) && (bpw != 32)))
return false;
}
@@ -2359,44 +2532,124 @@
return 0;
}
+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: copy device-tree data to platfrom data struct
*/
struct msm_spi_platform_data *
__init msm_spi_dt_to_pdata(struct platform_device *pdev)
{
- struct device_node *node = pdev->dev.of_node;
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},
+ {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;
@@ -2808,6 +3061,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 +3113,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 +3176,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/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index a3b2617..be9a4b5 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -498,7 +498,7 @@
power_supply_set_supply_type(dotg->psy, power_supply_type);
- if ((dotg->charger->chg_type == DWC3_CDP_CHARGER) && mA > 2)
+ if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
mA = DWC3_IDEV_CHG_MAX;
if (dotg->charger->max_power == mA)
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index aaacd43..15f20ca 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -74,7 +74,6 @@
struct usb_composite_dev *cdev;
atomic_t online;
- bool is_open;
atomic_t open_excl;
atomic_t ioctl_excl;
@@ -747,11 +746,6 @@
pr_debug("Queue empty packet for QBI");
spin_lock(&dev->lock);
- if (!dev->is_open) {
- pr_err("%s: mbim file handler %p is not open", __func__, dev);
- spin_unlock(&dev->lock);
- return;
- }
cpkt = mbim_alloc_ctrl_pkt(0, GFP_ATOMIC);
if (!cpkt) {
@@ -976,12 +970,6 @@
memcpy(cpkt->buf, req->buf, len);
spin_lock(&dev->lock);
- if (!dev->is_open) {
- pr_err("mbim file handler %p is not open", dev);
- spin_unlock(&dev->lock);
- mbim_free_ctrl_pkt(cpkt);
- return;
- }
list_add_tail(&cpkt->list, &dev->cpkt_req_q);
spin_unlock(&dev->lock);
@@ -1455,6 +1443,7 @@
mbim_union_desc.bSlaveInterface0 = status;
mbim->bam_port.cdev = cdev;
+ mbim->bam_port.func = &mbim->function;
status = -ENODEV;
@@ -1574,6 +1563,7 @@
{
struct f_mbim *mbim = func_to_mbim(f);
+ bam_data_destroy(mbim->port_num);
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors);
@@ -1844,10 +1834,6 @@
atomic_set(&_mbim_dev->error, 0);
- spin_lock(&_mbim_dev->lock);
- _mbim_dev->is_open = true;
- spin_unlock(&_mbim_dev->lock);
-
pr_info("Exit, mbim file opened\n");
return 0;
@@ -1855,14 +1841,8 @@
static int mbim_release(struct inode *ip, struct file *fp)
{
- struct f_mbim *mbim = fp->private_data;
-
pr_info("Close mbim file");
- spin_lock(&mbim->lock);
- mbim->is_open = false;
- spin_unlock(&mbim->lock);
-
mbim_unlock(&_mbim_dev->open_excl);
return 0;
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 37189d8..4586d80 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -696,8 +696,8 @@
break;
}
- if (count > MTP_BULK_BUFFER_SIZE)
- xfer = MTP_BULK_BUFFER_SIZE;
+ if (count > mtp_tx_req_len)
+ xfer = mtp_tx_req_len;
else
xfer = count;
if (xfer && copy_from_user(req->buf, buf, xfer)) {
@@ -789,8 +789,8 @@
break;
}
- if (count > MTP_BULK_BUFFER_SIZE)
- xfer = MTP_BULK_BUFFER_SIZE;
+ if (count > mtp_tx_req_len)
+ xfer = mtp_tx_req_len;
else
xfer = count;
diff --git a/drivers/usb/gadget/f_qc_ecm.c b/drivers/usb/gadget/f_qc_ecm.c
index a6b443f..3db5b51 100644
--- a/drivers/usb/gadget/f_qc_ecm.c
+++ b/drivers/usb/gadget/f_qc_ecm.c
@@ -846,6 +846,7 @@
DBG(c->cdev, "ecm unbind\n");
+ bam_data_destroy(0);
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors);
diff --git a/drivers/usb/gadget/f_qc_rndis.c b/drivers/usb/gadget/f_qc_rndis.c
index 267cf53..c1ab552 100644
--- a/drivers/usb/gadget/f_qc_rndis.c
+++ b/drivers/usb/gadget/f_qc_rndis.c
@@ -725,14 +725,14 @@
*/
rndis->port.cdc_filter = 0;
+ if (rndis_qc_bam_connect(rndis))
+ goto fail;
+
DBG(cdev, "RNDIS RX/TX early activation ...\n");
net = gether_qc_connect_name(&rndis->port, "rndis0", false);
if (IS_ERR(net))
return PTR_ERR(net);
- if (rndis_qc_bam_connect(rndis))
- goto fail;
-
rndis_set_param_dev(rndis->config, net,
&rndis->port.cdc_filter);
} else
@@ -976,6 +976,8 @@
{
struct f_rndis_qc *rndis = func_to_rndis_qc(f);
+ pr_debug("rndis_qc_unbind: free");
+ bam_data_destroy(0);
rndis_deregister(rndis->config);
rndis_exit();
diff --git a/drivers/usb/gadget/u_bam.c b/drivers/usb/gadget/u_bam.c
index b71f903..9dd9978 100644
--- a/drivers/usb/gadget/u_bam.c
+++ b/drivers/usb/gadget/u_bam.c
@@ -778,6 +778,7 @@
unsigned long flags;
if (d->trans == USB_GADGET_XPORT_BAM2BAM) {
+ usb_bam_reset_complete();
ret = usb_bam_connect(d->src_connection_idx, &d->src_pipe_idx);
if (ret) {
pr_err("%s: usb_bam_connect (src) failed: err:%d\n",
@@ -916,7 +917,7 @@
msm_hw_bam_disable(1);
/* Reset BAM */
- ret = usb_bam_a2_reset();
+ ret = usb_bam_a2_reset(0);
if (ret) {
pr_err("%s: BAM reset failed %d\n", __func__, ret);
goto reenable_eps;
diff --git a/drivers/usb/gadget/u_bam_data.c b/drivers/usb/gadget/u_bam_data.c
index c638164..5c7e52f 100644
--- a/drivers/usb/gadget/u_bam_data.c
+++ b/drivers/usb/gadget/u_bam_data.c
@@ -145,69 +145,24 @@
struct bam_data_port *port = (struct bam_data_port *)param;
struct bam_data_ch_info *d;
int ret;
- bool reenable_eps = false;
d = &port->data_ch;
pr_debug("%s: reset by peer\n", __func__);
- /* Disable the relevant EPs if currently EPs are enabled */
- if (port->port_usb && port->port_usb->in &&
- port->port_usb->in->driver_data) {
- usb_ep_disable(port->port_usb->out);
- usb_ep_disable(port->port_usb->in);
-
- port->port_usb->in->driver_data = NULL;
- port->port_usb->out->driver_data = NULL;
- reenable_eps = true;
- }
-
/* Disable BAM */
msm_hw_bam_disable(1);
/* Reset BAM */
- ret = usb_bam_a2_reset();
+ ret = usb_bam_a2_reset(0);
if (ret) {
pr_err("%s: BAM reset failed %d\n", __func__, ret);
- goto reenable_eps;
+ return ret;
}
/* Enable BAM */
msm_hw_bam_disable(0);
-reenable_eps:
- /* Re-Enable the relevant EPs, if EPs were originally enabled */
- if (reenable_eps) {
- if (config_ep_by_speed(port->port_usb->cdev->gadget,
- port->port_usb->func, port->port_usb->in) ||
- config_ep_by_speed(port->port_usb->cdev->gadget,
- port->port_usb->func, port->port_usb->out)) {
- pr_err("%s: config_ep_by_speed failed", __func__);
- port->port_usb->in->desc = NULL;
- port->port_usb->out->desc = NULL;
- return -EINVAL;
- }
- ret = usb_ep_enable(port->port_usb->in);
- if (ret) {
- pr_err("%s: usb_ep_enable failed eptype:IN ep:%p",
- __func__, port->port_usb->in);
- return ret;
- }
- port->port_usb->in->driver_data = port;
-
- ret = usb_ep_enable(port->port_usb->out);
- if (ret) {
- pr_err("%s: usb_ep_enable failed eptype:OUT ep:%p",
- __func__, port->port_usb->out);
- port->port_usb->in->driver_data = 0;
- return ret;
- }
- port->port_usb->out->driver_data = port;
-
- bam_data_start_endless_rx(port);
- bam_data_start_endless_tx(port);
- }
-
/* Unregister the peer reset callback */
usb_bam_register_peer_reset_cb(NULL, NULL);
@@ -244,6 +199,7 @@
int ret;
pr_debug("%s: Connect workqueue started", __func__);
+ usb_bam_reset_complete();
if (d->trans == USB_GADGET_XPORT_BAM2BAM_IPA) {
if (d->func_type == USB_FUNC_MBIM) {
@@ -504,6 +460,23 @@
return 0;
}
+int bam_data_destroy(unsigned int no_bam2bam_port)
+{
+ struct bam_data_ch_info *d;
+ struct bam_data_port *port;
+
+ port = bam2bam_data_ports[no_bam2bam_port];
+ d = &port->data_ch;
+
+ pr_debug("bam_data_destroy: Freeing ports\n");
+ bam2bam_data_port_free(no_bam2bam_port);
+ if (bam_data_wq)
+ destroy_workqueue(bam_data_wq);
+ bam_data_wq = NULL;
+
+ return 0;
+}
+
int bam_data_setup(unsigned int no_bam2bam_port)
{
int i;
@@ -516,6 +489,11 @@
return -EINVAL;
}
+ if (bam_data_wq) {
+ pr_debug("bam_data is already setup");
+ return 0;
+ }
+
bam_data_wq = alloc_workqueue("k_bam_data",
WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
if (!bam_data_wq) {
diff --git a/drivers/usb/gadget/u_bam_data.h b/drivers/usb/gadget/u_bam_data.h
index 5ce678d..61f653a 100644
--- a/drivers/usb/gadget/u_bam_data.h
+++ b/drivers/usb/gadget/u_bam_data.h
@@ -36,6 +36,8 @@
int bam_data_setup(unsigned int no_bam2bam_port);
+int bam_data_destroy(unsigned int no_bam2bam_port);
+
void bam_data_suspend(u8 port_num);
void bam_data_resume(u8 port_num);
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_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c
index 3ee4d08..72e3c64 100644
--- a/drivers/video/msm/mdss/mdss_dsi_host.c
+++ b/drivers/video/msm/mdss/mdss_dsi_host.c
@@ -212,7 +212,7 @@
int mdss_dsi_buf_alloc(struct dsi_buf *dp, int size)
{
- dp->start = kmalloc(size, GFP_KERNEL);
+ dp->start = dma_alloc_writecombine(NULL, size, &dp->dmap, GFP_KERNEL);
if (dp->start == NULL) {
pr_err("%s:%u\n", __func__, __LINE__);
return -ENOMEM;
@@ -1360,11 +1360,6 @@
len = ALIGN(tp->len, 4);
size = ALIGN(tp->len, SZ_4K);
- tp->dmap = dma_map_single(&dsi_dev, tp->data, size, DMA_TO_DEVICE);
- if (dma_mapping_error(&dsi_dev, tp->dmap)) {
- pr_err("%s: dmap mapp failed\n", __func__);
- return -ENOMEM;
- }
if (is_mdss_iommu_attached()) {
int ret = msm_iommu_map_contig_buffer(tp->dmap,
@@ -1409,8 +1404,6 @@
msm_iommu_unmap_contig_buffer(addr,
mdss_get_iommu_domain(domain), 0, size);
- dma_unmap_single(&dsi_dev, tp->dmap, size, DMA_TO_DEVICE);
- tp->dmap = 0;
return tp->len;
}
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.h b/drivers/video/msm/mdss/mdss_mdp.h
index f59cdaa..7c9b5a9 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -364,6 +364,12 @@
bool mixer_swap;
};
+struct mdss_mdp_perf_params {
+ u32 ib_quota;
+ u32 ab_quota;
+ u32 mdp_clk_rate;
+};
+
#define is_vig_pipe(_pipe_id_) ((_pipe_id_) <= MDSS_MDP_SSPP_VIG2)
static inline void mdss_mdp_ctl_write(struct mdss_mdp_ctl *ctl,
u32 reg, u32 val)
@@ -430,6 +436,8 @@
int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
+int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_perf_params *perf);
struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 1cd2dbd..e81e3f5 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -98,13 +98,80 @@
return 0;
}
+/**
+ * mdss_mdp_perf_calc_pipe() - calculate performance numbers required by pipe
+ * @pipe: Source pipe struct containing updated pipe params
+ * @perf: Structure containing values that should be updated for
+ * performance tuning
+ *
+ * Function calculates the minimum required performance calculations in order
+ * to avoid MDP underflow. The calculations are based on the way MDP
+ * fetches (bandwidth requirement) and processes data through MDP pipeline
+ * (MDP clock requirement) based on frame size and scaling requirements.
+ */
+int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
+ struct mdss_mdp_perf_params *perf)
+{
+ struct mdss_mdp_mixer *mixer;
+ int fps = DEFAULT_FRAME_RATE;
+ u32 quota, rate, v_total, src_h;
+
+ if (!pipe || !perf || !pipe->mixer)
+ return -EINVAL;
+
+ mixer = pipe->mixer;
+ if (mixer->rotator_mode) {
+ v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
+ } else if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
+ struct mdss_panel_info *pinfo;
+
+ pinfo = &mixer->ctl->panel_data->panel_info;
+ fps = mdss_panel_get_framerate(pinfo);
+ v_total = mdss_panel_get_vtotal(pinfo);
+ } else {
+ v_total = mixer->height;
+ }
+
+ /*
+ * when doing vertical decimation lines will be skipped, hence there is
+ * no need to account for these lines in MDP clock or request bus
+ * bandwidth to fetch them.
+ */
+ src_h = pipe->src.h >> pipe->vert_deci;
+
+ quota = fps * pipe->src.w * src_h;
+ if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
+ quota = (quota * 3) / 2;
+ else
+ quota *= pipe->src_fmt->bpp;
+
+ rate = pipe->dst.w;
+ if (src_h > pipe->dst.h)
+ rate = (rate * src_h) / pipe->dst.h;
+
+ rate *= v_total * fps;
+ if (mixer->rotator_mode) {
+ rate /= 4; /* block mode fetch at 4 pix/clk */
+ quota *= 2; /* bus read + write */
+ perf->ib_quota = quota;
+ } else {
+ perf->ib_quota = (quota / pipe->dst.h) * v_total;
+ }
+ perf->ab_quota = quota;
+ perf->mdp_clk_rate = rate;
+
+ pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
+ mixer->num, pipe->num, rate, perf->ab_quota, perf->ib_quota);
+
+ return 0;
+}
+
static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
u32 *bus_ab_quota, u32 *bus_ib_quota,
u32 *clk_rate)
{
struct mdss_mdp_pipe *pipe;
- const int fps = 60;
- u32 quota, rate;
+ int fps = DEFAULT_FRAME_RATE;
u32 v_total;
int i;
u32 max_clk_rate = 0, ab_total = 0, ib_total = 0;
@@ -113,17 +180,13 @@
*bus_ib_quota = 0;
*clk_rate = 0;
- if (mixer->rotator_mode) {
- pipe = mixer->stage_pipe[0]; /* rotator pipe */
- v_total = pipe->flags & MDP_ROT_90 ? pipe->dst.w : pipe->dst.h;
- } else {
+ if (!mixer->rotator_mode) {
int is_writeback = false;
if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
struct mdss_panel_info *pinfo;
pinfo = &mixer->ctl->panel_data->panel_info;
- v_total = (pinfo->yres + pinfo->lcdc.v_back_porch +
- pinfo->lcdc.v_front_porch +
- pinfo->lcdc.v_pulse_width);
+ fps = mdss_panel_get_framerate(pinfo);
+ v_total = mdss_panel_get_vtotal(pinfo);
if (pinfo->type == WRITEBACK_PANEL)
is_writeback = true;
@@ -142,7 +205,7 @@
}
for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
- u32 ib_quota;
+ struct mdss_mdp_perf_params perf;
pipe = mixer->stage_pipe[i];
if (pipe == NULL)
continue;
@@ -152,33 +215,13 @@
max_clk_rate = 0;
}
- quota = fps * pipe->src.w * pipe->src.h;
- if (pipe->src_fmt->chroma_sample == MDSS_MDP_CHROMA_420)
- quota = (quota * 3) / 2;
- else
- quota *= pipe->src_fmt->bpp;
+ if (mdss_mdp_perf_calc_pipe(pipe, &perf))
+ continue;
- rate = pipe->dst.w;
- if (pipe->src.h > pipe->dst.h)
- rate = (rate * pipe->src.h) / pipe->dst.h;
-
- rate *= v_total * fps;
- if (mixer->rotator_mode) {
- rate /= 4; /* block mode fetch at 4 pix/clk */
- quota *= 2; /* bus read + write */
- ib_quota = quota;
- } else {
- ib_quota = (quota / pipe->dst.h) * v_total;
- }
-
-
- pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
- mixer->num, pipe->num, rate, quota, ib_quota);
-
- ab_total += quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
- ib_total += ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
- if (rate > max_clk_rate)
- max_clk_rate = rate;
+ ab_total += perf.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+ ib_total += perf.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
+ if (perf.mdp_clk_rate > max_clk_rate)
+ max_clk_rate = perf.mdp_clk_rate;
}
*bus_ab_quota += ab_total;
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index fcaa80b..808800a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -289,6 +289,32 @@
return ret;
}
+static int __mdp_pipe_tune_perf(struct mdss_mdp_pipe *pipe)
+{
+ struct mdss_data_type *mdata = pipe->mixer->ctl->mdata;
+ struct mdss_mdp_perf_params perf;
+ int rc;
+
+ for (;;) {
+ rc = mdss_mdp_perf_calc_pipe(pipe, &perf);
+
+ if (!rc && (perf.mdp_clk_rate <= mdata->max_mdp_clk_rate))
+ break;
+
+ /*
+ * if decimation is available try to reduce minimum clock rate
+ * requirement by applying vertical decimation and reduce
+ * mdp clock requirement
+ */
+ if (mdata->has_decimation && (pipe->vert_deci < MAX_DECIMATION))
+ pipe->vert_deci++;
+ else
+ return -EPERM;
+ }
+
+ return 0;
+}
+
static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd,
struct mdp_overlay *req,
struct mdss_mdp_pipe **ppipe)
@@ -497,6 +523,12 @@
}
}
+ ret = __mdp_pipe_tune_perf(pipe);
+ if (ret) {
+ pr_debug("unable to satisfy performance. ret=%d\n", ret);
+ goto exit_fail;
+ }
+
ret = mdss_mdp_smp_reserve(pipe);
if (ret) {
pr_debug("mdss_mdp_smp_reserve failed. ret=%d\n", ret);
@@ -506,6 +538,7 @@
pipe->params_changed++;
req->id = pipe->ndx;
+ req->vert_deci = pipe->vert_deci;
*ppipe = pipe;
@@ -1667,7 +1700,7 @@
switch (metadata->op) {
case metadata_op_frame_rate:
metadata->data.panel_frame_rate =
- mdss_get_panel_framerate(mfd);
+ mdss_panel_get_framerate(mfd->panel_info);
break;
case metadata_op_get_caps:
ret = mdss_fb_get_hw_caps(mfd, &metadata->data.caps);
diff --git a/drivers/video/msm/mdss/mdss_mdp_util.c b/drivers/video/msm/mdss/mdss_mdp_util.c
index 305c3cb..539ed22 100644
--- a/drivers/video/msm/mdss/mdss_mdp_util.c
+++ b/drivers/video/msm/mdss/mdss_mdp_util.c
@@ -28,7 +28,6 @@
#include "mdss_mdp.h"
#include "mdss_mdp_formats.h"
#include "mdss_debug.h"
-#define DEFAULT_FRAME_RATE 60
enum {
MDP_INTR_VSYNC_INTF_0,
@@ -246,6 +245,9 @@
ps->rau_h[1] = 4;
} else
ps->ystride[1] = 32 * 2;
+
+ /* account for both chroma components */
+ ps->ystride[1] <<= 1;
} else if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
ps->rau_cnt = DIV_ROUND_UP(w, 32);
ps->ystride[0] = 32 * 4 * fmt->bpp;
@@ -261,6 +263,10 @@
ps->ystride[1] *= ps->rau_cnt;
ps->num_planes = 2;
+ pr_debug("BWC rau_cnt=%d strides={%d,%d} heights={%d,%d}\n",
+ ps->rau_cnt, ps->ystride[0], ps->ystride[1],
+ ps->rau_h[0], ps->rau_h[1]);
+
return 0;
}
@@ -269,7 +275,7 @@
{
struct mdss_mdp_format_params *fmt;
int i, rc;
- u32 bpp, ystride0_off, ystride1_off;
+ u32 bpp;
if (ps == NULL)
return -EINVAL;
@@ -284,24 +290,23 @@
memset(ps, 0, sizeof(struct mdss_mdp_plane_sizes));
if (bwc_mode) {
- u32 meta_size;
+ u32 height, meta_size;
rc = mdss_mdp_get_rau_strides(w, h, fmt, ps);
if (rc)
return rc;
+ height = DIV_ROUND_UP(h, ps->rau_h[0]);
meta_size = DIV_ROUND_UP(ps->rau_cnt, 8);
- ps->ystride[0] += meta_size;
ps->ystride[1] += meta_size;
+ ps->ystride[0] += ps->ystride[1] + meta_size;
+ ps->plane_size[0] = ps->ystride[0] * height;
- ystride0_off = DIV_ROUND_UP(h, ps->rau_h[0]);
- ystride1_off = DIV_ROUND_UP(h, ps->rau_h[1]);
- ps->plane_size[0] = (ps->ystride[0] * ystride0_off) +
- (ps->ystride[1] * ystride1_off);
- ps->ystride[0] += ps->ystride[1];
ps->ystride[1] = 2;
- ps->plane_size[1] = ps->rau_cnt * ps->ystride[1] *
- (ystride0_off + ystride1_off);
+ ps->plane_size[1] = 2 * ps->rau_cnt * height;
+
+ pr_debug("BWC data stride=%d size=%d meta size=%d\n",
+ ps->ystride[0], ps->plane_size[0], ps->plane_size[1]);
} else {
if (fmt->fetch_planes == MDSS_MDP_PLANE_INTERLEAVED) {
ps->num_planes = 1;
@@ -551,27 +556,3 @@
return ret;
}
-
-u32 mdss_get_panel_framerate(struct msm_fb_data_type *mfd)
-{
- u32 frame_rate = DEFAULT_FRAME_RATE;
- u32 pixel_total;
- struct mdss_panel_info *panel_info = mfd->panel_info;
-
- if ((panel_info->type == MIPI_VIDEO_PANEL) ||
- (panel_info->type == MIPI_CMD_PANEL)) {
- frame_rate = panel_info->mipi.frame_rate;
- } else {
- pixel_total = (panel_info->lcdc.h_back_porch +
- panel_info->lcdc.h_front_porch +
- panel_info->lcdc.h_pulse_width +
- panel_info->xres) *
- (panel_info->lcdc.v_back_porch +
- panel_info->lcdc.v_front_porch +
- panel_info->lcdc.v_pulse_width +
- panel_info->yres);
- if (pixel_total)
- frame_rate = panel_info->clk_rate / pixel_total;
- }
- return frame_rate;
-}
diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h
index 1bf414f..e8a6312 100644
--- a/drivers/video/msm/mdss/mdss_panel.h
+++ b/drivers/video/msm/mdss/mdss_panel.h
@@ -23,6 +23,8 @@
u16 type;
};
+#define DEFAULT_FRAME_RATE 60
+
/* panel type list */
#define NO_PANEL 0xffff /* No Panel */
#define MDDI_PANEL 1 /* MDDI */
@@ -270,6 +272,58 @@
struct mdss_panel_data *next;
};
+/**
+ * mdss_get_panel_framerate() - get panel frame rate based on panel information
+ * @panel_info: Pointer to panel info containing all panel information
+ */
+static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info)
+{
+ u32 frame_rate, pixel_total;
+
+ if (panel_info == NULL)
+ return DEFAULT_FRAME_RATE;
+
+ switch (panel_info->type) {
+ case MIPI_VIDEO_PANEL:
+ case MIPI_CMD_PANEL:
+ frame_rate = panel_info->mipi.frame_rate;
+ break;
+ case WRITEBACK_PANEL:
+ frame_rate = DEFAULT_FRAME_RATE;
+ break;
+ default:
+ pixel_total = (panel_info->lcdc.h_back_porch +
+ panel_info->lcdc.h_front_porch +
+ panel_info->lcdc.h_pulse_width +
+ panel_info->xres) *
+ (panel_info->lcdc.v_back_porch +
+ panel_info->lcdc.v_front_porch +
+ panel_info->lcdc.v_pulse_width +
+ panel_info->yres);
+ if (pixel_total)
+ frame_rate = panel_info->clk_rate / pixel_total;
+ else
+ frame_rate = DEFAULT_FRAME_RATE;
+
+ break;
+ }
+ return frame_rate;
+}
+
+/*
+ * mdss_panel_get_vtotal() - return panel vertical height
+ * @pinfo: Pointer to panel info containing all panel information
+ *
+ * Returns the total height of the panel including any blanking regions
+ * which are not visible to user but used to calculate panel pixel clock.
+ */
+static inline int mdss_panel_get_vtotal(struct mdss_panel_info *pinfo)
+{
+ return pinfo->yres + pinfo->lcdc.v_back_porch +
+ pinfo->lcdc.v_front_porch +
+ pinfo->lcdc.v_pulse_width;
+}
+
int mdss_register_panel(struct platform_device *pdev,
struct mdss_panel_data *pdata);
#endif /* MDSS_PANEL_H */
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/msm8226.c b/sound/soc/msm/msm8226.c
index 9990ae8..22cd61a 100644
--- a/sound/soc/msm/msm8226.c
+++ b/sound/soc/msm/msm8226.c
@@ -295,10 +295,10 @@
struct snd_ctl_elem_value *ucontrol)
{
switch (ucontrol->value.integer.value[0]) {
- case 0:
+ case 8000:
msm_btsco_rate = BTSCO_RATE_8KHZ;
break;
- case 1:
+ case 16000:
msm_btsco_rate = BTSCO_RATE_16KHZ;
break;
default:
@@ -310,11 +310,6 @@
return 0;
}
-static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
- SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
- msm_btsco_rate_get, msm_btsco_rate_put),
-};
-
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -549,6 +544,8 @@
msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
SOC_ENUM_EXT("AUX PCM SampleRate", msm8226_auxpcm_enum[0],
msm8226_auxpcm_rate_get, msm8226_auxpcm_rate_put),
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 9fc0adb..a39a18b 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -862,10 +862,10 @@
struct snd_ctl_elem_value *ucontrol)
{
switch (ucontrol->value.integer.value[0]) {
- case 0:
+ case 8000:
msm_btsco_rate = BTSCO_RATE_8KHZ;
break;
- case 1:
+ case 16000:
msm_btsco_rate = BTSCO_RATE_16KHZ;
break;
default:
@@ -940,11 +940,6 @@
return 1;
}
-static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
- SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
- msm_btsco_rate_get, msm_btsco_rate_put),
-};
-
static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -1350,6 +1345,8 @@
hdmi_rx_bit_format_get, hdmi_rx_bit_format_put),
SOC_ENUM_EXT("PROXY_RX Channels", msm_snd_enum[6],
msm_proxy_rx_ch_get, msm_proxy_rx_ch_put),
+ SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
+ msm_btsco_rate_get, msm_btsco_rate_put),
};
static bool msm8974_swap_gnd_mic(struct snd_soc_codec *codec)
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