Merge "msm8937: Enable config flag for File based Encryption"
diff --git a/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt
new file mode 100644
index 0000000..ba61a2f
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt
@@ -0,0 +1,99 @@
+Goodix GT9xx series touch controller
+
+Required properties:
+
+ - compatible : Should be "goodix,gt9xx"
+ - reg : I2C slave address of the device.
+ - interrupt-parent : Parent of interrupt.
+ - interrupts : Configuration of touch panel controller interrupt
+ GPIO.
+ - goodix,product-id : Product identification of the controller.
+ - interrupt-gpios : Interrupt gpio which is to provide interrupts to
+ host, same as "interrupts" node.
+ - reset-gpios : Reset gpio to control the reset of chip.
+ - goodix,display-coords : Display coordinates in pixels. It is a four
+ tuple consisting of min x, min y, max x and
+ max y values.
+
+Optional properties:
+
+ - avdd-supply : Power supply needed to power up the device, this is
+ for fixed voltage external regulator.
+ - vdd-supply : Power supply needed to power up the device, when use
+ external regulator, do not add this property.
+ - vcc-i2c-supply : Power source required to power up i2c bus.
+ GT9xx series can provide 1.8V from internal
+ LDO, add this properties base on hardware
+ design.
+ - goodix,panel-coords : Panel coordinates for the chip in pixels.
+ It is a four tuple consisting of min x,
+ min y, max x and max y values.
+ - goodix,i2c-pull-up : To specify pull up is required.
+ - goodix,force-update : To specify force update is allowed.
+ - goodix,enable-power-off : Power off touchscreen during suspend.
+ - goodix,button-map : Button map of key codes. The number of key codes
+ depend on panel.
+ - goodix,cfg-data0 : Touch screen controller config data group 0. Ask vendor
+ to provide that.
+ Driver supports maximum six config groups. If more than one
+ groups are defined, driver will select config group depending
+ on hardware configuration. If only config group 0 is defined,
+ it will be used for all hardware configurations.
+ Touch screen controller will use its onchip default config data
+ if this property is not present.
+ - goodix,cfg-data1 : Touch screen controller config data group 1. Ask vendor
+ to provide that.
+ - goodix,cfg-data2 : Touch screen controller config data group 2. Ask vendor
+ to provide that.
+ - goodix,cfg-data3 : Touch screen controller config data group 3. Ask vendor
+ to provide that.
+ - goodix,cfg-data4 : Touch screen controller config data group 4. Ask vendor
+ to provide that.
+ - goodix,cfg-data5 : Touch screen controller config data group 5. Ask vendor
+ to provide that.
+ - goodix,fw-name : Touch screen controller firmware file name.
+ - goodix,slide-wakeup : To specify slide-wakeup property is enabled or not.
+ - goodix,dbl-clk-wakeup : To specify dbl-clk-wakeup property is enabled or not.
+ - goodix,change-x2y : To specify change-x2y property is enabled or not.
+ - goodix,driver-send-cfg : To specify driver-send-cfg property is enabled or not.
+ - goodix,have-touch-key : To specify have-touch-key property is enabled or not.
+ - goodix,with-pen : To specify with-pen property is enabled or not.
+Example:
+i2c@f9927000 {
+ goodix@5d {
+ compatible = "goodix,gt9xx";
+ reg = <0x5d>;
+ interrupt-parent = <&msmgpio>;
+ interrupts = <17 0x2008>;
+ reset-gpios = <&msmgpio 16 0x00>;
+ interrupt-gpios = <&msmgpio 17 0x00>;
+ avdd-supply = <&tp_power>;
+ goodix,panel-coords = <0 0 720 1200>;
+ goodix,display-coords = <0 0 720 1080>;
+ goodix,button-map= <158 102 139>;
+ goodix,product-id = "915";
+ goodix,cfg-data0 = [
+ 41 D0 02 00 05 0A 05 01 01 08
+ 12 58 50 41 03 05 00 00 00 00
+ 00 00 00 00 00 00 00 8C 2E 0E
+ 28 24 73 13 00 00 00 83 03 1D
+ 40 02 00 00 00 03 64 32 00 00
+ 00 1A 38 94 C0 02 00 00 00 04
+ 9E 1C 00 8D 20 00 7A 26 00 6D
+ 2C 00 60 34 00 60 10 38 68 00
+ F0 50 35 FF FF 27 00 00 00 00
+ 00 01 1B 14 0C 14 00 00 01 00
+ 00 00 00 00 00 00 00 00 00 00
+ 00 00 02 04 06 08 0A 0C 0E 10
+ 12 14 16 18 1A 1C FF FF FF FF
+ FF FF FF FF FF FF FF FF FF FF
+ FF FF 00 02 04 06 08 0A 0C 0F
+ 10 12 13 14 16 18 1C 1D 1E 1F
+ 20 21 22 24 26 28 29 2A FF FF
+ FF FF FF FF FF FF FF 22 22 22
+ 22 22 22 FF 07 01];
+ goodix,fw_name = "gtp_fw.bin";
+ goodix,have-touch-key;
+ goodix,driver-send-cfg;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
index 04f11ce..fa858c3 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts
@@ -20,3 +20,7 @@
"qcom,sdxpoorwills", "qcom,cdp";
qcom,board-id = <1 0x0>;
};
+
+&blsp1_uart2b_hs {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
index 0f9c8bc..fc56a50 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi
@@ -11,6 +11,7 @@
*/
#include "sdxpoorwills-cdp.dtsi"
+#include "sdxpoorwills-memory-256.dtsi"
&soc {
vreg_sd_mmc: vreg_sd_mmc {
@@ -21,3 +22,11 @@
&sdhc_1 {
cd-gpios = <&tlmm 21 0x1>;
};
+
+&soc {
+ bluetooth: bt_qca6174 {
+ compatible = "qca,qca6174";
+ qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */
+ qca,bt-vdd-pa-supply = <&vreg_wlan>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi
new file mode 100644
index 0000000..0c21814
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi
@@ -0,0 +1,19 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&peripheral2_mem {
+ reg = <0x8fe00000 0x200000>;
+};
+
+&mss_mem {
+ reg = <0x87000000 0x8300000>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
index 2377d79c..a774c8b 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts
@@ -20,3 +20,7 @@
"qcom,sdxpoorwills", "qcom,mtp";
qcom,board-id = <8 0x0>;
};
+
+&blsp1_uart2b_hs {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
index 7412031..297af52 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi
@@ -11,6 +11,7 @@
*/
#include "sdxpoorwills-mtp.dtsi"
+#include "sdxpoorwills-memory-256.dtsi"
&soc {
vreg_sd_mmc: vreg_sd_mmc {
@@ -21,3 +22,11 @@
&sdhc_1 {
cd-gpios = <&tlmm 21 0x1>;
};
+
+&soc {
+ bluetooth: bt_qca6174 {
+ compatible = "qca,qca6174";
+ qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */
+ qca,bt-vdd-pa-supply = <&vreg_wlan>;
+ };
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 2014885..ef001fb 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -36,7 +36,7 @@
peripheral2_mem: peripheral2_region@8fe00000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0x8fe00000 0x200000>;
+ reg = <0x8fe00000 0xe00000>;
label = "peripheral2_mem";
};
@@ -65,7 +65,7 @@
mss_mem: mss_region@87400000 {
compatible = "removed-dma-pool";
no-map;
- reg = <0x87400000 0x8300000>;
+ reg = <0x87000000 0x8700000>;
label = "mss_mem";
};
diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi
new file mode 100644
index 0000000..e065f00
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi
@@ -0,0 +1,157 @@
+/* Copyright (c) 2018, 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.
+ */
+
+&mdss_mdp {
+ dsi_hx83112a_truly_video: qcom,mdss_dsi_hx83112a_truly_video {
+ qcom,mdss-dsi-panel-name =
+ "hx83112a video mode dsi truly panel";
+ qcom,mdss-dsi-panel-type = "dsi_video_mode";
+
+ qcom,mdss-dsi-virtual-channel-id = <0>;
+ qcom,mdss-dsi-stream = <0>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-color-order = "rgb_swap_rgb";
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-h-sync-pulse = <0>;
+ qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
+ qcom,mdss-dsi-lane-map = "lane_map_0123";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-tx-eot-append;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-lp11-init;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0 {
+ qcom,mdss-dsi-panel-width = <1080>;
+ qcom,mdss-dsi-panel-height = <2160>;
+ qcom,mdss-dsi-h-front-porch = <42>;
+ qcom,mdss-dsi-h-back-porch = <42>;
+ qcom,mdss-dsi-h-pulse-width = <10>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <15>;
+ qcom,mdss-dsi-v-front-porch = <10>;
+ qcom,mdss-dsi-v-pulse-width = <3>;
+ qcom,mdss-dsi-panel-framerate = <60>;
+ qcom,mdss-dsi-on-command = [
+ 39 01 00 00 00 00 04 B9 83 11 2A
+ 39 01 00 00 00 00 09 B1 08 29 29 00 00 4F 54
+ 33
+ 39 01 00 00 00 00 11 B2 00 02 00 80 70 00 08
+ 26 FC 01 00 03 15 A3 87 09
+ 39 01 00 00 00 00 02 BD 02
+ 39 01 00 00 00 00 02 BD 00
+ 39 01 00 00 00 00 03 D2 2C 2C
+ 39 01 00 00 00 00 1C B4 01 CE 01 CE 01 CE 0A
+ CE 0A CE 0A CE 00 FF 00 FF 00 00 22 23 00
+ 28 0A 13 14 00 8A
+ 39 01 00 00 00 00 02 BD 02
+ 39 01 00 00 00 00 0A B4 00 92 12 22 88 12 12
+ 00 53
+ 39 01 00 00 00 00 02 BD 00
+ 39 01 00 00 00 00 04 B6 82 82 E3
+ 39 01 00 00 00 00 02 CC 08
+ 39 01 00 00 00 00 2B D3 40 00 00 00 00 01 01
+ 0A 0A 07 07 00 08 09 09 09 09 32 10 09 00
+ 09 32 21 0A 00 0A 32 10 08 00 00 00 00 00
+ 00 00 00 00 0B 08 82
+ 39 01 00 00 00 00 02 BD 01
+ 39 01 00 00 00 00 09 D3 00 00 19 00 00 0A 00
+ 81
+ 39 01 00 00 00 00 02 BD 00
+ 39 01 00 00 00 00 31 D5 18 18 18 18 18 18 18
+ 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0
+ 18 40 40 01 00 07 06 05 04 03 02 21 20 18
+ 18 19 19 18 18 03 03 18 18 18 18 18 18
+ 39 01 00 00 00 00 31 D6 18 18 18 18 18 18 18
+ 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0
+ 18 40 40 02 03 04 05 06 07 00 01 20 21 18
+ 18 18 18 19 19 20 20 18 18 18 18 18 18
+ 39 01 00 00 00 00 19 D8 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00
+ 39 01 00 00 00 00 02 BD 01
+ 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA
+ 39 01 00 00 00 00 02 BD 02
+ 39 01 00 00 00 00 0D D8 AF FF FA AA BA AA AA
+ FF FA AA BA AA
+ 39 01 00 00 00 00 02 BD 03
+ 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA
+ AA AA AA AA AA AA AA AA AA AA AA AA AA AA
+ AA AA AA
+ 39 01 00 00 00 00 02 BD 00
+ 39 01 00 00 00 00 18 E7 0E 0E 1E 6A 1D 6A 00
+ 32 02 02 00 00 02 02 02 05 14 14 32 B9 23
+ B9 08
+ 39 01 00 00 00 00 02 BD 01
+ 39 01 00 00 00 00 0A E7 02 00 98 01 9A 0D A8
+ 0E 01
+ 39 01 00 00 00 00 02 BD 02
+ 39 01 00 00 00 00 1E E7 00 00 08 00 01 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 04 00 00 00 00 02 00
+ 39 01 00 00 00 00 02 BD 00
+ 39 01 00 00 00 00 02 C1 01
+ 39 01 00 00 00 00 02 BD 01
+ 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4
+ C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74
+ 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22
+ 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54
+ C6 B8 9C 37 43 3D E5 00
+ 39 01 00 00 00 00 02 BD 02
+ 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4
+ C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74
+ 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22
+ 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54
+ C6 B8 9C 37 43 3D E5 00
+ 39 01 00 00 00 00 02 BD 03
+ 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4
+ C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74
+ 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22
+ 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54
+ C6 B8 9C 37 43 3D E5 00
+ 39 01 00 00 00 00 02 BD 00
+ 39 01 00 00 00 00 02 E9 C3
+ 39 01 00 00 00 00 03 CB 92 01
+ 39 01 00 00 00 00 02 E9 3F
+ 39 01 00 00 00 00 07 C7 70 00 04 E0 33 00
+ 39 01 00 00 00 00 03 51 0F FF
+ 39 01 00 00 00 00 02 53 24
+ 39 01 00 00 00 00 02 55 00
+ 15 01 00 00 00 00 02 35 00
+ 05 01 00 00 96 00 02 11 00
+ 05 01 00 00 32 00 02 29 00];
+ qcom,mdss-dsi-off-command = [
+ 05 01 00 00 32 00 02 28 00
+ 05 01 00 00 96 00 02 10 00];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi
new file mode 100644
index 0000000..23c0987
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-mtp.dtsi
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2015-2018, 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.
+ */
+
+&cci {
+ actuator0: qcom,actuator@0 {
+ cell-index = <0>;
+ reg = <0x0>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ cam_vaf-supply = <&pm8937_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ actuator1: qcom,actuator@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ compatible = "qcom,actuator";
+ qcom,cci-master = <0>;
+ cam_vaf-supply = <&pm8937_l17>;
+ qcom,cam-vreg-name = "cam_vaf";
+ qcom,cam-vreg-min-voltage = <2850000>;
+ qcom,cam-vreg-max-voltage = <2850000>;
+ qcom,cam-vreg-op-mode = <80000>;
+ };
+
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <0>;
+ reg = <0x0>;
+ cam_vdig-supply = <&pm8937_l23>;
+ cam_vana-supply = <&pm8937_l22>;
+ cam_vio-supply = <&pm8937_l6>;
+ cam_vaf-supply = <&pm8937_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vana", "cam_vio",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 36 0>,
+ <&tlmm 35 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0";
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <19200000 0>;
+ };
+
+ eeprom1: qcom,eeprom@1 {
+ cell-index = <1>;
+ reg = <0x1>;
+ qcom,eeprom-name = "sunny_8865";
+ compatible = "qcom,eeprom";
+ qcom,slave-addr = <0x6c>;
+ qcom,cci-master = <0>;
+ qcom,num-blocks = <8>;
+
+ qcom,page0 = <1 0x0100 2 0x01 1 1>;
+ qcom,poll0 = <0 0x0 2 0x0 1 0>;
+ qcom,mem0 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page1 = <1 0x5002 2 0x00 1 0>;
+ qcom,poll1 = <0 0x0 2 0x0 1 0>;
+ qcom,mem1 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page2 = <1 0x3d84 2 0xc0 1 0>;
+ qcom,poll2 = <0 0x0 2 0x0 1 0>;
+ qcom,mem2 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page3 = <1 0x3d88 2 0x70 1 0>;
+ qcom,poll3 = <0 0x0 2 0x0 1 0>;
+ qcom,mem3 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page4 = <1 0x3d89 2 0x10 1 0>;
+ qcom,poll4 = <0 0x0 2 0x0 1 0>;
+ qcom,mem4 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page5 = <1 0x3d8a 2 0x70 1 0>;
+ qcom,poll5 = <0 0x0 2 0x0 1 0>;
+ qcom,mem5 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page6 = <1 0x3d8b 2 0xf4 1 0>;
+ qcom,poll6 = <0 0x0 2 0x0 1 0>;
+ qcom,mem6 = <0 0x0 2 0x0 1 0>;
+
+ qcom,page7 = <1 0x3d81 2 0x01 1 10>;
+ qcom,poll7 = <0 0x0 2 0x0 1 1>;
+ qcom,mem7 = <1536 0x7010 2 0 1 0>;
+
+ cam_vdig-supply = <&pm8937_l23>;
+ cam_vana-supply = <&pm8937_l22>;
+ cam_vio-supply = <&pm8937_l6>;
+ cam_vaf-supply = <&pm8937_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg",
+ "sensor_vreg",
+ "sensor_gpio", "sensor_gpio" , "sensor_clk";
+ qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio",
+ "sensor_gpio_reset", "sensor_gpio_standby",
+ "sensor_cam_mclk";
+ qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>;
+ qcom,cam-power-seq-delay = <1 1 1 30 30 5>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ };
+
+ qcom,camera@0 {
+ cell-index = <0>;
+ compatible = "qcom,camera";
+ reg = <0x0>;
+ qcom,csiphy-sd-index = <0>;
+ qcom,csid-sd-index = <0>;
+ qcom,mount-angle = <270>;
+ qcom,led-flash-src = <&led_flash0>;
+ qcom,eeprom-src = <&eeprom0>;
+ qcom,actuator-src = <&actuator0>;
+ cam_vana-supply = <&pm8937_l22>;
+ cam_vio-supply = <&pm8937_l6>;
+ cam_vaf-supply = <&pm8937_l17>;
+ qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vaf";
+ qcom,cam-vreg-min-voltage = <0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_default
+ &cam_sensor_rear_default
+ &cam_sensor_rear_vdig>;
+ pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep
+ &cam_sensor_rear_vdig_sleep>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 36 0>,
+ <&tlmm 35 0>,
+ <&tlmm 62 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-req-tbl-num = <0 1 2 3>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VDIG";
+ qcom,sensor-position = <0>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk0_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk0_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@1 {
+ cell-index = <1>;
+ compatible = "qcom,camera";
+ reg = <0x1>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ cam_vdig-supply = <&pm8937_l23>;
+ cam_vana-supply = <&pm8937_l22>;
+ cam_vio-supply = <&pm8937_l6>;
+ cam_vaf-supply = <&pm8937_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <200000 0 80000 100000>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk1_default
+ &cam_sensor_front_default>;
+ pinctrl-1 = <&cam_sensor_mclk1_sleep
+ &cam_sensor_front_sleep>;
+ gpios = <&tlmm 27 0>,
+ <&tlmm 38 0>,
+ <&tlmm 50 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK1",
+ "CAM_RESET1",
+ "CAM_STANDBY1";
+ qcom,sensor-position = <0x100>;
+ qcom,sensor-mode = <1>;
+ qcom,cci-master = <1>;
+ clocks = <&clock_gcc clk_mclk1_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk1_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+
+ qcom,camera@2 {
+ cell-index = <2>;
+ compatible = "qcom,camera";
+ reg = <0x02>;
+ qcom,csiphy-sd-index = <1>;
+ qcom,csid-sd-index = <1>;
+ qcom,mount-angle = <90>;
+ qcom,eeprom-src = <&eeprom1>;
+ qcom,actuator-src = <&actuator1>;
+ cam_vdig-supply = <&pm8937_l23>;
+ cam_vana-supply = <&pm8937_l22>;
+ cam_vio-supply = <&pm8937_l6>;
+ cam_vaf-supply = <&pm8937_l17>;
+ qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_vaf";
+ qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>;
+ qcom,cam-vreg-op-mode = <105000 0 80000 100000>;
+ qcom,gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk2_default
+ &cam_sensor_front1_default>;
+ pinctrl-1 = <&cam_sensor_mclk2_sleep
+ &cam_sensor_front1_sleep>;
+ gpios = <&tlmm 28 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>;
+ qcom,gpio-reset = <1>;
+ qcom,gpio-standby = <2>;
+ qcom,gpio-req-tbl-num = <0 1 2>;
+ qcom,gpio-req-tbl-flags = <1 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK2",
+ "CAM_RESET2",
+ "CAM_STANDBY2";
+ qcom,sensor-position = <1>;
+ qcom,sensor-mode = <0>;
+ qcom,cci-master = <0>;
+ status = "ok";
+ clocks = <&clock_gcc clk_mclk2_clk_src>,
+ <&clock_gcc clk_gcc_camss_mclk2_clk>;
+ clock-names = "cam_src_clk", "cam_clk";
+ qcom,clock-rates = <24000000 0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
index d2e100e9..7f35e1e 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include "msm8917-camera-sensor-mtp.dtsi"
&blsp1_uart2 {
status = "ok";
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi
index 91a290f..55e8e21 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937.dtsi
@@ -22,3 +22,14 @@
&usb_otg {
extcon = <&qpnp_smbcharger>;
};
+
+&soc {
+ led_flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pmi8937_flash0 &pmi8937_flash1>;
+ qcom,torch-source = <&pmi8937_torch0 &pmi8937_torch1>;
+ qcom,switch-source = <&pmi8937_switch>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
index 90226da..9b9cd47 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
@@ -22,3 +22,14 @@
&usb_otg {
extcon = <&qpnp_smbcharger>;
};
+
+&soc {
+ led_flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pmi8940_flash0 &pmi8940_flash1>;
+ qcom,torch-source = <&pmi8940_torch0 &pmi8940_torch1>;
+ qcom,switch-source = <&pmi8940_switch>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
index 3552055..65b2397 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
@@ -1400,6 +1400,66 @@
};
};
+ spi6 {
+ spi6_default: spi6_default {
+ /* active state */
+ mux {
+ /* MOSI, MISO, CLK */
+ pins = "gpio20", "gpio21", "gpio23";
+ function = "blsp_spi6";
+ };
+
+ config {
+ pins = "gpio20", "gpio21", "gpio23";
+ drive-strength = <12>; /* 12 MA */
+ bias-disable = <0>; /* No PULL */
+ };
+ };
+
+ spi6_sleep: spi6_sleep {
+ /* suspended state */
+ mux {
+ /* MOSI, MISO, CLK */
+ pins = "gpio20", "gpio21", "gpio23";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio20", "gpio21", "gpio23";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL Down */
+ };
+ };
+
+ spi6_cs0_active: cs0_active {
+ /* CS */
+ mux {
+ pins = "gpio22";
+ function = "blsp_spi6";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
+ spi6_cs0_sleep: cs0_sleep {
+ /* CS */
+ mux {
+ pins = "gpio22";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio22";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+ };
+
/* add pingrp for touchscreen */
pmx_ts_int_active {
ts_int_active: ts_int_active {
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index d12e04a..3ab3b2b 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -179,6 +179,7 @@
i2c3 = &i2c_3;
i2c5 = &i2c_5;
spi3 = &spi_3;
+ spi6 = &spi_6;
};
soc: soc {
@@ -700,6 +701,33 @@
qcom,master-id = <86>;
status = "disabled";
};
+
+ spi_6: spi@7af6000 { /* BLSP2 QUP2 */
+ compatible = "qcom,spi-qup-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "spi_physical", "spi_bam_physical";
+ reg = <0x7af6000 0x600>,
+ <0x7ac4000 0x1f000>;
+ interrupt-names = "spi_irq", "spi_bam_irq";
+ interrupts = <0 300 0>, <0 239 0>;
+ spi-max-frequency = <19200000>;
+ pinctrl-names = "spi_default", "spi_sleep";
+ pinctrl-0 = <&spi6_default &spi6_cs0_active>;
+ pinctrl-1 = <&spi6_sleep &spi6_cs0_sleep>;
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup2_spi_apps_clk>;
+ clock-names = "iface_clk", "core_clk";
+ qcom,infinite-mode = <0>;
+ qcom,use-bam;
+ qcom,use-pinctrl;
+ qcom,ver-reg-exists;
+ qcom,bam-consumer-pipe-index = <6>;
+ qcom,bam-producer-pipe-index = <7>;
+ qcom,master-id = <84>;
+ status = "disabled";
+ };
+
i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */
compatible = "qcom,i2c-msm-v2";
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts
index 44fae6a..76088af 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, 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,3 +32,47 @@
<0x0001001b 0x0102001a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&cam_cci {
+ /delete-node/ qcom,cam-sensor@1;
+ qcom,cam-sensor@1 {
+ cell-index = <1>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x1>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <90>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <180>;
+ eeprom-src = <&eeprom_rear_aux>;
+ cam_vio-supply = <&camera_vio_ldo>;
+ cam_vana-supply = <&camera_vana_ldo>;
+ cam_vdig-supply = <&camera_ldo>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <1352000 1800000 2850000 0>;
+ rgltr-max-voltage = <1352000 1800000 2850000 0>;
+ rgltr-load-current = <105000 0 80000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 28 0>;
+ gpio-reset = <1>;
+ gpio-req-tbl-num = <0 1>;
+ gpio-req-tbl-flags = <1 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET1";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts
index abc3f2d..47ea8f3 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,3 +26,47 @@
<0x0001001b 0x0102001a 0x0 0x0>,
<0x0001001b 0x0201011a 0x0 0x0>;
};
+
+&cam_cci {
+ /delete-node/ qcom,cam-sensor@1;
+ qcom,cam-sensor@1 {
+ cell-index = <1>;
+ compatible = "qcom,cam-sensor";
+ reg = <0x1>;
+ csiphy-sd-index = <1>;
+ sensor-position-roll = <90>;
+ sensor-position-pitch = <0>;
+ sensor-position-yaw = <180>;
+ eeprom-src = <&eeprom_rear_aux>;
+ cam_vio-supply = <&camera_vio_ldo>;
+ cam_vana-supply = <&camera_vana_ldo>;
+ cam_vdig-supply = <&camera_ldo>;
+ cam_clk-supply = <&titan_top_gdsc>;
+ regulator-names = "cam_vdig", "cam_vio", "cam_vana",
+ "cam_clk";
+ rgltr-cntrl-support;
+ rgltr-min-voltage = <1352000 1800000 2850000 0>;
+ rgltr-max-voltage = <1352000 1800000 2850000 0>;
+ rgltr-load-current = <105000 0 80000 0>;
+ gpio-no-mux = <0>;
+ pinctrl-names = "cam_default", "cam_suspend";
+ pinctrl-0 = <&cam_sensor_mclk0_active
+ &cam_sensor_rear2_active>;
+ pinctrl-1 = <&cam_sensor_mclk0_suspend
+ &cam_sensor_rear2_suspend>;
+ gpios = <&tlmm 13 0>,
+ <&tlmm 28 0>;
+ gpio-reset = <1>;
+ gpio-req-tbl-num = <0 1>;
+ gpio-req-tbl-flags = <1 0>;
+ gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET1";
+ sensor-mode = <0>;
+ cci-master = <1>;
+ status = "ok";
+ clocks = <&clock_camcc CAM_CC_MCLK0_CLK>;
+ clock-names = "cam_clk";
+ clock-cntl-level = "turbo";
+ clock-rates = <24000000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
index 414e8fe..42c3e83 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
@@ -477,17 +477,22 @@
qcom,cpr-quotient-adjustment =
<66 77 66>, /* SVSP/NOM/TUR:30/35/30 mV */
- <(-74) (-57) (-30)>, /* SVSP/NOM/TUR:-34/-26/-14 mV */
+ <(-74) 0 (-30)>, /* SVSP/NOM/TUR:-34/0/-14 mV */
<0 0 0>;
qcom,cpr-floor-to-ceiling-max-range =
- <50000 50000 50000 65000 65000>,
- <50000 50000 50000 65000 65000>,
- <50000 50000 50000 65000 65000>;
+ <50000 50000 65000 65000 65000>,
+ <50000 50000 65000 65000 65000>,
+ <50000 50000 65000 65000 65000>;
qcom,cpr-voltage-ceiling-override =
<(-1) (-1) 810000 845000 885000 960000 960000>;
+ qcom,cpr-virtual-corner-quotient-adjustment =
+ <0 0 0 0 0>,
+ <0 0 (-22) 0 0>, /* NOMP: -10 mV */
+ <0 0 0 0 0>;
+
qcom,cpr-enable;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
index 348ba6f..237152d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi
@@ -338,17 +338,17 @@
iova-mem-region-io {
/* IO region is approximately 3 GB */
iova-region-name = "io";
- iova-region-start = <0xd911000>;
- iova-region-len = <0xd26ef000>;
+ iova-region-start = <0xda00000>;
+ iova-region-len = <0xd2500000>;
iova-region-id = <0x3>;
status = "ok";
};
iova-mem-qdss-region {
- /* qdss region is approximately 64K */
+ /* qdss region is approximately 1MB */
iova-region-name = "qdss";
iova-region-start = <0xd900000>;
- iova-region-len = <0x10000>;
+ iova-region-len = <0x100000>;
iova-region-id = <0x5>;
qdss-phy-addr = <0x16790000>;
status = "ok";
@@ -911,6 +911,9 @@
cam_ipe0: qcom,ipe0 {
cell-index = <0>;
compatible = "qcom,cam-ipe";
+ reg = <0xac87000 0x3000>;
+ reg-names = "ipe0_top";
+ reg-cam-base = <0x87000>;
regulator-names = "ipe0-vdd";
ipe0-vdd-supply = <&ipe_0_gdsc>;
clock-names = "ipe_0_ahb_clk",
@@ -938,6 +941,9 @@
cam_ipe1: qcom,ipe1 {
cell-index = <1>;
compatible = "qcom,cam-ipe";
+ reg = <0xac91000 0x3000>;
+ reg-names = "ipe1_top";
+ reg-cam-base = <0x91000>;
regulator-names = "ipe1-vdd";
ipe1-vdd-supply = <&ipe_1_gdsc>;
clock-names = "ipe_1_ahb_clk",
@@ -965,6 +971,9 @@
cam_bps: qcom,bps {
cell-index = <0>;
compatible = "qcom,cam-bps";
+ reg = <0xac6f000 0x3000>;
+ reg-names = "bps_top";
+ reg-cam-base = <0x6f000>;
regulator-names = "bps-vdd";
bps-vdd-supply = <&bps_gdsc>;
clock-names = "bps_ahb_clk",
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
index a743373..5d62c5a 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi
@@ -27,6 +27,7 @@
#include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi"
#include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi"
#include "dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi"
+#include "dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi"
#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
&soc {
@@ -489,7 +490,30 @@
ibb-supply = <&lcdb_ncp_vreg>;
};
- ext_dsi_bridge_display: qcom,dsi-display@17 {
+ dsi_hx83112a_truly_video_display: qcom,dsi-display@17 {
+ compatible = "qcom,dsi-display";
+ label = "dsi_hx83112a_truly_video_display";
+ qcom,display-type = "primary";
+
+ qcom,dsi-ctrl = <&mdss_dsi0>;
+ qcom,dsi-phy = <&mdss_dsi_phy0>;
+ clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>,
+ <&mdss_dsi0_pll PCLK_MUX_0_CLK>;
+ clock-names = "src_byte_clk", "src_pixel_clk";
+
+ pinctrl-names = "panel_active", "panel_suspend";
+ pinctrl-0 = <&sde_dsi_active &sde_te_active>;
+ pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>;
+ qcom,platform-te-gpio = <&tlmm 10 0>;
+ qcom,platform-reset-gpio = <&tlmm 75 0>;
+
+ qcom,dsi-panel = <&dsi_hx83112a_truly_video>;
+ vddio-supply = <&pm660_l11>;
+ lab-supply = <&lcdb_ldo_vreg>;
+ ibb-supply = <&lcdb_ncp_vreg>;
+ };
+
+ ext_dsi_bridge_display: qcom,dsi-display@18 {
compatible = "qcom,dsi-display";
label = "ext_dsi_bridge_display";
qcom,display-type = "primary";
@@ -561,7 +585,7 @@
qcom,mdss-dsi-display-timings {
timing@0{
qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
- 07 05 03 04 00];
+ 07 05 02 04 00];
qcom,display-topology = <2 0 2>,
<1 0 2>;
qcom,default-topology-index = <0>;
@@ -583,7 +607,7 @@
qcom,mdss-dsi-display-timings {
timing@0{
qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
- 07 05 03 04 00];
+ 07 05 02 04 00];
qcom,display-topology = <2 0 2>,
<1 0 2>;
qcom,default-topology-index = <0>;
@@ -607,7 +631,7 @@
qcom,mdss-dsi-display-timings {
timing@0{
qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
- 05 03 03 04 00];
+ 05 03 02 04 00];
qcom,display-topology = <1 1 1>,
<2 2 1>, /* dsc merge */
<2 1 1>; /* 3d mux */
@@ -634,7 +658,7 @@
qcom,mdss-dsi-display-timings {
timing@0{
qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
- 04 03 03 04 00];
+ 04 03 02 04 00];
qcom,display-topology = <1 1 1>,
<2 2 1>, /* dsc merge */
<2 1 1>; /* 3d mux */
@@ -649,7 +673,7 @@
qcom,mdss-dsi-display-timings {
timing@0{
qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
- 07 05 03 04 00];
+ 07 05 02 04 00];
qcom,display-topology = <1 0 1>,
<2 0 1>;
qcom,default-topology-index = <0>;
@@ -663,7 +687,7 @@
qcom,mdss-dsi-display-timings {
timing@0{
qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
- 07 05 03 04 00];
+ 07 05 02 04 00];
qcom,display-topology = <2 0 2>,
<1 0 2>;
qcom,default-topology-index = <0>;
@@ -682,7 +706,7 @@
qcom,panel-roi-alignment = <720 40 720 40 720 40>;
qcom,partial-update-enabled = "single_roi";
qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07
- 07 04 03 04 00];
+ 07 04 02 04 00];
};
timing@1{
qcom,display-topology = <1 0 1>,
@@ -691,7 +715,7 @@
qcom,panel-roi-alignment = <540 40 540 40 540 40>;
qcom,partial-update-enabled = "single_roi";
qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07
- 07 04 03 04 00];
+ 07 04 02 04 00];
};
timing@2{
qcom,display-topology = <1 0 1>,
@@ -700,7 +724,7 @@
qcom,panel-roi-alignment = <360 40 360 40 360 40>;
qcom,partial-update-enabled = "single_roi";
qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07
- 07 04 03 04 00];
+ 07 04 02 04 00];
};
};
};
@@ -711,20 +735,20 @@
qcom,mdss-dsi-display-timings {
timing@0{
qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09
- 09 06 03 04 00];
+ 09 06 02 04 00];
qcom,display-topology = <2 0 2>;
qcom,default-topology-index = <0>;
};
timing@1{
qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
- 07 05 03 04 00];
+ 07 05 02 04 00];
qcom,display-topology = <2 0 2>,
<1 0 2>;
qcom,default-topology-index = <0>;
};
timing@2{
qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
- 06 04 03 04 00];
+ 06 04 02 04 00];
qcom,display-topology = <2 0 2>;
qcom,default-topology-index = <0>;
};
@@ -737,13 +761,13 @@
qcom,mdss-dsi-display-timings {
timing@0 { /* 1080p */
qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07
- 07 04 03 04 00];
+ 07 04 02 04 00];
qcom,display-topology = <1 1 1>;
qcom,default-topology-index = <0>;
};
timing@1 { /* qhd */
qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05
- 05 03 03 04 00];
+ 05 03 02 04 00];
qcom,display-topology = <1 1 1>,
<2 2 1>, /* dsc merge */
<2 1 1>; /* 3d mux */
@@ -758,13 +782,13 @@
qcom,mdss-dsi-display-timings {
timing@0 { /* qhd */
qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
- 07 05 03 04 00];
+ 07 05 02 04 00];
qcom,display-topology = <2 2 2>;
qcom,default-topology-index = <0>;
};
timing@1 { /* 4k */
qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06
- 06 04 03 04 00];
+ 06 04 02 04 00];
qcom,display-topology = <2 2 2>;
qcom,default-topology-index = <0>;
};
@@ -777,7 +801,7 @@
qcom,mdss-dsi-display-timings {
timing@0 {
qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
- 07 05 03 04 00];
+ 07 05 02 04 00];
qcom,display-topology = <2 0 2>,
<1 0 2>;
qcom,default-topology-index = <0>;
@@ -792,7 +816,7 @@
qcom,mdss-dsi-display-timings {
timing@0 {
qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07
- 07 05 03 04 00];
+ 07 05 02 04 00];
qcom,display-topology = <2 0 2>,
<1 0 2>;
qcom,default-topology-index = <0>;
@@ -808,7 +832,7 @@
qcom,mdss-dsi-display-timings {
timing@0 {
qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c
- 05 07 05 03 04 00];
+ 05 07 05 02 04 00];
qcom,display-topology = <1 0 1>;
qcom,default-topology-index = <0>;
};
@@ -826,7 +850,7 @@
qcom,mdss-dsi-display-timings {
timing@0 {
qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c
- 05 07 05 03 04 00];
+ 05 07 05 02 04 00];
qcom,display-topology = <1 0 1>;
qcom,default-topology-index = <0>;
};
@@ -841,7 +865,7 @@
qcom,mdss-dsi-display-timings {
timing@0 {
qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22
- 07 07 05 03 04 00];
+ 07 07 05 02 04 00];
qcom,display-topology = <1 0 1>;
qcom,default-topology-index = <0>;
};
@@ -862,7 +886,7 @@
qcom,mdss-dsi-display-timings {
timing@0{
qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08
- 08 05 03 04 00];
+ 08 05 02 04 00];
qcom,display-topology = <2 0 2>,
<1 0 2>;
qcom,default-topology-index = <0>;
@@ -888,7 +912,32 @@
qcom,mdss-dsi-display-timings {
timing@0 {
qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08
- 08 05 03 04 00];
+ 08 05 02 04 00];
+ qcom,display-topology = <1 0 1>;
+ qcom,default-topology-index = <0>;
+ };
+ };
+};
+
+&dsi_hx83112a_truly_video {
+ qcom,mdss-dsi-t-clk-post = <0x0E>;
+ qcom,mdss-dsi-t-clk-pre = <0x30>;
+
+ qcom,mdss-dsi-min-refresh-rate = <55>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-status-read-length = <4>;
+
+ qcom,mdss-dsi-display-timings {
+ timing@0 {
+ qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08
+ 08 05 02 04 00];
qcom,display-topology = <1 0 1>;
qcom,default-topology-index = <0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index 2e2de74..e77dcc3 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
@@ -311,17 +311,17 @@
iova-mem-region-io {
/* IO region is approximately 3 GB */
iova-region-name = "io";
- iova-region-start = <0xd911000>;
- iova-region-len = <0xd26ef000>;
+ iova-region-start = <0xda00000>;
+ iova-region-len = <0xd2500000>;
iova-region-id = <0x3>;
status = "ok";
};
iova-mem-qdss-region {
- /* qdss region is approximately 64K */
+ /* qdss region is approximately 1MB */
iova-region-name = "qdss";
iova-region-start = <0xd900000>;
- iova-region-len = <0x10000>;
+ iova-region-len = <0x100000>;
iova-region-id = <0x5>;
qdss-phy-addr = <0x16790000>;
status = "ok";
@@ -881,6 +881,9 @@
cam_ipe0: qcom,ipe0 {
cell-index = <0>;
compatible = "qcom,cam-ipe";
+ reg = <0xac87000 0x3000>;
+ reg-names = "ipe0_top";
+ reg-cam-base = <0x87000>;
regulator-names = "ipe0-vdd";
ipe0-vdd-supply = <&ipe_0_gdsc>;
clock-names = "ipe_0_ahb_clk",
@@ -908,6 +911,9 @@
cam_ipe1: qcom,ipe1 {
cell-index = <1>;
compatible = "qcom,cam-ipe";
+ reg = <0xac91000 0x3000>;
+ reg-names = "ipe1_top";
+ reg-cam-base = <0x91000>;
regulator-names = "ipe1-vdd";
ipe1-vdd-supply = <&ipe_1_gdsc>;
clock-names = "ipe_1_ahb_clk",
@@ -935,6 +941,9 @@
cam_bps: qcom,bps {
cell-index = <0>;
compatible = "qcom,cam-bps";
+ reg = <0xac6f000 0x3000>;
+ reg-names = "bps_top";
+ reg-cam-base = <0x6f000>;
regulator-names = "bps-vdd";
bps-vdd-supply = <&bps_gdsc>;
clock-names = "bps_ahb_clk",
diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
index 97cb981..c9669d9 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi
@@ -248,17 +248,17 @@
iova-mem-region-io {
/* IO region is approximately 3 GB */
iova-region-name = "io";
- iova-region-start = <0xd911000>;
- iova-region-len = <0xd26ef000>;
+ iova-region-start = <0xda00000>;
+ iova-region-len = <0xd2500000>;
iova-region-id = <0x3>;
status = "ok";
};
iova-mem-qdss-region {
- /* qdss region is approximately 64K */
+ /* qdss region is approximately 1MB */
iova-region-name = "qdss";
iova-region-start = <0xd900000>;
- iova-region-len = <0x10000>;
+ iova-region-len = <0x100000>;
iova-region-id = <0x5>;
qdss-phy-addr = <0x16790000>;
status = "ok";
diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig
index be3fae7..bf35544 100644
--- a/arch/arm64/configs/msm8937-perf_defconfig
+++ b/arch/arm64/configs/msm8937-perf_defconfig
@@ -591,6 +591,9 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
@@ -622,12 +625,12 @@
CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig
index ebcc83e..ba390c4 100644
--- a/arch/arm64/configs/msm8937_defconfig
+++ b/arch/arm64/configs/msm8937_defconfig
@@ -610,6 +610,9 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
@@ -688,12 +691,12 @@
CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index fca320e..eeb1d74 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -604,6 +604,9 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
@@ -635,12 +638,12 @@
CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index a3547be..d0783cd 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -623,6 +623,9 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
@@ -702,12 +705,12 @@
CONFIG_CORESIGHT_CTI=y
CONFIG_CORESIGHT_EVENT=y
CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_PFK=y
CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
CONFIG_SECURITY=y
CONFIG_HARDENED_USERCOPY=y
CONFIG_SECURITY_SELINUX=y
CONFIG_SECURITY_SMACK=y
-CONFIG_CRYPTO_CTR=y
CONFIG_CRYPTO_XCBC=y
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_TWOFISH=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index e35e571..0c54182 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -520,6 +520,7 @@
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_MINIDUMP=y
CONFIG_QCOM_BUS_SCALING=y
CONFIG_QCOM_BUS_CONFIG_RPMH=y
CONFIG_QCOM_SECURE_BUFFER=y
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index 065b765..fff2ae9 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -2564,22 +2564,6 @@
return arm_iommu_create_mapping(&platform_bus_type, base, size);
}
-static int gpi_dma_mask(struct gpi_dev *gpi_dev)
-{
- int mask = 64;
-
- if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) {
- unsigned long addr;
-
- addr = gpi_dev->iova_base + gpi_dev->iova_size + 1;
- mask = find_last_bit(&addr, 64);
- }
-
- GPI_LOG(gpi_dev, "Setting dma mask to %d\n", mask);
-
- return dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(mask));
-}
-
static int gpi_smmu_init(struct gpi_dev *gpi_dev)
{
struct dma_iommu_mapping *mapping = NULL;
@@ -2643,9 +2627,10 @@
}
}
- ret = gpi_dma_mask(gpi_dev);
+ GPI_LOG(gpi_dev, "Setting dma mask to 64\n");
+ ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64));
if (ret) {
- GPI_ERR(gpi_dev, "Error setting dma_mask, ret:%d\n", ret);
+ GPI_ERR(gpi_dev, "Error setting dma_mask to 64, ret:%d\n", ret);
goto error_set_mask;
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index f0ea211..1880ad1 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -377,7 +377,7 @@
if (r_config->sequence[i].sleep_ms)
usleep_range(r_config->sequence[i].sleep_ms * 1000,
- r_config->sequence[i].sleep_ms * 1000);
+ (r_config->sequence[i].sleep_ms * 1000) + 100);
}
if (gpio_is_valid(panel->bl_config.en_gpio)) {
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c
index 3da0fc3..45f7577 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c
@@ -113,7 +113,7 @@
else
timing->lane[i][4] = desc->hs_rqst.reg_value;
- timing->lane[i][5] = 0x3;
+ timing->lane[i][5] = 0x2;
timing->lane[i][6] = 0x4;
timing->lane[i][7] = 0xA0;
pr_debug("[%d][%d %d %d %d %d]\n", i, timing->lane[i][0],
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c
index 4392c60..c0e9d44 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c
@@ -92,7 +92,7 @@
timing->lane_v3[6] = desc->hs_prepare.reg_value;
timing->lane_v3[7] = desc->hs_trail.reg_value;
timing->lane_v3[8] = desc->hs_rqst.reg_value;
- timing->lane_v3[9] = 0x03;
+ timing->lane_v3[9] = 0x02;
timing->lane_v3[10] = 0x04;
timing->lane_v3[11] = 0x00;
diff --git a/drivers/gpu/drm/msm/sde_io_util.c b/drivers/gpu/drm/msm/sde_io_util.c
index d5a438e..f830010 100644
--- a/drivers/gpu/drm/msm/sde_io_util.c
+++ b/drivers/gpu/drm/msm/sde_io_util.c
@@ -1,4 +1,5 @@
-/* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, 2017, 2018, 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
@@ -230,7 +231,7 @@
need_sleep = !regulator_is_enabled(in_vreg[i].vreg);
if (in_vreg[i].pre_on_sleep && need_sleep)
usleep_range(in_vreg[i].pre_on_sleep * 1000,
- in_vreg[i].pre_on_sleep * 1000);
+ (in_vreg[i].pre_on_sleep * 1000) + 10);
rc = regulator_set_load(in_vreg[i].vreg,
in_vreg[i].enable_load);
if (rc < 0) {
@@ -242,7 +243,7 @@
rc = regulator_enable(in_vreg[i].vreg);
if (in_vreg[i].post_on_sleep && need_sleep)
usleep_range(in_vreg[i].post_on_sleep * 1000,
- in_vreg[i].post_on_sleep * 1000);
+ (in_vreg[i].post_on_sleep * 1000) + 10);
if (rc < 0) {
DEV_ERR("%pS->%s: %s enable failed\n",
__builtin_return_address(0), __func__,
@@ -254,13 +255,13 @@
for (i = num_vreg-1; i >= 0; i--) {
if (in_vreg[i].pre_off_sleep)
usleep_range(in_vreg[i].pre_off_sleep * 1000,
- in_vreg[i].pre_off_sleep * 1000);
+ (in_vreg[i].pre_off_sleep * 1000) + 10);
regulator_set_load(in_vreg[i].vreg,
in_vreg[i].disable_load);
regulator_disable(in_vreg[i].vreg);
if (in_vreg[i].post_off_sleep)
usleep_range(in_vreg[i].post_off_sleep * 1000,
- in_vreg[i].post_off_sleep * 1000);
+ (in_vreg[i].post_off_sleep * 1000) + 10);
}
}
return rc;
@@ -272,13 +273,13 @@
for (i--; i >= 0; i--) {
if (in_vreg[i].pre_off_sleep)
usleep_range(in_vreg[i].pre_off_sleep * 1000,
- in_vreg[i].pre_off_sleep * 1000);
+ (in_vreg[i].pre_off_sleep * 1000) + 10);
regulator_set_load(in_vreg[i].vreg,
in_vreg[i].disable_load);
regulator_disable(in_vreg[i].vreg);
if (in_vreg[i].post_off_sleep)
usleep_range(in_vreg[i].post_off_sleep * 1000,
- in_vreg[i].post_off_sleep * 1000);
+ (in_vreg[i].post_off_sleep * 1000) + 10);
}
return rc;
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
index 26cee2e..34508b2 100644
--- a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
@@ -963,6 +963,8 @@
struct vl_data *data = dev_get_drvdata(dev);
struct VL_RangingMeasurementData_t Measure;
+ if (data->enable_ps_sensor == 0)
+ return -ENODEV;
papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure);
return snprintf(buf, 7, "%d\n", Measure.RangeMilliMeter);
}
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6c4156a..e9c1d69 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1279,6 +1279,18 @@
If unsure, say N.
+config TOUCHSCREEN_GT9XX_v28
+ bool "Goodix touchpanel GT9xx_v28 series"
+ depends on I2C
+ help
+ Say Y here if you have a Goodix GT9xx_v28 touchscreen.
+ Gt9xx controllers are multi touch controllers which can
+ report 5 touches at a time.
+
+ If unsure, say N.
+
+source "drivers/input/touchscreen/gt9xx_v2.8/Kconfig"
+
config TOUCHSCREEN_HIMAX_CHIPSET
bool "Himax touchpanel CHIPSET"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index a5952ca..c8e0104 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -105,3 +105,4 @@
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/
obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/
+obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx_v2.8/
\ No newline at end of file
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/Kconfig b/drivers/input/touchscreen/gt9xx_v2.8/Kconfig
new file mode 100644
index 0000000..7046cc9
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/Kconfig
@@ -0,0 +1,36 @@
+#
+# Goodix GT9xx Touchscreen driver
+#
+config TOUCHSCREEN_GT9XX_v28
+ bool "Goodix touchpanel GT9xx series"
+ depends on I2C
+ help
+ Enable this for support Goodix GT9xx_v28 driver.
+
+ Say Y here if you have a Goodix GT9xx touchscreen
+ controller.
+
+ If unsure, say N.
+
+config TOUCHSCREEN_GT9XX_UPDATE
+ tristate "Goodix GT9xx touch controller auto update support"
+ depends on TOUCHSCREEN_GT9XX_v28
+ help
+ Enable this for support firmware update.
+
+ Say Y here if you want update touch controller
+ firmware.
+
+ If unsure, say N.
+
+config TOUCHSCREEN_GT9XX_TOOL
+ tristate "Goodix GT9xx Tools for debuging"
+ depends on TOUCHSCREEN_GT9XX_v28
+ help
+ This implement interface support for Goodix GT9xx
+ touchscreen debug.
+
+ Say Y here if you want to have a Android app debug interface
+ to your system.
+
+ If unsure, say N.
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/Makefile b/drivers/input/touchscreen/gt9xx_v2.8/Makefile
new file mode 100644
index 0000000..6c1c404
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Goodix gt9xx touchscreen driver.
+#
+#subdir-ccflags-y += -DDEBUG
+obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx.o
+obj-$(CONFIG_TOUCHSCREEN_GT9XX_UPDATE) += gt9xx_update.o
+obj-$(CONFIG_TOUCHSCREEN_GT9XX_TOOL) += goodix_tool.o
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c b/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c
new file mode 100644
index 0000000..7db5ae2
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c
@@ -0,0 +1,529 @@
+/*
+ * Goodix GT9xx touchscreen driver
+ *
+ * Copyright (C) 2016 - 2017 Goodix. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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 "gt9xx.h"
+
+#define DATA_LENGTH_UINT 512
+#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8 *))
+static char procname[20] = {0};
+
+#pragma pack(1)
+struct st_cmd_head {
+ u8 wr; /*write read flag 0:R 1:W 2:PID 3:*/
+ u8 flag; /*0:no need flag/int 1: need flag 2:need int*/
+ u8 flag_addr[2]; /*flag address*/
+ u8 flag_val; /*flag val*/
+ u8 flag_relation; /*flag_val:flag 0:not equal 1:equal 2:> 3:<*/
+ u16 circle; /*polling cycle*/
+ u8 times; /*plling times*/
+ u8 retry; /*I2C retry times*/
+ u16 delay; /*delay before read or after write*/
+ u16 data_len; /*data length*/
+ u8 addr_len; /*address length*/
+ u8 addr[2]; /*address*/
+ u8 res[3]; /*reserved*/
+ u8 *data; }; /*data pointer*/
+#pragma pack()
+struct st_cmd_head cmd_head;
+
+static struct i2c_client *gt_client;
+static struct proc_dir_entry *goodix_proc_entry;
+
+static ssize_t goodix_tool_read(struct file *, char __user *, size_t, loff_t *);
+static ssize_t goodix_tool_write(struct file *, const char __user *,
+ size_t, loff_t *);
+static const struct file_operations gtp_proc_ops = {
+ .owner = THIS_MODULE,
+ .read = goodix_tool_read,
+ .write = goodix_tool_write,
+};
+
+/* static s32 goodix_tool_write(struct file *filp,
+ * const char __user *buff, unsigned long len, void *data);
+ */
+/*static s32 goodix_tool_read( char *page, char
+ **start, off_t off, int count, int *eof, void *data );
+ */
+static s32 (*tool_i2c_read)(u8 *, u16);
+static s32 (*tool_i2c_write)(u8 *, u16);
+
+static s32 DATA_LENGTH = (s32)0;
+static s8 IC_TYPE[16] = "GT9XX";
+
+static void tool_set_proc_name(char *procname)
+{
+ snprintf(procname, 20, "gmnode"); /* modify for moto */
+}
+
+static s32 tool_i2c_read_no_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
+
+ for (i = 0; i < cmd_head.retry; i++) {
+ ret = gtp_i2c_read(ts->client, buf, len + GTP_ADDR_LENGTH);
+ if (ret > 0)
+ break;
+ }
+ return ret;
+}
+
+static s32 tool_i2c_write_no_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ s32 i = 0;
+ struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
+
+ for (i = 0; i < cmd_head.retry; i++) {
+ ret = gtp_i2c_write(ts->client, buf, len);
+ if (ret > 0)
+ break;
+ }
+
+ return ret;
+}
+
+static s32 tool_i2c_read_with_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_read_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static s32 tool_i2c_write_with_extra(u8 *buf, u16 len)
+{
+ s32 ret = -1;
+ u8 pre[2] = {0x0f, 0xff};
+ u8 end[2] = {0x80, 0x00};
+
+ tool_i2c_write_no_extra(pre, 2);
+ ret = tool_i2c_write_no_extra(buf, len);
+ tool_i2c_write_no_extra(end, 2);
+
+ return ret;
+}
+
+static void register_i2c_func(void)
+{
+ /* if (!strcmp(IC_TYPE, "GT818", 5)
+ * || !strcmp(IC_TYPE, "GT816", 5)
+ * || !strcmp(IC_TYPE, "GT811", 5)
+ * || !strcmp(IC_TYPE, "GT818F", 6)
+ * || !strcmp(IC_TYPE, "GT827", 5)
+ * || !strcmp(IC_TYPE,"GT828", 5)
+ * || !strcmp(IC_TYPE, "GT813", 5))
+ */
+ if (strcmp(IC_TYPE, "GT8110") &&
+ strcmp(IC_TYPE, "GT8105") &&
+ strcmp(IC_TYPE, "GT801") &&
+ strcmp(IC_TYPE, "GT800") &&
+ strcmp(IC_TYPE, "GT801PLUS") &&
+ strcmp(IC_TYPE, "GT811") &&
+ strcmp(IC_TYPE, "GTxxx") &&
+ strcmp(IC_TYPE, "GT9XX")) {
+ tool_i2c_read = tool_i2c_read_with_extra;
+ tool_i2c_write = tool_i2c_write_with_extra;
+ dev_dbg(>_client->dev, "I2C function: with pre and end cmd!");
+ } else {
+ tool_i2c_read = tool_i2c_read_no_extra;
+ tool_i2c_write = tool_i2c_write_no_extra;
+ dev_info(>_client->dev, "I2C function: without pre and end cmd!");
+ }
+}
+
+static void unregister_i2c_func(void)
+{
+ tool_i2c_read = NULL;
+ tool_i2c_write = NULL;
+ dev_info(>_client->dev, "I2C function: unregister i2c transfer function!");
+}
+
+s32 init_wr_node(struct i2c_client *client)
+{
+ s32 i;
+
+ gt_client = client;
+ memset(&cmd_head, 0, sizeof(cmd_head));
+ cmd_head.data = NULL;
+
+ i = 6;
+ while ((!cmd_head.data) && i) {
+ cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL);
+ if (cmd_head.data)
+ break;
+ i--;
+ }
+ if (i) {
+ DATA_LENGTH = i * DATA_LENGTH_UINT - GTP_ADDR_LENGTH;
+ dev_info(>_client->dev,
+ "Alloc memory size:%d.", DATA_LENGTH);
+ } else {
+ dev_err(>_client->dev, "Apply for memory failed.");
+ return FAIL;
+ }
+
+ cmd_head.addr_len = 2;
+ cmd_head.retry = 5;
+
+ register_i2c_func();
+
+ tool_set_proc_name(procname);
+ goodix_proc_entry = proc_create(procname, 0664, NULL, >p_proc_ops);
+ if (!goodix_proc_entry) {
+ dev_err(>_client->dev, "Couldn't create proc entry!");
+ return FAIL;
+ }
+
+ dev_info(>_client->dev, "Create proc entry success!");
+ return SUCCESS;
+}
+
+void uninit_wr_node(void)
+{
+ kfree(cmd_head.data);
+ cmd_head.data = NULL;
+ unregister_i2c_func();
+ remove_proc_entry(procname, NULL);
+}
+
+static u8 relation(u8 src, u8 dst, u8 rlt)
+{
+ u8 ret = 0;
+
+ switch (rlt) {
+ case 0:
+ ret = (src != dst) ? true : false;
+ break;
+
+ case 1:
+ ret = (src == dst) ? true : false;
+ dev_dbg(>_client->dev,
+ "equal:src:0x%02x dst:0x%02x ret:%d.",
+ src, dst, (s32)ret);
+ break;
+
+ case 2:
+ ret = (src > dst) ? true : false;
+ break;
+
+ case 3:
+ ret = (src < dst) ? true : false;
+ break;
+
+ case 4:
+ ret = (src & dst) ? true : false;
+ break;
+
+ case 5:
+ ret = (!(src | dst)) ? true : false;
+ break;
+
+ default:
+ ret = false;
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************
+ * Function:
+ * Comfirm function.
+ * Input:
+ * None.
+ * Output:
+ * Return write length.
+ ********************************************************/
+static u8 comfirm(void)
+{
+ s32 i = 0;
+ u8 buf[32];
+
+ memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
+
+ for (i = 0; i < cmd_head.times; i++) {
+ if (tool_i2c_read(buf, 1) <= 0) {
+ dev_err(>_client->dev, "Read flag data failed!");
+ return FAIL;
+ }
+ if (true == relation(buf[GTP_ADDR_LENGTH],
+ cmd_head.flag_val, cmd_head.flag_relation)) {
+ dev_dbg(>_client->dev, "value at flag addr:0x%02x.",
+ buf[GTP_ADDR_LENGTH]);
+ dev_dbg(>_client->dev, "flag value:0x%02x.",
+ cmd_head.flag_val);
+ break;
+ }
+
+ msleep(cmd_head.circle);
+ }
+
+ if (i >= cmd_head.times) {
+ dev_err(>_client->dev, "Can't get the continue flag!");
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+ssize_t goodix_tool_write(struct file *filp, const char __user *buff,
+ size_t len, loff_t *off)
+{
+ s32 ret = 0;
+ struct goodix_ts_data *ts = i2c_get_clientdata(gt_client);
+
+ ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
+ if (ret) {
+ dev_err(>_client->dev, "copy_from_user failed.");
+ return -EPERM;
+ }
+
+ dev_dbg(>_client->dev, "[Operation]wr: %02X", cmd_head.wr);
+ dev_dbg(>_client->dev,
+ "[Flag]flag: %02X,addr: %02X%02X,value: %02X,relation: %02X",
+ cmd_head.flag, cmd_head.flag_addr[0],
+ cmd_head.flag_addr[1], cmd_head.flag_val,
+ cmd_head.flag_relation);
+ dev_dbg(>_client->dev,
+ "[Retry]circle: %d,times: %d,retry: %d, delay: %d",
+ (s32)cmd_head.circle,
+ (s32)cmd_head.times, (s32)cmd_head.retry,
+ (s32)cmd_head.delay);
+
+ if (cmd_head.wr == 1) {
+ if (cmd_head.data_len > DATA_LENGTH) {
+ dev_err(>_client->dev,
+ "Tool write failed data too long");
+ return -EPERM;
+ }
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+ &buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+ if (ret) {
+ dev_err(>_client->dev, "copy_from_user failed.");
+ return -EPERM;
+ }
+ memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len],
+ cmd_head.addr, cmd_head.addr_len);
+
+ GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len +
+ cmd_head.addr_len);
+
+ if (cmd_head.flag == 1) {
+ if (comfirm() == FAIL) {
+ dev_err(>_client->dev,
+ "[WRITE]Comfirm fail!");
+ return -EPERM;
+ }
+ } else if (cmd_head.flag == 2) {
+ /*Need interrupt!*/
+ }
+ if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH -
+ cmd_head.addr_len], cmd_head.data_len +
+ cmd_head.addr_len) <= 0) {
+ dev_err(>_client->dev, "[WRITE]Write data failed!");
+ return -EPERM;
+ }
+
+ GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH -
+ cmd_head.addr_len],
+ cmd_head.data_len + cmd_head.addr_len);
+ if (cmd_head.delay)
+ msleep(cmd_head.delay);
+ } else if (cmd_head.wr == 3) {
+ if (cmd_head.data_len > DATA_LENGTH) {
+ dev_err(>_client->dev,
+ "Tool write failed data too long");
+ return -EPERM;
+ }
+ ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+ if (ret) {
+ dev_err(>_client->dev, "copy_from_user failed.");
+ return -EPERM;
+ }
+ memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);
+
+ register_i2c_func();
+ } else if (cmd_head.wr == 5) {
+ /*memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);*/
+ } else if (cmd_head.wr == 7) {/*disable irq!*/
+ gtp_work_control_enable(i2c_get_clientdata(gt_client), false);
+
+ if (ts->pdata->esd_protect)
+ gtp_esd_off(ts);
+ } else if (cmd_head.wr == 9) {/*enable irq!*/
+ gtp_work_control_enable(i2c_get_clientdata(gt_client), true);
+
+ if (ts->pdata->esd_protect)
+ gtp_esd_on(ts);
+ } else if (cmd_head.wr == 17) {
+ if (cmd_head.data_len > DATA_LENGTH) {
+ dev_err(>_client->dev,
+ "Tool write failed data too long");
+ return -EPERM;
+ }
+ ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH],
+ &buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+ if (ret) {
+ dev_dbg(>_client->dev, "copy_from_user failed.");
+ return -EPERM;
+ }
+ if (cmd_head.data[GTP_ADDR_LENGTH]) {
+ dev_info(>_client->dev, "gtp enter rawdiff.");
+ set_bit(RAW_DATA_MODE, &ts->flags);
+ } else {
+ clear_bit(RAW_DATA_MODE, &ts->flags);
+ dev_info(>_client->dev, "gtp leave rawdiff.");
+ }
+ } else if (cmd_head.wr == 19) {
+ /* add new command: reset guitar */
+ gtp_reset_guitar(gt_client, 20);
+ }
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+ else if (cmd_head.wr == 11) {/*Enter update mode!*/
+ if (gup_enter_update_mode(gt_client) == FAIL)
+ return -EPERM;
+ } else if (cmd_head.wr == 13) {/*Leave update mode!*/
+ gup_leave_update_mode(gt_client);
+ } else if (cmd_head.wr == 15) {/*Update firmware!*/
+ show_len = 0;
+ total_len = 0;
+ if (cmd_head.data_len > DATA_LENGTH) {
+ dev_err(>_client->dev,
+ "Tool write failed data too long");
+ return -EPERM;
+ }
+ memset(cmd_head.data, 0, DATA_LENGTH);
+ ret = copy_from_user(cmd_head.data,
+ &buff[CMD_HEAD_LENGTH],
+ cmd_head.data_len);
+ if (ret) {
+ dev_dbg(>_client->dev, "copy_from_user failed.");
+ return -EPERM;
+ }
+
+ if (gup_update_proc((void *)cmd_head.data) == FAIL)
+ return -EPERM;
+ }
+#endif
+
+ return len;
+}
+
+/*******************************************************
+ * Function:
+ * Goodix tool read function.
+ * Input:
+ * standard proc read function param.
+ * Output:
+ * Return read length.
+ ********************************************************/
+ssize_t goodix_tool_read(struct file *file, char __user *page,
+ size_t size, loff_t *ppos)
+{
+ s32 ret = 0;
+
+ if (*ppos) {
+ /* ADB call again
+ * dev_dbg(>_client->dev, "[HEAD]wr: %d", cmd_head.wr);
+ * dev_dbg(>_client->dev,
+ * "[PARAM]size: %d, *ppos: %d", size, (int)*ppos);
+ * dev_dbg(>_client->dev,
+ * "[TOOL_READ]ADB call again, return it.");
+ */
+ *ppos = 0;
+ return 0;
+ }
+
+ if (cmd_head.wr % 2) {
+ return -EPERM;
+ } else if (!cmd_head.wr) {
+ u16 len, data_len, loc, addr;
+
+ if (cmd_head.flag == 1) {
+ if (comfirm() == FAIL) {
+ dev_err(>_client->dev, "[READ]Comfirm fail!");
+ return -EPERM;
+ }
+ } else if (cmd_head.flag == 2) {
+ /*Need interrupt!*/
+ }
+
+ if (cmd_head.delay)
+ msleep(cmd_head.delay);
+
+ data_len = cmd_head.data_len;
+ addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1];
+ loc = 0;
+
+ while (data_len > 0) {
+ len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len;
+ cmd_head.data[0] = (addr >> 8) & 0xFF;
+ cmd_head.data[1] = (addr & 0xFF);
+ if (tool_i2c_read(cmd_head.data, len) <= 0) {
+ dev_err(>_client->dev, "[READ]Read data failed!");
+ return -EPERM;
+ }
+ ret = simple_read_from_buffer(&page[loc], size, ppos,
+ &cmd_head.data[GTP_ADDR_LENGTH], len);
+ if (ret < 0)
+ return ret;
+ loc += len;
+ addr += len;
+ data_len -= len;
+ }
+ return cmd_head.data_len;
+ } else if (cmd_head.wr == 2) {
+ ret = simple_read_from_buffer(page, size, ppos,
+ IC_TYPE, sizeof(IC_TYPE));
+ return ret;
+ }
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+ else if (cmd_head.wr == 4) {
+ u8 progress_buf[4];
+
+ progress_buf[0] = show_len >> 8;
+ progress_buf[1] = show_len & 0xff;
+ progress_buf[2] = total_len >> 8;
+ progress_buf[3] = total_len & 0xff;
+
+ ret = simple_read_from_buffer(page, size, ppos,
+ progress_buf, 4);
+ return ret;
+ }
+#endif
+ else if (cmd_head.wr == 6) {
+ /*Read error code!*/
+ } else if (cmd_head.wr == 8) { /*Read driver version*/
+ ret = simple_read_from_buffer(page, size, ppos,
+ GTP_DRIVER_VERSION,
+ strlen(GTP_DRIVER_VERSION));
+ return ret;
+ }
+
+ return -EPERM;
+}
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c
new file mode 100644
index 0000000..03328d0
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c
@@ -0,0 +1,2678 @@
+/*
+ * Goodix GT9xx touchscreen driver
+ *
+ * Copyright (C) 2016 - 2017 Goodix. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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/irq.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/input/mt.h>
+#include "gt9xx.h"
+
+#define GOODIX_VTG_MIN_UV 2600000
+#define GOODIX_VTG_MAX_UV 3300000
+#define GOODIX_I2C_VTG_MIN_UV 1800000
+#define GOODIX_I2C_VTG_MAX_UV 1800000
+
+#define DELAY_FOR_DISCHARGING 35
+#define GOODIX_COORDS_ARR_SIZE 4
+#define PROP_NAME_SIZE 24
+#define I2C_MAX_TRANSFER_SIZE 255
+#define GTP_PEN_BUTTON1 BTN_STYLUS
+#define GTP_PEN_BUTTON2 BTN_STYLUS2
+
+static const char *goodix_ts_name = "goodix-ts";
+static const char *goodix_input_phys = "input/ts";
+struct i2c_client *i2c_connect_client;
+static struct proc_dir_entry *gtp_config_proc;
+
+enum doze {
+ DOZE_DISABLED = 0,
+ DOZE_ENABLED = 1,
+ DOZE_WAKEUP = 2,
+};
+
+static enum doze doze_status = DOZE_DISABLED;
+
+static int gtp_i2c_test(struct i2c_client *client);
+static int gtp_enter_doze(struct goodix_ts_data *ts);
+
+static int gtp_unregister_powermanager(struct goodix_ts_data *ts);
+static int gtp_register_powermanager(struct goodix_ts_data *ts);
+
+static int gtp_esd_init(struct goodix_ts_data *ts);
+static void gtp_esd_check_func(struct work_struct *);
+static int gtp_init_ext_watchdog(struct i2c_client *client);
+
+/*
+ * return: 2 - ok, < 0 - i2c transfer error
+ */
+int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len)
+{
+ unsigned int transfer_length = 0;
+ unsigned int pos = 0, address = (buf[0] << 8) + buf[1];
+ unsigned char get_buf[64], addr_buf[2];
+ int retry, r = 2;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = !I2C_M_RD,
+ .buf = &addr_buf[0],
+ .len = GTP_ADDR_LENGTH,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ }
+ };
+
+ len -= GTP_ADDR_LENGTH;
+ if (likely(len < sizeof(get_buf))) {
+ /* code optimize, use stack memory */
+ msgs[1].buf = &get_buf[0];
+ } else {
+ msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE
+ ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL);
+ if (!msgs[1].buf)
+ return -ENOMEM;
+ }
+
+ while (pos != len) {
+ if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE))
+ transfer_length = I2C_MAX_TRANSFER_SIZE;
+ else
+ transfer_length = len - pos;
+ msgs[0].buf[0] = (address >> 8) & 0xFF;
+ msgs[0].buf[1] = address & 0xFF;
+ msgs[1].len = transfer_length;
+ for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
+ if (likely(i2c_transfer(client->adapter,
+ msgs, 2) == 2)) {
+ memcpy(&buf[2 + pos], msgs[1].buf,
+ transfer_length);
+ pos += transfer_length;
+ address += transfer_length;
+ break;
+ }
+ dev_dbg(&client->dev, "I2c read retry[%d]:0x%x\n",
+ retry + 1, address);
+ usleep_range(2000, 2100);
+ }
+ if (unlikely(retry == RETRY_MAX_TIMES)) {
+ dev_err(&client->dev,
+ "I2c read failed,dev:%02x,reg:%04x,size:%u\n",
+ client->addr, address, len);
+ r = -EAGAIN;
+ goto read_exit;
+ }
+ }
+read_exit:
+ if (len >= sizeof(get_buf))
+ kfree(msgs[1].buf);
+ return r;
+}
+
+/*******************************************************
+ * Function:
+ * Write data to the i2c slave device.
+ * Input:
+ * client: i2c device.
+ * buf[0~1]: write start address.
+ * buf[2~len-1]: data buffer
+ * len: GTP_ADDR_LENGTH + write bytes count
+ * Output:
+ * numbers of i2c_msgs to transfer:
+ * 1: succeed, otherwise: failed
+ *********************************************************/
+int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len)
+
+{
+ unsigned int pos = 0, transfer_length = 0;
+ unsigned int address = (buf[0] << 8) + buf[1];
+ unsigned char put_buf[64];
+ int retry, r = 1;
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = !I2C_M_RD,
+ };
+
+ if (likely(len < sizeof(put_buf))) {
+ /* code optimize,use stack memory*/
+ msg.buf = &put_buf[0];
+ } else {
+ msg.buf = kmalloc(len > I2C_MAX_TRANSFER_SIZE
+ ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL);
+ if (!msg.buf)
+ return -ENOMEM;
+ }
+
+ len -= GTP_ADDR_LENGTH;
+ while (pos != len) {
+ if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE
+ - GTP_ADDR_LENGTH))
+ transfer_length = I2C_MAX_TRANSFER_SIZE
+ - GTP_ADDR_LENGTH;
+ else
+ transfer_length = len - pos;
+ msg.buf[0] = (unsigned char)((address >> 8) & 0xFF);
+ msg.buf[1] = (unsigned char)(address & 0xFF);
+ msg.len = transfer_length + 2;
+ memcpy(&msg.buf[2], &buf[2 + pos], transfer_length);
+ for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
+ if (likely(i2c_transfer(client->adapter,
+ &msg, 1) == 1)) {
+ pos += transfer_length;
+ address += transfer_length;
+ break;
+ }
+ dev_dbg(&client->dev, "I2C write retry[%d]\n",
+ retry + 1);
+ usleep_range(2000, 2100);
+ }
+ if (unlikely(retry == RETRY_MAX_TIMES)) {
+ dev_err(&client->dev,
+ "I2c write failed,dev:%02x,reg:%04x,size:%u\n",
+ client->addr, address, len);
+ r = -EAGAIN;
+ goto write_exit;
+ }
+ }
+write_exit:
+ if (len + GTP_ADDR_LENGTH >= sizeof(put_buf))
+ kfree(msg.buf);
+ return r;
+}
+
+/*******************************************************
+ * Function:
+ * i2c read twice, compare the results
+ * Input:
+ * client: i2c device
+ * addr: operate address
+ * rxbuf: read data to store, if compare successful
+ * len: bytes to read
+ * Output:
+ * FAIL: read failed
+ * SUCCESS: read successful
+ *********************************************************/
+s32 gtp_i2c_read_dbl_check(struct i2c_client *client,
+ u16 addr, u8 *rxbuf, int len)
+{
+ u8 buf[16] = {0};
+ u8 confirm_buf[16] = {0};
+ u8 retry = 0;
+
+ if (len + 2 > sizeof(buf)) {
+ dev_warn(&client->dev,
+ "%s, only support length less then %zu\n",
+ __func__, sizeof(buf) - 2);
+ return FAIL;
+ }
+ while (retry++ < 3) {
+ memset(buf, 0xAA, 16);
+ buf[0] = (u8)(addr >> 8);
+ buf[1] = (u8)(addr & 0xFF);
+ gtp_i2c_read(client, buf, len + 2);
+
+ memset(confirm_buf, 0xAB, 16);
+ confirm_buf[0] = (u8)(addr >> 8);
+ confirm_buf[1] = (u8)(addr & 0xFF);
+ gtp_i2c_read(client, confirm_buf, len + 2);
+
+ if (!memcmp(buf, confirm_buf, len + 2)) {
+ memcpy(rxbuf, confirm_buf + 2, len);
+ return SUCCESS;
+ }
+ }
+ dev_err(&client->dev,
+ "I2C read 0x%04X, %d bytes, double check failed!\n",
+ addr, len);
+
+ return FAIL;
+}
+
+/*******************************************************
+ * Function:
+ * Send config.
+ * Input:
+ * client: i2c device.
+ * Output:
+ * result of i2c write operation.
+ * 1: succeed, otherwise
+ * 0: Not executed
+ * < 0: failed
+ *********************************************************/
+s32 gtp_send_cfg(struct i2c_client *client)
+{
+ s32 ret, i;
+ u8 check_sum;
+ s32 retry = 0;
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+ struct goodix_config_data *cfg = &ts->pdata->config;
+
+ if (!cfg->length || !ts->pdata->driver_send_cfg) {
+ dev_info(&ts->client->dev,
+ "No config data or error occurred in panel_init\n");
+ return 0;
+ }
+
+ check_sum = 0;
+ for (i = GTP_ADDR_LENGTH; i < cfg->length; i++)
+ check_sum += cfg->data[i];
+ cfg->data[cfg->length] = (~check_sum) + 1;
+
+ dev_info(&ts->client->dev, "Driver send config\n");
+ for (retry = 0; retry < RETRY_MAX_TIMES; retry++) {
+ ret = gtp_i2c_write(client, cfg->data,
+ GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH);
+ if (ret > 0)
+ break;
+ }
+
+ return ret;
+}
+
+/*******************************************************
+ * Function:
+ * Control enable or disable of work thread.
+ * Input:
+ * ts: goodix i2c_client private data
+ * enable: enable var.
+ *********************************************************/
+void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable)
+{
+ if (enable) {
+ set_bit(REPORT_THREAD_ENABLED, &ts->flags);
+ dev_dbg(&ts->client->dev, "Input report thread enabled!\n");
+ } else {
+ clear_bit(REPORT_THREAD_ENABLED, &ts->flags);
+ dev_dbg(&ts->client->dev, "Input report thread disabled!\n");
+ }
+}
+
+static int gtp_gesture_handler(struct goodix_ts_data *ts)
+{
+ u8 doze_buf[3] = {GTP_REG_DOZE_BUF >> 8, GTP_REG_DOZE_BUF & 0xFF};
+ int ret;
+
+ ret = gtp_i2c_read(ts->client, doze_buf, 3);
+ if (ret < 0) {
+ dev_err(&ts->client->dev, "Failed read doze buf");
+ return -EINVAL;
+ }
+
+ dev_dbg(&ts->client->dev, "0x814B = 0x%02X", doze_buf[2]);
+ if ((doze_buf[2] == 'a') || (doze_buf[2] == 'b') ||
+ (doze_buf[2] == 'c') || (doze_buf[2] == 'd') ||
+ (doze_buf[2] == 'e') || (doze_buf[2] == 'g') ||
+ (doze_buf[2] == 'h') || (doze_buf[2] == 'm') ||
+ (doze_buf[2] == 'o') || (doze_buf[2] == 'q') ||
+ (doze_buf[2] == 's') || (doze_buf[2] == 'v') ||
+ (doze_buf[2] == 'w') || (doze_buf[2] == 'y') ||
+ (doze_buf[2] == 'z') || (doze_buf[2] == 0x5E) ||
+ (doze_buf[2] == 0xAA) || (doze_buf[2] == 0xAB) ||
+ (doze_buf[2] == 0xBA) || (doze_buf[2] == 0xBB) ||
+ (doze_buf[2] == 0xCC)) {
+ doze_status = DOZE_WAKEUP;
+ input_report_key(ts->input_dev, KEY_POWER, 1);
+ input_sync(ts->input_dev);
+ input_report_key(ts->input_dev, KEY_POWER, 0);
+ input_sync(ts->input_dev);
+ /* clear 0x814B */
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ } else {
+ /* clear 0x814B */
+ doze_buf[2] = 0x00;
+ gtp_i2c_write(ts->client, doze_buf, 3);
+ gtp_enter_doze(ts);
+ }
+ return 0;
+}
+
+/*
+ * return touch state register value
+ * pen event id fixed with 9 and set tool type TOOL_PEN
+ *
+ */
+static u8 gtp_get_points(struct goodix_ts_data *ts,
+ struct goodix_point_t *points,
+ u8 *key_value)
+{
+ int ret;
+ int i;
+ u8 *coor_data = NULL;
+ u8 finger_state = 0;
+ u8 touch_num = 0;
+ u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8,
+ GTP_READ_COOR_ADDR & 0xFF, 0 };
+ u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH_ID + 1] = {
+ GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF };
+
+ ret = gtp_i2c_read(ts->client, point_data, 12);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "I2C transfer error. errno:%d\n ", ret);
+ return 0;
+ }
+ finger_state = point_data[GTP_ADDR_LENGTH];
+ if (finger_state == 0x00)
+ return 0;
+
+ touch_num = finger_state & 0x0f;
+ if ((finger_state & MASK_BIT_8) == 0 ||
+ touch_num > ts->pdata->max_touch_id) {
+ dev_err(&ts->client->dev,
+ "Invalid touch state: 0x%x", finger_state);
+ finger_state = 0;
+ goto exit_get_point;
+ }
+
+ if (touch_num > 1) {
+ u8 buf[8 * GTP_MAX_TOUCH_ID] = {
+ (GTP_READ_COOR_ADDR + 10) >> 8,
+ (GTP_READ_COOR_ADDR + 10) & 0xff };
+
+ ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1));
+ if (ret < 0) {
+ dev_err(&ts->client->dev, "I2C error. %d\n", ret);
+ finger_state = 0;
+ goto exit_get_point;
+ }
+ memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
+ }
+
+ /* panel have touch key */
+ /* 0x20_UPKEY 0X10_DOWNKEY 0X40_ALLKEYDOWN */
+ *key_value = point_data[3 + 8 * touch_num];
+
+ memset(points, 0, sizeof(*points) * GTP_MAX_TOUCH_ID);
+ for (i = 0; i < touch_num; i++) {
+ coor_data = &point_data[i * 8 + 3];
+ points[i].id = coor_data[0];
+ points[i].x = coor_data[1] | (coor_data[2] << 8);
+ points[i].y = coor_data[3] | (coor_data[4] << 8);
+ points[i].w = coor_data[5] | (coor_data[6] << 8);
+ /* if pen hover points[].p must set to zero */
+ points[i].p = coor_data[5] | (coor_data[6] << 8);
+
+ if (ts->pdata->swap_x2y)
+ GTP_SWAP(points[i].x, points[i].y);
+
+ dev_dbg(&ts->client->dev, "[%d][%d %d %d]\n",
+ points[i].id, points[i].x, points[i].y, points[i].p);
+
+ /* pen device coordinate */
+ if (points[i].id & 0x80) {
+ points[i].tool_type = GTP_TOOL_PEN;
+ points[i].id = 10;
+ if (ts->pdata->pen_suppress_finger) {
+ points[0] = points[i];
+ memset(++points, 0, sizeof(*points) *
+ (GTP_MAX_TOUCH_ID - 1));
+ finger_state &= 0xf0;
+ finger_state |= 0x01;
+ break;
+ }
+ } else {
+ points[i].tool_type = GTP_TOOL_FINGER;
+ }
+ }
+
+exit_get_point:
+ if (!test_bit(RAW_DATA_MODE, &ts->flags)) {
+ ret = gtp_i2c_write(ts->client, end_cmd, 3);
+ if (ret < 0)
+ dev_info(&ts->client->dev, "I2C write end_cmd error!");
+ }
+ return finger_state;
+}
+
+static void gtp_type_a_report(struct goodix_ts_data *ts, u8 touch_num,
+ struct goodix_point_t *points)
+{
+ int i;
+ u16 cur_touch = 0;
+ static u16 pre_touch;
+ static u8 pre_pen_id;
+
+ if (touch_num)
+ input_report_key(ts->input_dev, BTN_TOUCH, 1);
+
+ for (i = 0; i < ts->pdata->max_touch_id; i++) {
+ if (touch_num && i == points->id) {
+ input_report_abs(ts->input_dev,
+ ABS_MT_TRACKING_ID, points->id);
+
+ if (points->tool_type == GTP_TOOL_PEN) {
+ input_report_key(ts->input_dev,
+ BTN_TOOL_PEN, true);
+ pre_pen_id = points->id;
+ } else {
+ input_report_key(ts->input_dev,
+ BTN_TOOL_FINGER, true);
+ }
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+ points->x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+ points->y);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+ points->w);
+ input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+ points->p);
+ input_mt_sync(ts->input_dev);
+
+ cur_touch |= 0x01 << points->id;
+ points++;
+ } else if (pre_touch & 0x01 << i) {
+ if (pre_pen_id == i) {
+ input_report_key(ts->input_dev,
+ BTN_TOOL_PEN, false);
+/* valid id will < 10, so id to 0xff to indicate a invalid state */
+ pre_pen_id = 0xff;
+ } else {
+ input_report_key(ts->input_dev,
+ BTN_TOOL_FINGER, false);
+ }
+ }
+ }
+
+ pre_touch = cur_touch;
+ if (!pre_touch) {
+ input_mt_sync(ts->input_dev);
+ input_report_key(ts->input_dev, BTN_TOUCH, 0);
+ }
+ input_sync(ts->input_dev);
+}
+
+static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num,
+ struct goodix_point_t *points)
+{
+ int i;
+ u16 cur_touch = 0;
+ static u16 pre_touch;
+ static u8 pre_pen_id;
+
+ for (i = 0; i < ts->pdata->max_touch_id; i++) {
+ if (touch_num && i == points->id) {
+ input_mt_slot(ts->input_dev, points->id);
+
+ if (points->tool_type == GTP_TOOL_PEN) {
+ input_mt_report_slot_state(ts->input_dev,
+ MT_TOOL_PEN, true);
+ pre_pen_id = points->id;
+ } else {
+ input_mt_report_slot_state(ts->input_dev,
+ MT_TOOL_FINGER, true);
+ }
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
+ points->x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
+ points->y);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
+ points->w);
+ input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
+ points->p);
+
+ cur_touch |= 0x01 << points->id;
+ points++;
+ } else if (pre_touch & 0x01 << i) {
+ input_mt_slot(ts->input_dev, i);
+ if (pre_pen_id == i) {
+ input_mt_report_slot_state(ts->input_dev,
+ MT_TOOL_PEN, false);
+ /* valid id will < 10, so set id to 0xff to
+ * indicate a invalid state
+ */
+ pre_pen_id = 0xff;
+ } else {
+ input_mt_report_slot_state(ts->input_dev,
+ MT_TOOL_FINGER, false);
+ }
+ }
+ }
+
+ pre_touch = cur_touch;
+ /* report BTN_TOUCH event */
+ input_mt_sync_frame(ts->input_dev);
+ input_sync(ts->input_dev);
+}
+
+/*******************************************************
+ * Function:
+ * Goodix touchscreen sensor report function
+ * Input:
+ * ts: goodix tp private data
+ * Output:
+ * None.
+ *********************************************************/
+static void gtp_work_func(struct goodix_ts_data *ts)
+{
+ u8 point_state = 0;
+ u8 key_value = 0;
+ s32 i = 0;
+ s32 ret = -1;
+ static u8 pre_key;
+ struct goodix_point_t points[GTP_MAX_TOUCH_ID];
+
+ if (test_bit(PANEL_RESETTING, &ts->flags))
+ return;
+ if (!test_bit(REPORT_THREAD_ENABLED, &ts->flags))
+ return;
+
+ /* gesture event */
+ if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) {
+ ret = gtp_gesture_handler(ts);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "Failed handler gesture event %d\n", ret);
+ return;
+ }
+
+ point_state = gtp_get_points(ts, points, &key_value);
+ if (!point_state) {
+ dev_dbg(&ts->client->dev, "Invalid finger points\n");
+ return;
+ }
+
+ /* touch key event */
+ if (key_value & 0xf0 || pre_key & 0xf0) {
+ /* pen button */
+ switch (key_value) {
+ case 0x40:
+ input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1);
+ input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1);
+ break;
+ case 0x10:
+ input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1);
+ input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0);
+ dev_dbg(&ts->client->dev, "pen button1 down\n");
+ break;
+ case 0x20:
+ input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0);
+ input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1);
+ break;
+ default:
+ input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0);
+ input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0);
+ dev_dbg(&ts->client->dev, "button1 up\n");
+ break;
+ }
+ input_sync(ts->input_dev);
+ pre_key = key_value;
+ } else if (key_value & 0x0f || pre_key & 0x0f) {
+ /* panel key */
+ for (i = 0; i < ts->pdata->key_nums; i++) {
+ if ((pre_key | key_value) & (0x01 << i))
+ input_report_key(ts->input_dev,
+ ts->pdata->key_map[i],
+ key_value & (0x01 << i));
+ }
+ input_sync(ts->input_dev);
+ pre_key = key_value;
+ }
+
+ if (!ts->pdata->type_a_report)
+ gtp_mt_slot_report(ts, point_state & 0x0f, points);
+ else
+ gtp_type_a_report(ts, point_state & 0x0f, points);
+}
+
+/*******************************************************
+ * Function:
+ * Timer interrupt service routine for polling mode.
+ * Input:
+ * timer: timer struct pointer
+ * Output:
+ * Timer work mode.
+ * HRTIMER_NORESTART:
+ * no restart mode
+ *********************************************************/
+static enum hrtimer_restart gtp_timer_handler(struct hrtimer *timer)
+{
+ struct goodix_ts_data *ts =
+ container_of(timer, struct goodix_ts_data, timer);
+
+ gtp_work_func(ts);
+ hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
+ HRTIMER_MODE_REL);
+
+ return HRTIMER_NORESTART;
+}
+
+static irqreturn_t gtp_irq_handler(int irq, void *dev_id)
+{
+ struct goodix_ts_data *ts = dev_id;
+
+ gtp_work_func(ts);
+ return IRQ_HANDLED;
+}
+
+void gtp_int_output(struct goodix_ts_data *ts, int level)
+{
+ if (!ts->pdata->int_sync)
+ return;
+
+ if (level == 0) {
+ if (ts->pinctrl.pinctrl)
+ pinctrl_select_state(ts->pinctrl.pinctrl,
+ ts->pinctrl.int_out_low);
+ else if (gpio_is_valid(ts->pdata->irq_gpio))
+ gpio_direction_output(ts->pdata->irq_gpio, 0);
+ else
+ dev_err(&ts->client->dev,
+ "Failed set int pin output low\n");
+ } else {
+ if (ts->pinctrl.pinctrl)
+ pinctrl_select_state(ts->pinctrl.pinctrl,
+ ts->pinctrl.int_out_high);
+ else if (gpio_is_valid(ts->pdata->irq_gpio))
+ gpio_direction_output(ts->pdata->irq_gpio, 1);
+ else
+ dev_err(&ts->client->dev,
+ "Failed set int pin output high\n");
+ }
+}
+
+void gtp_int_sync(struct goodix_ts_data *ts, s32 ms)
+{
+ if (!ts->pdata->int_sync)
+ return;
+
+ if (ts->pinctrl.pinctrl) {
+ gtp_int_output(ts, 0);
+ msleep(ms);
+ pinctrl_select_state(ts->pinctrl.pinctrl,
+ ts->pinctrl.int_input);
+ } else if (gpio_is_valid(ts->pdata->irq_gpio)) {
+ gpio_direction_output(ts->pdata->irq_gpio, 0);
+ msleep(ms);
+ gpio_direction_input(ts->pdata->irq_gpio);
+ } else {
+ dev_err(&ts->client->dev, "Failed sync int pin\n");
+ }
+}
+
+void gtp_rst_output(struct goodix_ts_data *ts, int level)
+{
+ if (level == 0) {
+ if (ts->pinctrl.pinctrl)
+ pinctrl_select_state(ts->pinctrl.pinctrl,
+ ts->pinctrl.rst_out_low);
+ else if (gpio_is_valid(ts->pdata->rst_gpio))
+ gpio_direction_output(ts->pdata->rst_gpio, 0);
+ else
+ dev_err(&ts->client->dev,
+ "Failed set rst pin output low\n");
+ } else {
+ if (ts->pinctrl.pinctrl)
+ pinctrl_select_state(ts->pinctrl.pinctrl,
+ ts->pinctrl.rst_out_high);
+ else if (gpio_is_valid(ts->pdata->rst_gpio))
+ gpio_direction_output(ts->pdata->rst_gpio, 1);
+ else
+ dev_err(&ts->client->dev,
+ "Failed set rst pin output high\n");
+ }
+}
+
+void gtp_rst_input(struct goodix_ts_data *ts)
+{
+ if (ts->pinctrl.pinctrl)
+ pinctrl_select_state(ts->pinctrl.pinctrl,
+ ts->pinctrl.rst_input);
+ else if (gpio_is_valid(ts->pdata->rst_gpio))
+ gpio_direction_input(ts->pdata->rst_gpio);
+ else
+ dev_err(&ts->client->dev,
+ "Failed set rst pin input\n");
+}
+
+/*******************************************************
+ * Function:
+ * Reset chip. Control the reset pin and int-pin(if
+ * defined),
+ * Input:
+ * client: i2c device.
+ * ms: reset time in millisecond
+ * Output:
+ * None.
+ *******************************************************/
+void gtp_reset_guitar(struct i2c_client *client, s32 ms)
+{
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "Guitar reset");
+ set_bit(PANEL_RESETTING, &ts->flags);
+ if (!gpio_is_valid(ts->pdata->rst_gpio)) {
+ dev_warn(&client->dev, "reset failed no valid reset gpio");
+ return;
+ }
+
+ gtp_rst_output(ts, 0);
+ usleep_range(ms * 1000, ms * 1000 + 100); /* T2: > 10ms */
+
+ gtp_int_output(ts, client->addr == 0x14);
+
+ usleep_range(2000, 3000); /* T3: > 100us (2ms)*/
+ gtp_rst_output(ts, 1);
+
+ usleep_range(6000, 7000); /* T4: > 5ms */
+ gtp_rst_input(ts);
+
+ gtp_int_sync(ts, 50);
+ if (ts->pdata->esd_protect)
+ gtp_init_ext_watchdog(client);
+
+ clear_bit(PANEL_RESETTING, &ts->flags);
+}
+
+/*******************************************************
+ * Function:
+ * Enter doze mode for sliding wakeup.
+ * Input:
+ * ts: goodix tp private data
+ * Output:
+ * 1: succeed, otherwise failed
+ *******************************************************/
+static int gtp_enter_doze(struct goodix_ts_data *ts)
+{
+ int ret = -1;
+ int retry = 0;
+ u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8),
+ (u8)GTP_REG_COMMAND, 8 };
+
+ /* resend doze command
+ * if (test_and_set_bit(DOZE_MODE, &ts->flags)) {
+ * dev_info(&ts->client->dev, "Already in doze mode\n");
+ * return SUCCESS;
+ * }
+ */
+ set_bit(DOZE_MODE, &ts->flags);
+ dev_dbg(&ts->client->dev, "Entering gesture mode.");
+ while (retry++ < 5) {
+ i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8);
+ i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK;
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret < 0) {
+ dev_dbg(&ts->client->dev,
+ "failed to set doze flag into 0x8046, %d\n",
+ retry);
+ continue;
+ }
+ i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8);
+ i2c_control_buf[1] = (u8)GTP_REG_COMMAND;
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret > 0) {
+ dev_dbg(&ts->client->dev, "Gesture mode enabled\n");
+ return ret;
+ }
+ usleep_range(10000, 11000);
+ }
+
+ dev_err(&ts->client->dev, "Failed enter doze mode\n");
+ clear_bit(DOZE_MODE, &ts->flags);
+ return ret;
+}
+
+static s8 gtp_enter_sleep(struct goodix_ts_data *ts)
+{
+ s8 ret = -1;
+ s8 retry = 0;
+ u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8),
+ (u8)GTP_REG_COMMAND, 5 };
+
+ gtp_int_output(ts, 0);
+ usleep_range(5000, 6000);
+
+ while (retry++ < 5) {
+ ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+ if (ret > 0) {
+ dev_info(&ts->client->dev, "Enter sleep mode\n");
+
+ return ret;
+ }
+ usleep_range(10000, 11000);
+ }
+ dev_err(&ts->client->dev, "Failed send sleep cmd\n");
+
+ return ret;
+}
+
+static int gtp_wakeup_sleep(struct goodix_ts_data *ts)
+{
+ u8 retry = 0;
+ int ret = -1;
+
+ while (retry++ < 10) {
+ gtp_int_output(ts, 1);
+ usleep_range(5000, 6000);
+
+ ret = gtp_i2c_test(ts->client);
+ if (!ret) {
+ dev_dbg(&ts->client->dev, "Success wakeup sleep\n");
+
+ gtp_int_sync(ts, 25);
+ if (ts->pdata->esd_protect)
+ gtp_init_ext_watchdog(ts->client);
+
+ return ret;
+ }
+ gtp_reset_guitar(ts->client, 20);
+ }
+
+ dev_err(&ts->client->dev, "Failed wakeup from sleep mode\n");
+ return -EINVAL;
+}
+
+static int gtp_find_valid_cfg_data(struct goodix_ts_data *ts)
+{
+ int ret = -1;
+ u8 sensor_id = 0;
+ struct goodix_config_data *cfg = &ts->pdata->config;
+
+ /* if defined CONFIG_OF, parse config data from dtsi
+ * else parse config data form header file.
+ */
+ cfg->length = 0;
+
+#ifndef CONFIG_OF
+ u8 cfg_info_group0[] = CTP_CFG_GROUP0;
+ u8 cfg_info_group1[] = CTP_CFG_GROUP1;
+ u8 cfg_info_group2[] = CTP_CFG_GROUP2;
+ u8 cfg_info_group3[] = CTP_CFG_GROUP3;
+ u8 cfg_info_group4[] = CTP_CFG_GROUP4;
+ u8 cfg_info_group5[] = CTP_CFG_GROUP5;
+
+ u8 *send_cfg_buf[] = { cfg_info_group0, cfg_info_group1,
+ cfg_info_group2, cfg_info_group3,
+ cfg_info_group4, cfg_info_group5 };
+ u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group0),
+ CFG_GROUP_LEN(cfg_info_group1),
+ CFG_GROUP_LEN(cfg_info_group2),
+ CFG_GROUP_LEN(cfg_info_group3),
+ CFG_GROUP_LEN(cfg_info_group4),
+ CFG_GROUP_LEN(cfg_info_group5)};
+
+ dev_dbg(&ts->client->dev,
+ "Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
+ cfg_info_len[0], cfg_info_len[1], cfg_info_len[2],
+ cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]);
+#endif
+
+ /* read sensor id */
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
+ &sensor_id, 1);
+ if (ret != SUCCESS || sensor_id >= 0x06) {
+ dev_err(&ts->client->dev,
+ "Failed get valid sensor_id(0x%02X), No Config Sent\n",
+ sensor_id);
+ return -EINVAL;
+ }
+
+ dev_dbg(&ts->client->dev, "Sensor_ID: %d", sensor_id);
+ /* parse config data */
+#ifdef CONFIG_OF
+ dev_dbg(&ts->client->dev, "Get config data from device tree\n");
+ ret = gtp_parse_dt_cfg(&ts->client->dev,
+ &cfg->data[GTP_ADDR_LENGTH],
+ &cfg->length, sensor_id);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Failed to parse config data form device tree\n");
+ cfg->length = 0;
+ return -EPERM;
+ }
+#else
+ dev_dbg(&ts->client->dev, "Get config data from header file\n");
+ if ((!cfg_info_len[1]) && (!cfg_info_len[2]) &&
+ (!cfg_info_len[3]) && (!cfg_info_len[4]) &&
+ (!cfg_info_len[5])) {
+ sensor_id = 0;
+ }
+ cfg->length = cfg_info_len[sensor_id];
+ memset(&cfg->data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
+ memcpy(&cfg->data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
+ cfg->length);
+#endif
+
+ if (cfg->length < GTP_CONFIG_MIN_LENGTH) {
+ dev_err(&ts->client->dev,
+ "Failed get valid config data with sensor id %d\n",
+ sensor_id);
+ cfg->length = 0;
+ return -EPERM;
+ }
+
+ dev_info(&ts->client->dev, "Config group%d used,length: %d\n",
+ sensor_id, cfg->length);
+
+ return 0;
+}
+
+/*******************************************************
+ * Function:
+ * Get valid config data from dts or .h file.
+ * Read firmware version info and judge firmware
+ * working state
+ * Input:
+ * ts: goodix private data
+ * Output:
+ * Executive outcomes.
+ * 0: succeed, otherwise: failed
+ *******************************************************/
+static s32 gtp_init_panel(struct goodix_ts_data *ts)
+{
+ s32 ret = -1;
+ u8 opr_buf[16] = {0};
+ u8 drv_cfg_version = 0;
+ u8 flash_cfg_version = 0;
+ struct goodix_config_data *cfg = &ts->pdata->config;
+
+ if (!ts->pdata->driver_send_cfg) {
+ dev_info(&ts->client->dev, "Driver set not send config\n");
+ cfg->length = GTP_CONFIG_MAX_LENGTH;
+ ret = gtp_i2c_read(ts->client,
+ cfg->data, cfg->length +
+ GTP_ADDR_LENGTH);
+ if (ret < 0)
+ dev_err(&ts->client->dev, "Read origin Config Failed\n");
+
+ return 0;
+ }
+
+ gtp_find_valid_cfg_data(ts);
+
+ /* check firmware */
+ ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
+ if (ret == SUCCESS) {
+ if (opr_buf[0] != 0xBE) {
+ set_bit(FW_ERROR, &ts->flags);
+ dev_err(&ts->client->dev,
+ "Firmware error, no config sent!\n");
+ return -EINVAL;
+ }
+ }
+
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+ &opr_buf[0], 1);
+ if (ret == SUCCESS) {
+ dev_dbg(&ts->client->dev,
+ "Config Version: %d; IC Config Version: %d\n",
+ cfg->data[GTP_ADDR_LENGTH], opr_buf[0]);
+ flash_cfg_version = opr_buf[0];
+ drv_cfg_version = cfg->data[GTP_ADDR_LENGTH];
+
+ if (flash_cfg_version < 120 &&
+ flash_cfg_version > drv_cfg_version)
+ cfg->data[GTP_ADDR_LENGTH] = 0x00;
+ } else {
+ dev_err(&ts->client->dev,
+ "Failed to get ic config version!No config sent\n");
+ return -EPERM;
+ }
+
+ ret = gtp_send_cfg(ts->client);
+ if (ret < 0)
+ dev_err(&ts->client->dev, "Send config error\n");
+ else
+ usleep_range(10000, 11000); /* 10 ms */
+
+ /* restore config version */
+ cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version;
+
+ return 0;
+}
+
+static ssize_t gtp_config_read_proc(struct file *file, char __user *page,
+ size_t size, loff_t *ppos)
+{
+ int i, ret;
+ char *ptr;
+ size_t data_len = 0;
+ char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = {
+ (u8)(GTP_REG_CONFIG_DATA >> 8),
+ (u8)GTP_REG_CONFIG_DATA };
+ struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
+ struct goodix_config_data *cfg = &ts->pdata->config;
+
+ ptr = kzalloc(4096, GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ data_len += snprintf(ptr + data_len, 4096 - data_len,
+ "====init value====\n");
+ for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++) {
+ data_len += snprintf(ptr + data_len, 4096 - data_len,
+ "0x%02X ", cfg->data[i + 2]);
+
+ if (i % 8 == 7)
+ data_len += snprintf(ptr + data_len,
+ 4096 - data_len, "\n");
+ }
+ data_len += snprintf(ptr + data_len, 4096 - data_len, "\n");
+
+ data_len += snprintf(ptr + data_len, 4096 - data_len,
+ "====real value====\n");
+ ret = gtp_i2c_read(i2c_connect_client, temp_data,
+ GTP_CONFIG_MAX_LENGTH + 2);
+ if (ret < 0) {
+ data_len += snprintf(ptr + data_len, 4096 - data_len,
+ "Failed read real config data\n");
+ } else {
+ for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) {
+ data_len += snprintf(ptr + data_len, 4096 - data_len,
+ "0x%02X ", temp_data[i + 2]);
+
+ if (i % 8 == 7)
+ data_len += snprintf(ptr + data_len,
+ 4096 - data_len, "\n");
+ }
+ }
+
+ data_len = simple_read_from_buffer(page, size, ppos, ptr, data_len);
+ kfree(ptr);
+ ptr = NULL;
+ return data_len;
+}
+
+int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf)
+{
+ int i, ret;
+ int cfg_len = 0;
+ long val;
+ char temp_buf[5];
+
+ for (i = 0; i < src_len;) {
+ if (src_buf[i] == ' ' || src_buf[i] == '\r' ||
+ src_buf[i] == '\n') {
+ i++;
+ continue;
+ }
+
+ temp_buf[0] = src_buf[i];
+ temp_buf[1] = src_buf[i + 1];
+ temp_buf[2] = src_buf[i + 2];
+ temp_buf[3] = src_buf[i + 3];
+ temp_buf[4] = '\0';
+ if (!kstrtol(temp_buf, 16, &val)) {
+ if (cfg_len < GTP_CONFIG_MAX_LENGTH) {
+ dst_buf[cfg_len++] = val & 0xFF;
+ i += 5;
+ } else {
+ ret = -2;
+ goto convert_failed;
+ }
+ } else {
+ ret = -3;
+ goto convert_failed;
+ }
+ }
+ return cfg_len;
+
+convert_failed:
+ return ret;
+}
+
+static ssize_t gtp_config_write_proc(struct file *filp,
+ const char __user *buffer,
+ size_t count, loff_t *off)
+{
+ u8 *temp_buf;
+ u8 *file_config;
+ int file_cfg_len;
+ s32 ret = 0, i;
+ struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client);
+
+ dev_dbg(&ts->client->dev, "write count %zu\n", count);
+
+ if (count > PAGE_SIZE) {
+ dev_err(&ts->client->dev, "config to long %zu\n", count);
+ return -EFAULT;
+ }
+
+ temp_buf = kzalloc(count, GFP_KERNEL);
+ if (!temp_buf)
+ return -ENOMEM;
+
+ file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
+ GFP_KERNEL);
+ if (!file_config) {
+ kfree(temp_buf);
+ return -ENOMEM;
+ }
+ file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+ file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+
+ if (copy_from_user(temp_buf, buffer, count)) {
+ dev_err(&ts->client->dev, "Failed copy from user\n");
+ ret = -EFAULT;
+ goto send_cfg_err;
+ }
+
+ file_cfg_len = gtp_ascii_to_array(temp_buf, (int)count,
+ &file_config[GTP_ADDR_LENGTH]);
+ if (file_cfg_len < 0) {
+ dev_err(&ts->client->dev, "failed covert ascii to hex");
+ ret = -EFAULT;
+ goto send_cfg_err;
+ }
+
+ GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len);
+
+ i = 0;
+ while (i++ < 5) {
+ ret = gtp_i2c_write(ts->client, file_config, file_cfg_len + 2);
+ if (ret > 0) {
+ dev_info(&ts->client->dev, "Send config SUCCESS.");
+ break;
+ }
+ dev_err(&ts->client->dev, "Send config i2c error.");
+ ret = -EFAULT;
+ goto send_cfg_err;
+ }
+
+ ret = count;
+send_cfg_err:
+ kfree(temp_buf);
+ kfree(file_config);
+ return ret;
+}
+
+static const struct file_operations config_proc_ops = {
+ .owner = THIS_MODULE,
+ .read = gtp_config_read_proc,
+ .write = gtp_config_write_proc,
+};
+
+static ssize_t gtp_workmode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ size_t data_len = 0;
+ struct goodix_ts_data *data = dev_get_drvdata(dev);
+
+ if (test_bit(DOZE_MODE, &data->flags))
+ data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
+ "doze_mode");
+ else if (test_bit(SLEEP_MODE, &data->flags))
+ data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
+ "sleep_mode");
+ else
+ data_len = scnprintf(buf, PAGE_SIZE, "%s\n",
+ "normal_mode");
+
+ return data_len;
+}
+static DEVICE_ATTR(workmode, 0444, gtp_workmode_show, NULL);
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+#define FW_NAME_MAX_LEN 80
+static ssize_t gtp_dofwupdate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct goodix_ts_data *ts = dev_get_drvdata(dev);
+ char update_file_name[FW_NAME_MAX_LEN];
+ int retval;
+
+ if (count > FW_NAME_MAX_LEN) {
+ dev_info(&ts->client->dev, "FW filename is too long\n");
+ retval = -EINVAL;
+ goto exit;
+ }
+
+ strlcpy(update_file_name, buf, count);
+
+ ts->force_update = true;
+ retval = gup_update_proc(update_file_name);
+ if (retval == FAIL)
+ dev_err(&ts->client->dev, "Fail to update GTP firmware.\n");
+ else
+ dev_info(&ts->client->dev, "Update success\n");
+
+ return count;
+
+exit:
+ return retval;
+}
+static DEVICE_ATTR(dofwupdate, 0664, NULL, gtp_dofwupdate_store);
+#endif
+
+static ssize_t gtp_productinfo_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct goodix_ts_data *data = dev_get_drvdata(dev);
+ struct goodix_fw_info *fw_info = &data->fw_info;
+
+ return scnprintf(buf, PAGE_SIZE, "GT%s_%x_%d\n",
+ fw_info->pid, fw_info->version, fw_info->sensor_id);
+}
+static DEVICE_ATTR(productinfo, 0444, gtp_productinfo_show, NULL);
+
+static ssize_t gtp_drv_irq_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long value = 0;
+ int err = 0;
+ struct goodix_ts_data *data = dev_get_drvdata(dev);
+
+ err = kstrtoul(buf, 10, &value);
+ if (err < 0) {
+ dev_err(dev, "Failed to convert value\n");
+ return -EINVAL;
+ }
+
+ switch (value) {
+ case 0:
+ /* Disable irq */
+ gtp_work_control_enable(data, false);
+ break;
+ case 1:
+ /* Enable irq */
+ gtp_work_control_enable(data, true);
+ break;
+ default:
+ dev_err(dev, "Invalid value\n");
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static ssize_t gtp_drv_irq_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct goodix_ts_data *data = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n",
+ test_bit(REPORT_THREAD_ENABLED, &data->flags)
+ ? "enabled" : "disabled");
+}
+static DEVICE_ATTR(drv_irq, 0664, gtp_drv_irq_show, gtp_drv_irq_store);
+
+static ssize_t gtp_reset_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct goodix_ts_data *data = dev_get_drvdata(dev);
+
+ if ('1' != buf[0]) {
+ dev_err(dev, "Invalid argument for reset\n");
+ return -EINVAL;
+ }
+
+ gtp_reset_guitar(data->client, 20);
+
+ return count;
+}
+static DEVICE_ATTR(reset, 0220, NULL, gtp_reset_store);
+
+static struct attribute *gtp_attrs[] = {
+ &dev_attr_workmode.attr,
+ &dev_attr_productinfo.attr,
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+ &dev_attr_dofwupdate.attr,
+#endif
+
+ &dev_attr_drv_irq.attr,
+ &dev_attr_reset.attr,
+ NULL
+};
+
+static const struct attribute_group gtp_attr_group = {
+ .attrs = gtp_attrs,
+};
+
+static int gtp_create_file(struct goodix_ts_data *ts)
+{
+ int ret;
+ struct i2c_client *client = ts->client;
+
+ /* Create proc file system */
+ gtp_config_proc = NULL;
+ gtp_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0664,
+ NULL, &config_proc_ops);
+ if (!gtp_config_proc)
+ dev_err(&client->dev, "create_proc_entry %s failed\n",
+ GT91XX_CONFIG_PROC_FILE);
+ else
+ dev_info(&client->dev, "create proc entry %s success\n",
+ GT91XX_CONFIG_PROC_FILE);
+
+ ret = sysfs_create_group(&client->dev.kobj, >p_attr_group);
+ if (ret) {
+ dev_err(&client->dev, "Failure create sysfs group %d\n", ret);
+ /*TODO: debug change */
+ goto exit_free_config_proc;
+ }
+ return 0;
+
+exit_free_config_proc:
+ remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc);
+ return -ENODEV;
+}
+
+s32 gtp_get_fw_info(struct i2c_client *client, struct goodix_fw_info *fw_info)
+{
+ s32 ret = -1;
+ u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff};
+
+ ret = gtp_i2c_read(client, buf, sizeof(buf));
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed read fw_info\n");
+ return ret;
+ }
+
+ /* product id */
+ memset(fw_info, 0, sizeof(*fw_info));
+
+ if (buf[5] == 0x00) {
+ memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 3);
+ dev_info(&client->dev, "IC Version: %c%c%c_%02X%02X\n",
+ buf[2], buf[3], buf[4], buf[7], buf[6]);
+ } else {
+ memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 4);
+ dev_info(&client->dev, "IC Version: %c%c%c%c_%02X%02X\n",
+ buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]);
+ }
+
+ /* current firmware version */
+ fw_info->version = (buf[7] << 8) | buf[6];
+
+ /* read sensor id */
+ fw_info->sensor_id = 0xff;
+ ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID,
+ &fw_info->sensor_id, 1);
+ if (ret != SUCCESS || fw_info->sensor_id >= 0x06) {
+ dev_err(&client->dev,
+ "Failed get valid sensor_id(0x%02X), No Config Sent\n",
+ fw_info->sensor_id);
+
+ fw_info->sensor_id = 0xff;
+ }
+
+ return ret;
+}
+
+static int gtp_i2c_test(struct i2c_client *client)
+{
+ u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff};
+ u8 retry = 0;
+ int ret = -1;
+
+ while (retry++ < 3) {
+ ret = gtp_i2c_read(client, test, 3);
+ if (ret == 2)
+ return 0;
+
+ dev_err(&client->dev, "GTP i2c test failed time %d\n", retry);
+ usleep_range(10000, 11000); /* 10 ms */
+ }
+
+ return -EAGAIN;
+}
+
+static int gtp_pinctrl_init(struct goodix_ts_data *ts)
+{
+ struct goodix_pinctrl *pinctrl = &ts->pinctrl;
+
+ pinctrl->pinctrl = devm_pinctrl_get(&ts->client->dev);
+ if (IS_ERR_OR_NULL(pinctrl->pinctrl)) {
+ dev_info(&ts->client->dev, "No pinctrl found\n");
+ pinctrl->pinctrl = NULL;
+ return 0;
+ }
+
+ /* INT pinctrl */
+ pinctrl->int_default = pinctrl_lookup_state(pinctrl->pinctrl,
+ "gdix_ts_int_default");
+ if (IS_ERR_OR_NULL(pinctrl->int_default)) {
+ dev_info(&ts->client->dev,
+ "Failed get pinctrl state:INT default state\n");
+ goto exit_pinctrl_init;
+ }
+
+ pinctrl->int_out_high = pinctrl_lookup_state(pinctrl->pinctrl,
+ "gdix_ts_int_output_high");
+ if (IS_ERR_OR_NULL(pinctrl->int_out_high)) {
+ dev_info(&ts->client->dev,
+ "Failed get pinctrl state:INT output_high\n");
+ goto exit_pinctrl_init;
+ }
+
+ pinctrl->int_out_low = pinctrl_lookup_state(pinctrl->pinctrl,
+ "gdix_ts_int_output_low");
+ if (IS_ERR_OR_NULL(pinctrl->int_out_low)) {
+ dev_info(&ts->client->dev,
+ "Failed get pinctrl state:INT output_low\n");
+ goto exit_pinctrl_init;
+ }
+
+ pinctrl->int_input = pinctrl_lookup_state(pinctrl->pinctrl,
+ "gdix_ts_int_input");
+ if (IS_ERR_OR_NULL(pinctrl->int_input)) {
+ dev_info(&ts->client->dev,
+ "Failed get pinctrl state:int-input\n");
+ goto exit_pinctrl_init;
+ }
+ dev_info(&ts->client->dev, "Success init INT pinctrl\n");
+
+ /* RST pinctrl */
+ pinctrl->rst_default = pinctrl_lookup_state(pinctrl->pinctrl,
+ "gdix_ts_rst_default");
+ if (IS_ERR_OR_NULL(pinctrl->rst_default)) {
+ dev_info(&ts->client->dev,
+ "Failed get pinctrl state:RST default state\n");
+ goto exit_pinctrl_init;
+ }
+
+ pinctrl->rst_out_high = pinctrl_lookup_state(pinctrl->pinctrl,
+ "gdix_ts_rst_output_high");
+ if (IS_ERR_OR_NULL(pinctrl->rst_out_high)) {
+ dev_info(&ts->client->dev,
+ "Failed get pinctrl state:RST output_high\n");
+ goto exit_pinctrl_init;
+ }
+
+ pinctrl->rst_out_low = pinctrl_lookup_state(pinctrl->pinctrl,
+ "gdix_ts_rst_output_low");
+ if (IS_ERR_OR_NULL(pinctrl->rst_out_low)) {
+ dev_info(&ts->client->dev,
+ "Failed get pinctrl state:RST output_low\n");
+ goto exit_pinctrl_init;
+ }
+
+ pinctrl->rst_input = pinctrl_lookup_state(pinctrl->pinctrl,
+ "gdix_ts_rst_input");
+ if (IS_ERR_OR_NULL(pinctrl->rst_input)) {
+ dev_info(&ts->client->dev,
+ "Failed get pinctrl state:rst-input\n");
+ goto exit_pinctrl_init;
+ }
+ dev_info(&ts->client->dev, "Success init RST pinctrl\n");
+
+ return 0;
+exit_pinctrl_init:
+ devm_pinctrl_put(pinctrl->pinctrl);
+ pinctrl->pinctrl = NULL;
+ pinctrl->int_default = NULL;
+ pinctrl->int_out_high = NULL;
+ pinctrl->int_out_low = NULL;
+ pinctrl->int_input = NULL;
+ pinctrl->rst_default = NULL;
+ pinctrl->rst_out_high = NULL;
+ pinctrl->rst_out_low = NULL;
+ pinctrl->rst_input = NULL;
+ return -EINVAL;
+}
+
+static void gtp_pinctrl_deinit(struct goodix_ts_data *ts)
+{
+ if (ts->pinctrl.pinctrl)
+ devm_pinctrl_put(ts->pinctrl.pinctrl);
+}
+
+static int gtp_request_io_port(struct goodix_ts_data *ts)
+{
+ int ret = 0;
+
+ if (gpio_is_valid(ts->pdata->irq_gpio)) {
+ ret = gpio_request(ts->pdata->irq_gpio, "goodix_ts_int");
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Failed to request GPIO:%d, ERRNO:%d\n",
+ (s32)ts->pdata->irq_gpio, ret);
+ return -ENODEV;
+ }
+
+ gpio_direction_input(ts->pdata->irq_gpio);
+ dev_info(&ts->client->dev, "Success request irq-gpio\n");
+ }
+
+ if (gpio_is_valid(ts->pdata->rst_gpio)) {
+ ret = gpio_request(ts->pdata->rst_gpio, "goodix_ts_rst");
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Failed to request GPIO:%d, ERRNO:%d\n",
+ (s32)ts->pdata->rst_gpio, ret);
+
+ if (gpio_is_valid(ts->pdata->irq_gpio))
+ gpio_free(ts->pdata->irq_gpio);
+
+ return -ENODEV;
+ }
+
+ gpio_direction_input(ts->pdata->rst_gpio);
+ dev_info(&ts->client->dev, "Success request rst-gpio\n");
+ }
+
+ return 0;
+}
+
+/*******************************************************
+ * Function:
+ * Request interrupt if define irq pin, else use hrtimer
+ * as interrupt source
+ * Input:
+ * ts: private data.
+ * Output:
+ * Executive outcomes.
+ * 0: succeed, -1: failed.
+ *******************************************************/
+static int gtp_request_irq(struct goodix_ts_data *ts)
+{
+ int ret = -1;
+
+ /* use irq */
+ if (gpio_is_valid(ts->pdata->irq_gpio) || ts->client->irq > 0) {
+ if (gpio_is_valid(ts->pdata->irq_gpio))
+ ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio);
+
+ dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n",
+ ts->client->irq, ts->pdata->irq_flags);
+ ret = request_threaded_irq(ts->client->irq, NULL,
+ gtp_irq_handler,
+ ts->pdata->irq_flags | IRQF_ONESHOT,
+ ts->client->name,
+ ts);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Failed to request irq %d\n", ts->client->irq);
+ return ret;
+ }
+ } else { /* use hrtimer */
+ dev_info(&ts->client->dev, "No hardware irq, use hrtimer\n");
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ts->timer.function = gtp_timer_handler;
+ hrtimer_start(&ts->timer,
+ ktime_set(0, (GTP_POLL_TIME + 6) * 1000000),
+ HRTIMER_MODE_REL);
+ set_bit(HRTIMER_USED, &ts->flags);
+ ret = 0;
+ }
+ return ret;
+}
+
+static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
+{
+ s8 ret = -1;
+ u8 index = 0;
+
+ ts->input_dev = input_allocate_device();
+ if (!ts->input_dev) {
+ dev_err(&ts->client->dev, "Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY)
+ | BIT_MASK(EV_ABS);
+ if (!ts->pdata->type_a_report) {
+ input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT);
+ dev_info(&ts->client->dev, "Use slot report protocol\n");
+ } else {
+ __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+ __set_bit(BTN_TOUCH, ts->input_dev->keybit);
+ dev_info(&ts->client->dev, "Use type A report protocol\n");
+ }
+
+ input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON1);
+ input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON2);
+
+ /* touch key register */
+ for (index = 0; index < ts->pdata->key_nums; index++)
+ input_set_capability(ts->input_dev, EV_KEY,
+ ts->pdata->key_map[index]);
+
+ if (ts->pdata->slide_wakeup)
+ input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
+
+ if (ts->pdata->swap_x2y)
+ GTP_SWAP(ts->pdata->abs_size_x, ts->pdata->abs_size_y);
+
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
+ ts->pdata->abs_size_x, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
+ ts->pdata->abs_size_y, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0,
+ ts->pdata->max_touch_width, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0,
+ ts->pdata->max_touch_pressure, 0, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0,
+ ts->pdata->max_touch_id, 0, 0);
+ if (!ts->pdata->type_a_report) {
+ input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE,
+ 0, MT_TOOL_MAX, 0, 0);
+ } else {
+ __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
+ __set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit);
+ }
+
+ ts->input_dev->name = goodix_ts_name;
+ ts->input_dev->phys = goodix_input_phys;
+ ts->input_dev->id.bustype = BUS_I2C;
+ ts->input_dev->id.vendor = 0xDEAD;
+ ts->input_dev->id.product = 0xBEEF;
+ ts->input_dev->id.version = 10427;
+
+ ret = input_register_device(ts->input_dev);
+ if (ret) {
+ dev_err(&ts->client->dev, "Register %s input device failed\n",
+ ts->input_dev->name);
+ input_free_device(ts->input_dev);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/*
+ * Devices Tree support
+ */
+#ifdef CONFIG_OF
+static void gtp_parse_dt_coords(struct device *dev,
+ struct goodix_ts_platform_data *pdata)
+{
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ ret = of_property_read_u32(np, "touchscreen-max-id",
+ &pdata->max_touch_id);
+ if (ret || pdata->max_touch_id > GTP_MAX_TOUCH_ID) {
+ dev_info(dev, "Unset touchscreen-max-id, use default\n");
+ pdata->max_touch_id = GTP_MAX_TOUCH_ID;
+ }
+
+ ret = of_property_read_u32(np, "touchscreen-size-x",
+ &pdata->abs_size_x);
+ if (ret) {
+ dev_info(dev, "Unset touchscreen-size-x, use default\n");
+ pdata->abs_size_x = GTP_DEFAULT_MAX_X;
+ }
+
+ ret = of_property_read_u32(np, "touchscreen-size-y",
+ &pdata->abs_size_y);
+ if (ret) {
+ dev_info(dev, "Unset touchscreen-size-y, use default\n");
+ pdata->abs_size_y = GTP_DEFAULT_MAX_Y;
+ }
+
+ ret = of_property_read_u32(np, "touchscreen-max-w",
+ &pdata->max_touch_width);
+ if (ret) {
+ dev_info(dev, "Unset touchscreen-max-w, use default\n");
+ pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH;
+ }
+
+ ret = of_property_read_u32(np, "touchscreen-max-p",
+ &pdata->max_touch_pressure);
+ if (ret) {
+ dev_info(dev, "Unset touchscreen-max-p, use default\n");
+ pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE;
+ }
+ dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n",
+ pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y,
+ pdata->max_touch_width, pdata->max_touch_pressure);
+}
+
+static int gtp_parse_dt(struct device *dev,
+ struct goodix_ts_platform_data *pdata)
+{
+ int ret;
+ u32 key_nums;
+ struct property *prop;
+ u32 key_map[MAX_KEY_NUMS];
+ struct device_node *np = dev->of_node;
+
+ gtp_parse_dt_coords(dev, pdata);
+
+ ret = of_property_read_u32(np, "irq-flags",
+ &pdata->irq_flags);
+ if (ret) {
+ dev_info(dev,
+ "Failed get int-trigger-type from dts,set default\n");
+ pdata->irq_flags = GTP_DEFAULT_INT_TRIGGER;
+ }
+ of_property_read_u32(np, "goodix,int-sync", &pdata->int_sync);
+ if (pdata->int_sync)
+ dev_info(dev, "int-sync enabled\n");
+
+ of_property_read_u32(np, "goodix,driver-send-cfg",
+ &pdata->driver_send_cfg);
+ if (pdata->driver_send_cfg)
+ dev_info(dev, "driver-send-cfg enabled\n");
+
+ of_property_read_u32(np, "goodix,swap-x2y", &pdata->swap_x2y);
+ if (pdata->swap_x2y)
+ dev_info(dev, "swap-x2y enabled\n");
+
+ of_property_read_u32(np, "goodix,slide-wakeup", &pdata->slide_wakeup);
+ if (pdata->slide_wakeup)
+ dev_info(dev, "slide-wakeup enabled\n");
+
+ of_property_read_u32(np, "goodix,auto-update", &pdata->auto_update);
+ if (pdata->auto_update)
+ dev_info(dev, "auto-update enabled\n");
+
+ of_property_read_u32(np, "goodix,auto-update-cfg",
+ &pdata->auto_update_cfg);
+ if (pdata->auto_update_cfg)
+ dev_info(dev, "auto-update-cfg enabled\n");
+
+ of_property_read_u32(np, "goodix,esd-protect", &pdata->esd_protect);
+ if (pdata->esd_protect)
+ dev_info(dev, "esd-protect enabled\n");
+
+ of_property_read_u32(np, "goodix,type-a-report",
+ &pdata->type_a_report);
+ if (pdata->type_a_report)
+ dev_info(dev, "type-a-report enabled\n");
+
+ of_property_read_u32(np, "goodix,resume-in-workqueue",
+ &pdata->resume_in_workqueue);
+ if (pdata->resume_in_workqueue)
+ dev_info(dev, "resume-in-workqueue enabled\n");
+
+ of_property_read_u32(np, "goodix,power-off-sleep",
+ &pdata->power_off_sleep);
+ if (pdata->power_off_sleep)
+ dev_info(dev, "power-off-sleep enabled\n");
+
+ of_property_read_u32(np, "goodix,pen-suppress-finger",
+ &pdata->pen_suppress_finger);
+ if (pdata->pen_suppress_finger)
+ dev_info(dev, "pen-suppress-finger enabled\n");
+
+ prop = of_find_property(np, "touchscreen-key-map", NULL);
+ if (prop) {
+ key_nums = prop->length / sizeof(key_map[0]);
+ key_nums = key_nums > MAX_KEY_NUMS ? MAX_KEY_NUMS : key_nums;
+
+ dev_dbg(dev, "key nums %d\n", key_nums);
+ ret = of_property_read_u32_array(np,
+ "touchscreen-key-map", key_map,
+ key_nums);
+ if (ret) {
+ dev_err(dev, "Unable to read key codes\n");
+ pdata->key_nums = 0;
+ memset(pdata->key_map, 0,
+ MAX_KEY_NUMS * sizeof(pdata->key_map[0]));
+ }
+ pdata->key_nums = key_nums;
+ memcpy(pdata->key_map, key_map,
+ key_nums * sizeof(pdata->key_map[0]));
+ dev_info(dev, "key-map is [%x %x %x %x]\n",
+ pdata->key_map[0], pdata->key_map[1],
+ pdata->key_map[2], pdata->key_map[3]);
+ }
+
+ pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0);
+ if (!gpio_is_valid(pdata->irq_gpio))
+ dev_err(dev, "No valid irq gpio");
+
+ pdata->rst_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+ if (!gpio_is_valid(pdata->rst_gpio))
+ dev_err(dev, "No valid rst gpio");
+
+ return 0;
+}
+
+/*******************************************************
+ * Function:
+ * parse config data from devices tree.
+ * Input:
+ * dev: device that this driver attached.
+ * cfg: pointer of the config array.
+ * cfg_len: pointer of the config length.
+ * sid: sensor id.
+ * Output:
+ * Executive outcomes.
+ * 0-succeed, -1-faileds.
+ *******************************************************/
+int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid)
+{
+ struct device_node *np = dev->of_node;
+ struct property *prop;
+ char cfg_name[18];
+ int ret;
+
+ snprintf(cfg_name, sizeof(cfg_name), "goodix,cfg-group%d", sid);
+ prop = of_find_property(np, cfg_name, cfg_len);
+ if (!prop || !prop->value || *cfg_len == 0 ||
+ *cfg_len > GTP_CONFIG_MAX_LENGTH) {
+ *cfg_len = 0;
+ ret = -EPERM;/* failed */
+ } else {
+ memcpy(cfg, prop->value, *cfg_len);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+#endif
+
+static int gtp_power_on(struct goodix_ts_data *ts)
+{
+ int ret = 0;
+
+ if (ts->vdd_ana) {
+ ret = regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV,
+ GOODIX_VTG_MAX_UV);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator set_vtg failed vdd ret=%d\n",
+ ret);
+ goto err_set_vtg_vdd_ana;
+ }
+ ret = regulator_enable(ts->vdd_ana);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator vdd enable failed ret=%d\n",
+ ret);
+ goto err_enable_vdd_ana;
+ }
+ }
+
+ if (ts->vcc_i2c) {
+ ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
+ GOODIX_I2C_VTG_MAX_UV);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator set_vtg failed vcc_i2c ret=%d\n",
+ ret);
+ goto err_set_vtg_vcc_i2c;
+ }
+ ret = regulator_enable(ts->vcc_i2c);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator vcc_i2c enable failed ret=%d\n",
+ ret);
+ goto err_enable_vcc_i2c;
+ }
+ }
+ clear_bit(POWER_OFF_MODE, &ts->flags);
+ return 0;
+
+err_enable_vcc_i2c:
+ if (ts->vcc_i2c)
+ regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV);
+err_set_vtg_vcc_i2c:
+ if (ts->vdd_ana)
+ regulator_disable(ts->vdd_ana);
+err_enable_vdd_ana:
+ if (ts->vdd_ana)
+ regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV);
+err_set_vtg_vdd_ana:
+ set_bit(POWER_OFF_MODE, &ts->flags);
+ return ret;
+}
+
+static int gtp_power_off(struct goodix_ts_data *ts)
+{
+ int ret = 0;
+
+ if (ts->vcc_i2c) {
+ set_bit(POWER_OFF_MODE, &ts->flags);
+ ret = regulator_set_voltage(ts->vcc_i2c, 0,
+ GOODIX_I2C_VTG_MAX_UV);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Regulator vcc_i2c set_vtg failed ret=%d\n",
+ ret);
+ goto err_set_vtg_vcc_i2c;
+ }
+ ret = regulator_disable(ts->vcc_i2c);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator vcc_i2c disable failed ret=%d\n",
+ ret);
+ goto err_disable_vcc_i2c;
+ }
+ dev_info(&ts->client->dev,
+ "Regulator vcc_i2c disabled\n");
+ }
+
+ if (ts->vdd_ana) {
+ set_bit(POWER_OFF_MODE, &ts->flags);
+ ret = regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV);
+ if (ret < 0) {
+ dev_err(&ts->client->dev,
+ "Regulator vdd set_vtg failed ret=%d\n",
+ ret);
+ goto err_set_vtg_vdd_ana;
+ }
+ ret = regulator_disable(ts->vdd_ana);
+ if (ret) {
+ dev_err(&ts->client->dev,
+ "Regulator vdd disable failed ret=%d\n",
+ ret);
+ goto err_disable_vdd_ana;
+ }
+ dev_info(&ts->client->dev,
+ "Regulator vdd_ana disabled\n");
+ }
+ return ret;
+
+err_disable_vdd_ana:
+ if (ts->vdd_ana)
+ regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV,
+ GOODIX_VTG_MAX_UV);
+err_set_vtg_vdd_ana:
+ if (ts->vcc_i2c)
+ ret = regulator_enable(ts->vcc_i2c);
+err_disable_vcc_i2c:
+ if (ts->vcc_i2c)
+ regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV,
+ GOODIX_I2C_VTG_MAX_UV);
+err_set_vtg_vcc_i2c:
+ clear_bit(POWER_OFF_MODE, &ts->flags);
+ return ret;
+}
+
+static int gtp_power_init(struct goodix_ts_data *ts)
+{
+ int ret;
+
+ ts->vdd_ana = regulator_get(&ts->client->dev, "vdd_ana");
+ if (IS_ERR(ts->vdd_ana)) {
+ ts->vdd_ana = NULL;
+ ret = PTR_ERR(ts->vdd_ana);
+ dev_info(&ts->client->dev,
+ "Regulator get failed vdd ret=%d\n", ret);
+ }
+
+ ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c");
+ if (IS_ERR(ts->vcc_i2c)) {
+ ts->vcc_i2c = NULL;
+ ret = PTR_ERR(ts->vcc_i2c);
+ dev_info(&ts->client->dev,
+ "Regulator get failed vcc_i2c ret=%d\n", ret);
+ }
+ return 0;
+}
+
+static int gtp_power_deinit(struct goodix_ts_data *ts)
+{
+ if (ts->vdd_ana)
+ regulator_put(ts->vdd_ana);
+ if (ts->vcc_i2c)
+ regulator_put(ts->vcc_i2c);
+
+ return 0;
+}
+
+static void gtp_shutdown(struct i2c_client *client)
+{
+ struct goodix_ts_data *data = i2c_get_clientdata(client);
+
+ if (!data->init_done)
+ return;
+
+ gtp_work_control_enable(data, false);
+ gtp_power_off(data);
+}
+
+static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ int ret = -1;
+ struct goodix_ts_data *ts;
+ struct goodix_ts_platform_data *pdata;
+
+ /* do NOT remove these logs */
+ dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION);
+ dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr);
+
+ i2c_connect_client = client;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "Failed check I2C functionality");
+ return -ENODEV;
+ }
+
+ ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ devm_kfree(&client->dev, ts);
+ return -EINVAL;
+ }
+
+ ts->init_done = false;
+
+#ifdef CONFIG_OF
+ if (client->dev.of_node) {
+ ret = gtp_parse_dt(&client->dev, pdata);
+ if (ret) {
+ dev_err(&client->dev, "Failed parse dts\n");
+ goto exit_free_client_data;
+ }
+ }
+#else
+ /* set parameters at here if you platform doesn't DTS */
+ pdata->rst_gpio = GTP_RST_PORT;
+ pdata->irq_gpio = GTP_INT_PORT;
+ pdata->slide_wakeup = false;
+ pdata->auto_update = true;
+ pdata->auto_update_cfg = false;
+ pdata->type_a_report = false;
+ pdata->esd_protect = false;
+ pdata->max_touch_id = GTP_MAX_TOUCH_ID;
+ pdata->abs_size_x = GTP_DEFAULT_MAX_X;
+ pdata->abs_size_y = GTP_DEFAULT_MAX_Y;
+ pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH;
+ pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE;
+#endif
+
+ ts->client = client;
+ ts->pdata = pdata;
+
+ i2c_set_clientdata(client, ts);
+
+ ret = gtp_power_init(ts);
+ if (ret) {
+ dev_err(&client->dev, "Failed get regulator\n");
+ ret = -EINVAL;
+ goto exit_free_client_data;
+ }
+
+ ret = gtp_pinctrl_init(ts);
+ if (ret < 0) {
+ /* if define pinctrl must define the following state
+ * to let int-pin work normally: default, int_output_high,
+ * int_output_low, int_input
+ */
+ dev_err(&client->dev, "Failed get wanted pinctrl state\n");
+ goto exit_deinit_power;
+ }
+
+ ret = gtp_request_io_port(ts);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed request IO port\n");
+ goto exit_pinctrl;
+ }
+
+ /*wait for discharging power, which from i2c pull-up flow backward*/
+ gtp_rst_output(ts, 0);
+ msleep(DELAY_FOR_DISCHARGING);
+
+ ret = gtp_power_on(ts);
+ if (ret) {
+ dev_err(&client->dev, "Failed power on device\n");
+ ret = -EINVAL;
+ goto exit_free_io_port;
+ }
+
+ gtp_reset_guitar(ts->client, 20);
+
+ ret = gtp_i2c_test(client);
+ if (ret) {
+ dev_err(&client->dev, "Failed communicate with IC use I2C\n");
+ goto exit_power_off;
+ }
+
+ dev_info(&client->dev, "I2C Addr is %x\n", client->addr);
+
+ ret = gtp_get_fw_info(client, &ts->fw_info);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed read FW version\n");
+ goto exit_power_off;
+ }
+
+ pdata->config.data[0] = GTP_REG_CONFIG_DATA >> 8;
+ pdata->config.data[1] = GTP_REG_CONFIG_DATA & 0xff;
+ ret = gtp_init_panel(ts);
+ if (ret < 0)
+ dev_info(&client->dev, "Panel un-initialize\n");
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+ if (ts->pdata->auto_update) {
+ ret = gup_init_update_proc(ts);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed create update thread\n");
+ }
+#endif
+
+ ret = gtp_request_input_dev(ts);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed request input device\n");
+ goto exit_power_off;
+ }
+
+ mutex_init(&ts->lock);
+
+ ret = gtp_request_irq(ts);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed create work thread");
+ goto exit_unreg_input_dev;
+ }
+ gtp_work_control_enable(ts, false);
+ if (ts->pdata->slide_wakeup) {
+ dev_info(&client->dev, "slide wakeup enabled\n");
+ ret = enable_irq_wake(client->irq);
+ if (ret < 0)
+ dev_err(&client->dev, "Failed set irq wake\n");
+ }
+
+ gtp_register_powermanager(ts);
+
+ ret = gtp_create_file(ts);
+ if (ret) {
+ dev_info(&client->dev, "Failed create attributes file");
+ goto exit_powermanager;
+ }
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL
+ init_wr_node(client);/*TODO judge return value */
+#endif
+
+ gtp_esd_init(ts);
+ gtp_esd_on(ts);
+ /* probe init finished */
+ ts->init_done = true;
+ gtp_work_control_enable(ts, true);
+
+ return 0;
+
+exit_powermanager:
+ gtp_unregister_powermanager(ts);
+exit_unreg_input_dev:
+ input_unregister_device(ts->input_dev);
+exit_power_off:
+ gtp_power_off(ts);
+exit_free_io_port:
+ if (gpio_is_valid(ts->pdata->rst_gpio))
+ gpio_free(ts->pdata->rst_gpio);
+ if (gpio_is_valid(ts->pdata->irq_gpio))
+ gpio_free(ts->pdata->irq_gpio);
+exit_pinctrl:
+ gtp_pinctrl_deinit(ts);
+exit_deinit_power:
+ gtp_power_deinit(ts);
+exit_free_client_data:
+ devm_kfree(&client->dev, pdata);
+ devm_kfree(&client->dev, ts);
+ i2c_set_clientdata(client, NULL);
+
+ return ret;
+}
+
+static int gtp_drv_remove(struct i2c_client *client)
+{
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ gtp_work_control_enable(ts, false);
+ gtp_unregister_powermanager(ts);
+
+ remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc);
+
+ sysfs_remove_group(&client->dev.kobj, >p_attr_group);
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL
+ uninit_wr_node();
+#endif
+
+ if (ts->pdata->esd_protect)
+ gtp_esd_off(ts);
+
+ /* TODO: how to judge a irq numbers validity */
+ if (ts->client->irq)
+ free_irq(client->irq, ts);
+ else
+ hrtimer_cancel(&ts->timer);
+
+ if (gpio_is_valid(ts->pdata->rst_gpio))
+ gpio_free(ts->pdata->rst_gpio);
+
+ if (gpio_is_valid(ts->pdata->irq_gpio))
+ gpio_free(ts->pdata->irq_gpio);
+
+ gtp_power_off(ts);
+ gtp_power_deinit(ts);
+ gtp_pinctrl_deinit(ts);
+ dev_info(&client->dev, "goodix ts driver removed");
+ i2c_set_clientdata(client, NULL);
+ input_unregister_device(ts->input_dev);
+ mutex_destroy(&ts->lock);
+
+ devm_kfree(&client->dev, ts->pdata);
+ devm_kfree(&client->dev, ts);
+
+ return 0;
+}
+
+static void gtp_suspend(struct goodix_ts_data *ts)
+{
+ int ret = -1;
+
+ if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
+ dev_warn(&ts->client->dev,
+ "Fw upgrade in progress, can't go to suspend\n");
+ return;
+ }
+
+ if (test_and_set_bit(SLEEP_MODE, &ts->flags)) {
+ dev_info(&ts->client->dev, "Already in suspend state\n");
+ return;
+ }
+
+ dev_dbg(&ts->client->dev, "Try enter suspend mode\n");
+
+ gtp_esd_off(ts);
+ gtp_work_control_enable(ts, false);
+ if (ts->pdata->slide_wakeup) {
+ ret = gtp_enter_doze(ts);
+ gtp_work_control_enable(ts, true);
+ } else if (ts->pdata->power_off_sleep) {
+ /*TODO: power off routine */
+ gtp_power_off(ts);
+ ret = SUCCESS;
+ } else {
+ ret = gtp_enter_sleep(ts);
+ }
+
+ if (ret < 0)
+ dev_err(&ts->client->dev, "Failed enter suspend\n");
+
+ /* to avoid waking up while not sleeping */
+ /* delay 48 + 10ms to ensure reliability */
+ msleep(GTP_58_DLY_MS);
+}
+
+static int gtp_gesture_wakeup(struct goodix_ts_data *ts)
+{
+ int ret;
+ int retry = 10;
+
+ do {
+ gtp_reset_guitar(ts->client, 10);
+ ret = gtp_i2c_test(ts->client);
+ if (!ret)
+ break;
+ } while (--retry);
+
+ if (!retry)
+ ret = -EIO;
+
+ clear_bit(DOZE_MODE, &ts->flags);
+ return ret;
+}
+
+static void gtp_resume(struct goodix_ts_data *ts)
+{
+ int ret = 0;
+
+ if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
+ dev_info(&ts->client->dev,
+ "Fw upgrade in progress, can't do resume\n");
+ return;
+ }
+
+ if (!test_bit(SLEEP_MODE, &ts->flags)) {
+ dev_dbg(&ts->client->dev, "Already in awake state\n");
+ return;
+ }
+
+ dev_info(&ts->client->dev, "Try resume from sleep mode\n");
+
+ gtp_work_control_enable(ts, false);
+
+ if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) {
+ ret = gtp_gesture_wakeup(ts);
+ if (ret)
+ dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n");
+ } else if (ts->pdata->power_off_sleep) {
+ ret = gtp_power_on(ts);
+ if (ret) {
+ dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n");
+ } else {
+ gtp_reset_guitar(ts->client, 20);
+ ret = gtp_i2c_test(ts->client);
+ if (ret)
+ dev_warn(&ts->client->dev,
+ "I2C communicate failed after power on\n");
+ }
+ } else {
+ ret = gtp_wakeup_sleep(ts);
+ if (ret)
+ dev_warn(&ts->client->dev,
+ "Failed wakeup from sleep mode\n");
+ }
+
+ if (ret)
+ dev_warn(&ts->client->dev, "Later resume failed\n");
+ else
+ gtp_esd_on(ts);
+
+ clear_bit(SLEEP_MODE, &ts->flags);
+ gtp_work_control_enable(ts, true);
+}
+
+#if defined(CONFIG_FB)
+static void fb_notify_resume_work(struct work_struct *work)
+{
+ struct goodix_ts_data *ts =
+ container_of(work, struct goodix_ts_data, fb_notify_work);
+ dev_info(&ts->client->dev, "try resume in workqueue\n");
+ gtp_resume(ts);
+}
+
+/* frame buffer notifier block control the suspend/resume procedure */
+static int gtp_fb_notifier_callback(struct notifier_block *noti,
+ unsigned long event, void *data)
+{
+ struct fb_event *ev_data = data;
+ struct goodix_ts_data *ts = container_of(noti,
+ struct goodix_ts_data, notifier);
+ int *blank;
+
+ if (ev_data && ev_data->data && event == FB_EVENT_BLANK && ts) {
+ blank = ev_data->data;
+ if (*blank == FB_BLANK_UNBLANK ||
+ *blank == FB_BLANK_NORMAL) {
+ dev_dbg(&ts->client->dev, "ts_resume");
+ if (ts->pdata->resume_in_workqueue)
+ schedule_work(&ts->fb_notify_work);
+ else
+ gtp_resume(ts);
+ } else if (*blank == FB_BLANK_POWERDOWN) {
+ dev_dbg(&ts->client->dev, "ts_suspend");
+ if (ts->pdata->resume_in_workqueue)
+ flush_work(&ts->fb_notify_work);
+ gtp_suspend(ts);
+ }
+ }
+
+ return 0;
+}
+
+#elif defined(CONFIG_PM)
+static int gtp_pm_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts) {
+ dev_dbg(&ts->client->dev, "Suspend by i2c pm.");
+ gtp_suspend(ts);
+ }
+
+ return 0;
+}
+
+static int gtp_pm_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts) {
+ dev_dbg(&ts->client->dev, "Resume by i2c pm.");
+ gtp_resume(ts);
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops gtp_pm_ops = {
+ .suspend = gtp_pm_suspend,
+ .resume = gtp_pm_resume,
+};
+
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+static void gtp_early_suspend(struct early_suspend *h)
+{
+ struct goodix_ts_data *ts = container_of(h,
+ struct goodix_ts_data, early_suspend);
+
+ if (ts) {
+ dev_dbg(&ts->client->dev, "Suspend by earlysuspend module.");
+ gtp_suspend(ts);
+ }
+}
+
+static void gtp_late_resume(struct early_suspend *h)
+{
+ struct goodix_ts_data *ts = container_of(h,
+ struct goodix_ts_data, early_suspend);
+
+ if (ts) {
+ dev_dbg(&ts->client->dev, "Resume by earlysuspend module.");
+ gtp_resume(ts);
+ }
+}
+#endif
+
+static int gtp_register_powermanager(struct goodix_ts_data *ts)
+{
+ int ret;
+#if defined(CONFIG_FB)
+ INIT_WORK(&ts->fb_notify_work, fb_notify_resume_work);
+ ts->notifier.notifier_call = gtp_fb_notifier_callback;
+ ret = fb_register_client(&ts->notifier);
+ if (ret)
+ dev_err(&ts->client->dev,
+ "Unable to register fb_notifier: %d\n", ret);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ ts->early_suspend.suspend = goodix_ts_early_suspend;
+ ts->early_suspend.resume = goodix_ts_late_resume;
+ register_early_suspend(&ts->early_suspend);
+#endif
+
+ return ret;
+}
+
+static int gtp_unregister_powermanager(struct goodix_ts_data *ts)
+{
+#if defined(CONFIG_FB)
+ fb_unregister_client(&ts->notifier);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ unregister_early_suspend(&ts->early_suspend);
+#endif
+
+ return 0;
+}
+
+/*******************************************************
+ * Function:
+ * Initialize external watchdog for esd protect
+ * Input:
+ * client: i2c device.
+ * Output:
+ * result of i2c write operation.
+ * 0: succeed, otherwise: failed
+ ********************************************************/
+static int gtp_init_ext_watchdog(struct i2c_client *client)
+{
+ int ret;
+ u8 opr_buffer[3] = { (u8)(GTP_REG_ESD_CHECK >> 8),
+ (u8)GTP_REG_ESD_CHECK,
+ (u8)GTP_ESD_CHECK_VALUE };
+
+ dev_dbg(&client->dev, "[Esd]Init external watchdog\n");
+ ret = gtp_i2c_write(client, opr_buffer, 3);
+ if (ret == 1)
+ return 0;
+
+ dev_err(&client->dev, "Failed init ext watchdog\n");
+ return -EINVAL;
+}
+
+static void gtp_esd_check_func(struct work_struct *work)
+{
+ s32 i;
+ s32 ret = -1;
+ u8 esd_buf[5] = { (u8)(GTP_REG_COMMAND >> 8), (u8)GTP_REG_COMMAND };
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct goodix_ts_esd *ts_esd = container_of(dwork, struct goodix_ts_esd,
+ delayed_work);
+ struct goodix_ts_data *ts = container_of(ts_esd, struct goodix_ts_data,
+ ts_esd);
+
+ if (test_bit(SLEEP_MODE, &ts->flags) ||
+ test_bit(FW_UPDATE_RUNNING, &ts->flags)) {
+ dev_dbg(&ts->client->dev,
+ "Esd cancled by power_suspend or fw_update!");
+ return;
+ }
+
+ if (ts_esd->esd_on == false)
+ return;
+
+ for (i = 0; i < 3; i++) {
+ ret = gtp_i2c_read(ts->client, esd_buf, 4);
+ if (ret < 0)
+ continue;
+
+ dev_dbg(&ts->client->dev,
+ "[Esd]0x8040 = 0x%02X, 0x8041 = 0x%02X",
+ esd_buf[2], esd_buf[3]);
+ if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE ||
+ esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) {
+ gtp_i2c_read(ts->client, esd_buf, 4);
+ if (ret < 0)
+ continue;
+
+ if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE ||
+ esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) {
+ i = 3;
+ break;
+ }
+ } else {
+ /* IC works normally, Write 0x8040 0xAA, feed the dog */
+ esd_buf[2] = (u8)GTP_ESD_CHECK_VALUE;
+ gtp_i2c_write(ts->client, esd_buf, 3);
+ break;
+ }
+ }
+ if (i >= 3) {
+ dev_err(&ts->client->dev, "IC working abnormally! Reset IC\n");
+ esd_buf[0] = 0x42;
+ esd_buf[1] = 0x26;
+ esd_buf[2] = 0x01;
+ esd_buf[3] = 0x01;
+ esd_buf[4] = 0x01;
+ gtp_i2c_write(ts->client, esd_buf, 5);
+ /* TODO: Is power off really need? */
+ msleep(GTP_50_DLY_MS);
+ gtp_power_off(ts);
+ msleep(GTP_20_DLY_MS);
+ gtp_power_on(ts);
+ msleep(GTP_20_DLY_MS);
+
+ gtp_reset_guitar(ts->client, 50);
+ msleep(GTP_50_DLY_MS);
+ gtp_send_cfg(ts->client);
+ }
+
+ if (ts_esd->esd_on == true && !test_bit(SLEEP_MODE, &ts->flags)) {
+ schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ);
+ dev_dbg(&ts->client->dev, "ESD work rescheduled\n");
+ }
+}
+
+static int gtp_esd_init(struct goodix_ts_data *ts)
+{
+ struct goodix_ts_esd *ts_esd = &ts->ts_esd;
+
+ INIT_DELAYED_WORK(&ts_esd->delayed_work, gtp_esd_check_func);
+ mutex_init(&ts_esd->mutex);
+ ts_esd->esd_on = false;
+
+ return 0;
+}
+
+void gtp_esd_on(struct goodix_ts_data *ts)
+{
+ struct goodix_ts_esd *ts_esd = &ts->ts_esd;
+
+ if (!ts->pdata->esd_protect)
+ return;
+ mutex_lock(&ts_esd->mutex);
+ if (ts_esd->esd_on == false) {
+ ts_esd->esd_on = true;
+ schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ);
+ dev_info(&ts->client->dev, "ESD on");
+ }
+ mutex_unlock(&ts_esd->mutex);
+}
+
+void gtp_esd_off(struct goodix_ts_data *ts)
+{
+ struct goodix_ts_esd *ts_esd = &ts->ts_esd;
+
+ if (!ts->pdata->esd_protect)
+ return;
+ mutex_lock(&ts_esd->mutex);
+ if (ts_esd->esd_on == true) {
+ ts_esd->esd_on = false;
+ cancel_delayed_work_sync(&ts_esd->delayed_work);
+ dev_info(&ts->client->dev, "ESD off");
+ }
+ mutex_unlock(&ts_esd->mutex);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id gtp_match_table[] = {
+ {.compatible = "goodix,gt9xx",},
+ { },
+};
+#endif
+
+static const struct i2c_device_id gtp_device_id[] = {
+ { GTP_I2C_NAME, 0 },
+ { }
+};
+
+static struct i2c_driver goodix_ts_driver = {
+ .probe = gtp_probe,
+ .remove = gtp_drv_remove,
+ .id_table = gtp_device_id,
+ .shutdown = gtp_shutdown,
+ .driver = {
+ .name = GTP_I2C_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = gtp_match_table,
+#endif
+#if !defined(CONFIG_FB) && defined(CONFIG_PM)
+ .pm = >p_pm_ops,
+#endif
+ },
+};
+
+static int __init gtp_init(void)
+{
+ s32 ret;
+
+ pr_info("Gt9xx driver installing..\n");
+ ret = i2c_add_driver(&goodix_ts_driver);
+
+ return ret;
+}
+
+static void __exit gtp_exit(void)
+{
+ pr_info("Gt9xx driver exited\n");
+ i2c_del_driver(&goodix_ts_driver);
+}
+
+module_init(gtp_init);
+module_exit(gtp_exit);
+
+MODULE_DESCRIPTION("GT9 serials touch controller Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h
new file mode 100644
index 0000000..78fa338
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h
@@ -0,0 +1,375 @@
+/*
+ * Goodix GT9xx touchscreen driver
+ *
+ * Copyright (C) 2016 - 2017 Goodix. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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.
+ *
+ * Version: 2.8.0.2
+ * Release Date: 2017/12/14
+ */
+
+#ifndef _GOODIX_GT9XX_H_
+#define _GOODIX_GT9XX_H_
+
+#include <linux/kernel.h>
+#include <linux/hrtimer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/major.h>
+#include <linux/kdev_t.h>
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#ifdef CONFIG_FB
+#include <linux/notifier.h>
+#include <linux/fb.h>
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/usb.h>
+#include <linux/power_supply.h>
+
+#define GTP_TOOL_PEN 1
+#define GTP_TOOL_FINGER 2
+
+#define MAX_KEY_NUMS 4
+#define GTP_CONFIG_MAX_LENGTH 240
+#define GTP_ADDR_LENGTH 2
+
+/***************************PART1:ON/OFF define*******************************/
+#define GTP_DEBUG_ON 1
+#define GTP_DEBUG_ARRAY_ON 0
+#define GTP_DEBUG_FUNC_ON 0
+
+struct goodix_point_t {
+ int id;
+ int x;
+ int y;
+ int w;
+ int p;
+ int tool_type;
+};
+
+struct goodix_config_data {
+ int length;
+ u8 data[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH];
+};
+
+struct goodix_ts_platform_data {
+ int irq_gpio;
+ int rst_gpio;
+ u32 irq_flags;
+ u32 abs_size_x;
+ u32 abs_size_y;
+ u32 max_touch_id;
+ u32 max_touch_width;
+ u32 max_touch_pressure;
+ u32 key_map[MAX_KEY_NUMS];
+ u32 key_nums;
+ u32 int_sync;
+ u32 driver_send_cfg;
+ u32 swap_x2y;
+ u32 slide_wakeup;
+ u32 auto_update;
+ u32 auto_update_cfg;
+ u32 esd_protect;
+ u32 type_a_report;
+ u32 power_off_sleep;
+ u32 resume_in_workqueue;
+ u32 pen_suppress_finger;
+ struct goodix_config_data config;
+};
+
+struct goodix_ts_esd {
+ struct delayed_work delayed_work;
+ struct mutex mutex;
+ bool esd_on;
+};
+
+enum {
+ REPORT_THREAD_ENABLED = 0,
+ HRTIMER_USED,
+ FW_ERROR,
+
+ DOZE_MODE,
+ SLEEP_MODE,
+ POWER_OFF_MODE,
+ RAW_DATA_MODE,
+
+ FW_UPDATE_RUNNING,
+ PANEL_RESETTING
+};
+
+struct goodix_pinctrl {
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *int_default;
+ struct pinctrl_state *int_out_high;
+ struct pinctrl_state *int_out_low;
+ struct pinctrl_state *int_input;
+ struct pinctrl_state *rst_default;
+ struct pinctrl_state *rst_out_high;
+ struct pinctrl_state *rst_out_low;
+ struct pinctrl_state *rst_input;
+};
+
+struct goodix_fw_info {
+ u8 pid[6];
+ u16 version;
+ u8 sensor_id;
+};
+
+struct goodix_ts_data {
+ unsigned long flags; /* This member record the device status */
+
+ struct goodix_ts_esd ts_esd;
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct input_dev *pen_dev;
+ struct goodix_ts_platform_data *pdata;
+ /* use pinctrl control int-pin output low or high */
+ struct goodix_pinctrl pinctrl;
+ struct hrtimer timer;
+ struct mutex lock;
+ struct notifier_block ps_notif;
+ struct regulator *vdd_ana;
+ struct regulator *vcc_i2c;
+#if defined(CONFIG_FB)
+ struct notifier_block notifier;
+ struct work_struct fb_notify_work;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ struct early_suspend early_suspend;
+#endif
+ struct goodix_fw_info fw_info;
+ bool force_update;
+ bool init_done;
+};
+
+/************************* PART2:TODO define *******************************/
+/* STEP_1(REQUIRED): Define Configuration Information Group(s)
+ * Sensor_ID Map:
+ * sensor_opt1 sensor_opt2 Sensor_ID
+ * GND GND 0
+ * VDDIO GND 1
+ * NC GND 2
+ * GND NC/300K 3
+ * VDDIO NC/300K 4
+ * NC NC/300K 5
+ */
+/* TODO: define your own default or for Sensor_ID == 0 config here.
+ * The predefined one is just a sample config,
+ * which is not suitable for your tp in most cases.
+ */
+#define CTP_CFG_GROUP0 {\
+ 0x41, 0xD0, 0x02, 0x00, 0x05, 0x0A, 0x34, \
+ 0x00, 0x01, 0x08, 0x28, 0x05, 0x50, 0x32, \
+ 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x17, 0x19, 0x1E, 0x14, 0x8C, \
+ 0x2D, 0x0E, 0x3C, 0x3E, 0x82, 0x0A, 0x82, \
+ 0x0A, 0x00, 0x99, 0x33, 0x1D, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x2B, 0x19, 0x64, 0x94, 0xC0, 0x02, \
+ 0x08, 0x00, 0x00, 0x04, 0xF2, 0x1C, 0x00, \
+ 0xB9, 0x26, 0x00, 0x93, 0x32, 0x00, 0x77, \
+ 0x42, 0x00, 0x62, 0x57, 0x00, 0x62, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0xFF, 0x65, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x19, 0x46, 0x00, 0x00, 0x00, 0x00, 0x32, \
+ 0x1C, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, \
+ 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x08, \
+ 0x0A, 0x0C, 0x0F, 0x10, 0x12, 0x13, 0x14, \
+ 0x18, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, \
+ 0x22, 0x24, 0x26, 0x28, 0x29, 0x2A, 0xFF, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
+ 0x00, 0x00, 0xB8, 0x01\
+}
+
+/* TODO: define your config for Sensor_ID == 1 here, if needed */
+#define CTP_CFG_GROUP1 {\
+}
+
+/* TODO: define your config for Sensor_ID == 2 here, if needed */
+#define CTP_CFG_GROUP2 {\
+}
+
+/* TODO: define your config for Sensor_ID == 3 here, if needed */
+#define CTP_CFG_GROUP3 {\
+}
+/* TODO: define your config for Sensor_ID == 4 here, if needed */
+#define CTP_CFG_GROUP4 {\
+}
+
+/* TODO: define your config for Sensor_ID == 5 here, if needed */
+#define CTP_CFG_GROUP5 {\
+}
+
+/* STEP_2(REQUIRED): Customize your I/O ports & I/O operations */
+#define GTP_RST_PORT 64 /* EXYNOS4_GPX2(0) */
+#define GTP_INT_PORT 65 /* EXYNOS4_GPX2(1) */
+
+#define GTP_GPIO_AS_INPUT(pin) (gpio_direction_input(pin))
+#define GTP_GPIO_AS_INT(pin) (GTP_GPIO_AS_INPUT(pin))
+#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin)
+#define GTP_GPIO_OUTPUT(pin, level) gpio_direction_output(pin, level)
+#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label)
+#define GTP_GPIO_FREE(pin) gpio_free(pin)
+
+/* STEP_3(optional): Specify your special config info if needed */
+#define GTP_DEFAULT_MAX_X 720 /* default coordinate max values */
+#define GTP_DEFAULT_MAX_Y 1080
+#define GTP_DEFAULT_MAX_WIDTH 1024
+#define GTP_DEFAULT_MAX_PRESSURE 1024
+#define GTP_DEFAULT_INT_TRIGGER 1 /* 1 rising, 2 falling */
+#define GTP_MAX_TOUCH_ID 16
+
+/* STEP_4(optional): If keys are available and reported as keys,
+ * config your key info here
+ */
+#define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK, KEY_HOMEPAGE, \
+ KEY_F1, KEY_F2, KEY_F3}
+
+/**************************PART3:OTHER define*******************************/
+#define GTP_DRIVER_VERSION "V2.8.0.2<2017/12/14>"
+#define GTP_I2C_NAME "goodix-ts"
+#define GT91XX_CONFIG_PROC_FILE "gt9xx_config"
+#define GTP_POLL_TIME 10
+#define GTP_CONFIG_MIN_LENGTH 186
+#define GTP_ESD_CHECK_VALUE 0xAA
+#define RETRY_MAX_TIMES 5
+#define PEN_TRACK_ID 9
+#define MASK_BIT_8 0x80
+#define FAIL 0
+#define SUCCESS 1
+
+/* Registers define */
+#define GTP_REG_COMMAND 0x8040
+#define GTP_REG_ESD_CHECK 0x8041
+#define GTP_REG_COMMAND_CHECK 0x8046
+#define GTP_REG_CONFIG_DATA 0x8047
+#define GTP_REG_VERSION 0x8140
+#define GTP_REG_SENSOR_ID 0x814A
+#define GTP_REG_DOZE_BUF 0x814B
+#define GTP_READ_COOR_ADDR 0x814E
+
+/* Sleep time define */
+#define GTP_1_DLY_MS 1
+#define GTP_2_DLY_MS 2
+#define GTP_10_DLY_MS 10
+#define GTP_20_DLY_MS 20
+#define GTP_50_DLY_MS 50
+#define GTP_58_DLY_MS 58
+#define GTP_100_DLY_MS 100
+#define GTP_500_DLY_MS 500
+#define GTP_1000_DLY_MS 1000
+#define GTP_3000_DLY_MS 3000
+
+#define RESOLUTION_LOC 3
+#define TRIGGER_LOC 8
+
+#define CFG_GROUP_LEN(p_cfg_grp) ARRAY_SIZE(p_cfg_grp)
+/* Log define */
+#define GTP_DEBUG(fmt, arg...) \
+do { \
+ if (GTP_DEBUG_ON) {\
+ pr_info("<<-GTP-DEBUG->> [%d]"fmt"\n", __LINE__, ##arg);\
+ } \
+} while (0)
+#define GTP_DEBUG_ARRAY(array, num) \
+do { \
+ s32 i;\
+ u8 *a = array;\
+ if (GTP_DEBUG_ARRAY_ON) {\
+ pr_warn("<<-GTP-DEBUG-ARRAY->>\n");\
+ for (i = 0; i < (num); i++) {\
+ pr_warn("%02x ", (a)[i]);\
+ if ((i + 1) % 10 == 0) {\
+ pr_warn("\n");\
+ } \
+ } \
+ pr_warn("\n");\
+ } \
+} while (0)
+#define GTP_DEBUG_FUNC() \
+do {\
+ if (GTP_DEBUG_FUNC_ON) {\
+ pr_warn("<<-GTP-FUNC->> Func:%s@Line:%d\n", \
+ __func__, __LINE__);\
+ } \
+} while (0)
+#define GTP_SWAP(x, y) \
+do {\
+ typeof(x) z = x;\
+ x = y;\
+ y = z;\
+} while (0)
+
+/******************************End of Part III********************************/
+#ifdef CONFIG_OF
+extern int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid);
+#endif
+
+extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
+extern void gtp_int_sync(struct goodix_ts_data *ts, s32 ms);
+extern void gtp_esd_on(struct goodix_ts_data *ts);
+extern void gtp_esd_off(struct goodix_ts_data *ts);
+extern void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable);
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE
+extern u16 show_len;
+extern u16 total_len;
+extern u8 gup_init_update_proc(struct goodix_ts_data *ts);
+extern s32 gup_update_proc(void *dir);
+extern s32 gup_enter_update_mode(struct i2c_client *client);
+extern void gup_leave_update_mode(struct i2c_client *client);
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL
+extern s32 init_wr_node(struct i2c_client *client);
+extern void uninit_wr_node(void);
+#endif
+
+/*********** For gt9xx_update Start *********/
+extern struct i2c_client *i2c_connect_client;
+extern void gtp_reset_guitar(struct i2c_client *client, s32 ms);
+extern void gtp_int_output(struct goodix_ts_data *ts, int level);
+extern void gtp_rst_output(struct goodix_ts_data *ts, int level);
+extern void gtp_rst_input(struct goodix_ts_data *ts);
+extern s32 gtp_send_cfg(struct i2c_client *client);
+extern s32 gtp_get_fw_info(struct i2c_client *client,
+ struct goodix_fw_info *fw_info);
+extern s32 gtp_i2c_read_dbl_check(struct i2c_client *client,
+ u16 addr, u8 *rxbuf, int len);
+extern int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len);
+extern int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len);
+extern s32 gtp_fw_startup(struct i2c_client *client);
+extern int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf);
+/*********** For gt9xx_update End *********/
+
+#endif /* _GOODIX_GT9XX_H_ */
diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c
new file mode 100644
index 0000000..7a428a3
--- /dev/null
+++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c
@@ -0,0 +1,2090 @@
+/*
+ * Goodix GT9xx touchscreen driver
+ *
+ * Copyright (C) 2016 - 2017 Goodix. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be a reference
+ * to you, when you are integrating the GOODiX's CTP IC into your system,
+ * 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/kthread.h>
+#include "gt9xx.h"
+
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/firmware.h>
+#include <linux/ctype.h>
+
+#define GUP_REG_HW_INFO 0x4220
+#define GUP_REG_FW_MSG 0x41E4
+#define GUP_REG_PID_VID 0x8140
+
+#define FIRMWARE_NAME_LEN_MAX 256
+#define GOODIX_FIRMWARE_FILE_NAME "goodix_firmware.bin"
+#define GOODIX_CONFIG_FILE_NAME "goodix_config.cfg"
+
+#define FW_HEAD_LENGTH 14
+#define FW_SECTION_LENGTH 0x2000 /* 8K */
+#define FW_DSP_ISP_LENGTH 0x1000 /* 4K */
+#define FW_DSP_LENGTH 0x1000 /* 4K */
+#define FW_BOOT_LENGTH 0x800 /* 2K */
+#define FW_SS51_LENGTH (4 * FW_SECTION_LENGTH) /* 32K */
+#define FW_BOOT_ISP_LENGTH 0x800 /* 2k */
+#define FW_GLINK_LENGTH 0x3000 /* 12k */
+#define FW_GWAKE_LENGTH (4 * FW_SECTION_LENGTH) /* 32k */
+
+#define DELAY_FOR_SENDCFG 500
+#define PACK_SIZE 256
+#define MAX_FRAME_CHECK_TIME 5
+
+#define _bRW_MISCTL__SRAM_BANK 0x4048
+#define _bRW_MISCTL__MEM_CD_EN 0x4049
+#define _bRW_MISCTL__CACHE_EN 0x404B
+#define _bRW_MISCTL__TMR0_EN 0x40B0
+#define _rRW_MISCTL__SWRST_B0_ 0x4180
+#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184
+#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190
+#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218
+#define _rRW_MISCTL__BOOT_CTL_ 0x5094
+
+#pragma pack(1)
+struct st_fw_head {
+ u8 hw_info[4]; /* hardware info */
+ u8 pid[8]; /* product id */
+ u16 vid; /* version id */
+};
+#pragma pack()
+
+struct st_update_msg {
+ u8 fw_damaged;
+ u8 fw_flag;
+ const u8 *fw_data;
+ struct file *cfg_file;
+ struct st_fw_head ic_fw_msg;
+ u32 fw_total_len;
+ u32 fw_burned_len;
+ const struct firmware *fw;
+} update_msg;
+
+struct st_update_msg update_msg;
+
+u16 show_len;
+u16 total_len;
+
+static u8 gup_burn_fw_gwake_section(struct i2c_client *client,
+ u8 *fw_section, u16 start_addr,
+ u32 len, u8 bank_cmd);
+
+static s32 gup_init_panel(struct goodix_ts_data *ts)
+{
+ s32 ret = 0;
+ u8 opr_buf[16];
+ u8 sensor_id = 0;
+ u8 drv_cfg_version;
+ u8 flash_cfg_version;
+ struct goodix_config_data *cfg = &ts->pdata->config;
+
+ if (cfg->length < GTP_CONFIG_MIN_LENGTH) {
+ dev_err(&ts->client->dev,
+ "No valid config with sensor_ID(%d) ",
+ sensor_id);
+
+ return -EPERM;
+ }
+
+ ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
+ &opr_buf[0], 1);
+ if (ret == SUCCESS) {
+ dev_dbg(&ts->client->dev,
+ "CFG_GROUP%d Config Version: %d, IC Config Version: %d",
+ sensor_id, cfg->data[GTP_ADDR_LENGTH], opr_buf[0]);
+
+ flash_cfg_version = opr_buf[0];
+ drv_cfg_version = cfg->data[GTP_ADDR_LENGTH];
+
+ if (flash_cfg_version < 90 &&
+ flash_cfg_version > drv_cfg_version)
+ cfg->data[GTP_ADDR_LENGTH] = 0x00;
+ } else {
+ dev_err(&ts->client->dev,
+ "Failed to get ic config version!No config sent!");
+ return -EPERM;
+ }
+
+ ret = gtp_send_cfg(ts->client);
+ if (ret < 0)
+ dev_err(&ts->client->dev, "Send config error.");
+ else
+ usleep_range(10000, 11000);
+
+ /* restore config vrsion */
+ cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version;
+
+ return 0;
+}
+
+
+static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len)
+{
+ s32 i = 0;
+
+ msg[0] = (addr >> 8) & 0xff;
+ msg[1] = addr & 0xff;
+
+ for (i = 0; i < 5; i++) {
+ if (gtp_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0)
+ break;
+ }
+
+ if (i >= 5) {
+ dev_err(&client->dev,
+ "Read data from 0x%02x%02x failed!",
+ msg[0], msg[1]);
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val)
+{
+ s32 i = 0;
+ u8 msg[3];
+
+ msg[0] = (addr >> 8) & 0xff;
+ msg[1] = addr & 0xff;
+ msg[2] = val;
+
+ for (i = 0; i < 5; i++) {
+ if (gtp_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0)
+ break;
+ }
+
+ if (i >= 5) {
+ dev_err(&client->dev,
+ "Set data to 0x%02x%02x failed!", msg[0], msg[1]);
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_get_ic_fw_msg(struct i2c_client *client)
+{
+ s32 ret = -1;
+ u8 retry = 0;
+ u8 buf[16];
+ u8 i;
+
+ /* step1:get hardware info */
+ ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO,
+ &buf[GTP_ADDR_LENGTH], 4);
+ if (ret == FAIL) {
+ dev_err(&client->dev, "[get_ic_fw_msg]get hw_info failed,exit");
+ return FAIL;
+ }
+
+ /* buf[2~5]: 00 06 90 00
+ * hw_info: 00 90 06 00
+ */
+ for (i = 0; i < 4; i++)
+ update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i];
+ dev_dbg(&client->dev,
+ "IC Hardware info:%02x%02x%02x%02x",
+ update_msg.ic_fw_msg.hw_info[0],
+ update_msg.ic_fw_msg.hw_info[1],
+ update_msg.ic_fw_msg.hw_info[2],
+ update_msg.ic_fw_msg.hw_info[3]);
+ /* step2:get firmware message */
+ for (retry = 0; retry < 2; retry++) {
+ ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1);
+ if (ret == FAIL) {
+ dev_err(&client->dev, "Read firmware message fail.");
+ return ret;
+ }
+
+ update_msg.fw_damaged = buf[GTP_ADDR_LENGTH];
+ if ((update_msg.fw_damaged != 0xBE) && (!retry)) {
+ dev_info(&client->dev, "The check sum in ic is error.");
+ dev_info(&client->dev, "The IC will be updated by force.");
+ continue;
+ }
+ break;
+ }
+ dev_dbg(&client->dev,
+ "IC force update flag:0x%x", update_msg.fw_damaged);
+
+ /* step3:get pid & vid */
+ ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID,
+ &buf[GTP_ADDR_LENGTH], 6);
+ if (ret == FAIL) {
+ dev_err(&client->dev, "[get_ic_fw_msg]get pid & vid failed,exit");
+ return FAIL;
+ }
+
+ memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid));
+ memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4);
+ dev_dbg(&client->dev, "IC Product id:%s", update_msg.ic_fw_msg.pid);
+
+ /* GT9XX PID MAPPING */
+ /*|-----FLASH-----RAM-----|
+ *|------918------918-----|
+ *|------968------968-----|
+ *|------913------913-----|
+ *|------913P-----913P----|
+ *|------927------927-----|
+ *|------927P-----927P----|
+ *|------9110-----9110----|
+ *|------9110P----9111----|
+ */
+ if (update_msg.ic_fw_msg.pid[0] != 0) {
+ if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) {
+ dev_dbg(&client->dev, "IC Mapping Product id:%s",
+ update_msg.ic_fw_msg.pid);
+ memcpy(update_msg.ic_fw_msg.pid, "9110P", 5);
+ }
+ }
+
+ update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] +
+ (buf[GTP_ADDR_LENGTH + 5] << 8);
+ dev_dbg(&client->dev, "IC version id:%04x", update_msg.ic_fw_msg.vid);
+
+ return SUCCESS;
+}
+
+s32 gup_enter_update_mode(struct i2c_client *client)
+{
+ s32 ret = -1;
+ s32 retry = 0;
+ u8 rd_buf[3];
+
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ /* step1:RST output low last at least 2ms */
+ if (!gpio_is_valid(ts->pdata->rst_gpio)) {
+ dev_err(&ts->client->dev, "update failed, no rst pin\n");
+ return FAIL;
+ }
+ gtp_rst_output(ts, 0);
+ usleep_range(2000, 3000);
+
+ /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */
+ gtp_int_output(ts, client->addr == 0x14);
+ usleep_range(2000, 3000);
+
+ /* step3:RST output high reset guitar */
+ gtp_rst_output(ts, 1);
+
+ /* 20121211 modify start */
+ usleep_range(5000, 6000);
+ while (retry++ < 200) {
+ /* step4:Hold ss51 & dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ dev_dbg(&client->dev,
+ "Hold ss51 & dsp I2C error,retry:%d",
+ retry);
+ continue;
+ }
+
+ /* step5:Confirm hold */
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1);
+ if (ret <= 0) {
+ dev_dbg(&client->dev,
+ "Hold ss51 & dsp I2C error,retry:%d",
+ retry);
+ continue;
+ }
+ if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) {
+ dev_dbg(&client->dev, "Hold ss51 & dsp confirm SUCCESS");
+ break;
+ }
+ dev_dbg(&client->dev,
+ "Hold ss51 & dsp confirm 0x4180 failed,value:%d",
+ rd_buf[GTP_ADDR_LENGTH]);
+ }
+ if (retry >= 200) {
+ dev_err(&client->dev, "Enter update Hold ss51 failed.");
+ return FAIL;
+ }
+
+ /* step6:DSP_CK and DSP_ALU_CK PowerOn */
+ ret = gup_set_ic_msg(client, 0x4010, 0x00);
+
+ /* 20121211 modify end */
+ return ret;
+}
+
+void gup_leave_update_mode(struct i2c_client *client)
+{
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts->pdata->int_sync && ts->pinctrl.pinctrl)
+ pinctrl_select_state(ts->pinctrl.pinctrl,
+ ts->pinctrl.int_input);
+ else if (ts->pdata->int_sync && gpio_is_valid(ts->pdata->irq_gpio))
+ gpio_direction_input(ts->pdata->irq_gpio);
+ dev_dbg(&client->dev, "[leave_update_mode]reset chip.");
+ gtp_reset_guitar(i2c_connect_client, 20);
+}
+
+static u8 gup_enter_update_judge(struct i2c_client *client,
+ struct st_fw_head *fw_head)
+{
+ u16 u16_tmp;
+ s32 i = 0;
+ u32 fw_len = 0;
+ s32 pid_cmp_len = 0;
+
+ u16_tmp = fw_head->vid;
+ fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8);
+
+ dev_info(&client->dev, "FILE HARDWARE INFO:%*ph\n", 4,
+ &fw_head->hw_info[0]);
+ dev_info(&client->dev, "FILE PID:%s\n", fw_head->pid);
+ dev_info(&client->dev, "FILE VID:%04x\n", fw_head->vid);
+
+ dev_info(&client->dev, "IC HARDWARE INFO:%*ph\n", 4,
+ &update_msg.ic_fw_msg.hw_info[0]);
+ dev_info(&client->dev, "IC PID:%s\n", update_msg.ic_fw_msg.pid);
+ dev_info(&client->dev, "IC VID:%04x\n", update_msg.ic_fw_msg.vid);
+
+ if (!memcmp(fw_head->pid, "9158", 4) &&
+ !memcmp(update_msg.ic_fw_msg.pid, "915S", 4)) {
+ dev_info(&client->dev, "Update GT915S to GT9158 directly!");
+ return SUCCESS;
+ }
+ /* First two conditions */
+ if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info,
+ sizeof(update_msg.ic_fw_msg.hw_info))) {
+ fw_len = 42 * 1024;
+ } else {
+ fw_len = fw_head->hw_info[3];
+ fw_len += (((u32)fw_head->hw_info[2]) << 8);
+ fw_len += (((u32)fw_head->hw_info[1]) << 16);
+ fw_len += (((u32)fw_head->hw_info[0]) << 24);
+ }
+ if (update_msg.fw_total_len != fw_len) {
+ dev_err(&client->dev,
+ "Inconsistent firmware size, Update aborted!");
+ dev_err(&client->dev,
+ " Default size: %d(%dK), actual size: %d(%dK)",
+ fw_len, fw_len/1024, update_msg.fw_total_len,
+ update_msg.fw_total_len/1024);
+ return FAIL;
+ }
+ dev_info(&client->dev, "Firmware length:%d(%dK)",
+ update_msg.fw_total_len,
+ update_msg.fw_total_len/1024);
+
+ if (update_msg.fw_damaged != 0xBE) {
+ dev_info(&client->dev, "FW chksum error,need enter update.");
+ return SUCCESS;
+ }
+
+ /* 20130523 start */
+ if (strlen(update_msg.ic_fw_msg.pid) < 3) {
+ dev_info(&client->dev, "Illegal IC pid, need enter update");
+ return SUCCESS;
+ }
+
+ /* check pid legality */
+ for (i = 0; i < 3; i++) {
+ if (!isdigit(update_msg.ic_fw_msg.pid[i])) {
+ dev_info(&client->dev,
+ "Illegal IC pid, need enter update");
+ return SUCCESS;
+ }
+ }
+ /* 20130523 end */
+
+ pid_cmp_len = strlen(fw_head->pid);
+ if (pid_cmp_len < strlen(update_msg.ic_fw_msg.pid))
+ pid_cmp_len = strlen(update_msg.ic_fw_msg.pid);
+
+ if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, pid_cmp_len)) ||
+ (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) ||
+ (!memcmp(fw_head->pid, "91XX", 4))) {
+ if (!memcmp(fw_head->pid, "91XX", 4))
+ dev_dbg(&client->dev,
+ "Force none same pid update mode.");
+ else
+ dev_dbg(&client->dev, "Get the same pid.");
+
+ /* The third condition */
+ if (fw_head->vid != update_msg.ic_fw_msg.vid) {
+ dev_info(&client->dev, "Need enter update.");
+ return SUCCESS;
+ }
+ dev_err(&client->dev, "File VID == Ic VID, update aborted!");
+ } else {
+ dev_err(&client->dev, "File PID != Ic PID, update aborted!");
+ }
+
+ return FAIL;
+}
+
+static int gup_update_config(struct i2c_client *client)
+{
+ s32 ret = 0;
+ s32 i = 0;
+ s32 file_cfg_len = 0;
+ u8 *file_config;
+ const struct firmware *fw_cfg;
+
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ ret = request_firmware(&fw_cfg, GOODIX_CONFIG_FILE_NAME,
+ &client->dev);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Cannot get config file - %s (%d)\n",
+ GOODIX_CONFIG_FILE_NAME, ret);
+ return -EFAULT;
+ }
+ if (!fw_cfg || !fw_cfg->data || fw_cfg->size > PAGE_SIZE) {
+ dev_err(&client->dev, "config file illegal");
+ ret = -EFAULT;
+ goto cfg_fw_err;
+ }
+
+ dev_dbg(&client->dev, "config firmware file len:%zu", fw_cfg->size);
+
+ file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
+ GFP_KERNEL);
+ if (!file_config) {
+ ret = -ENOMEM;
+ goto cfg_fw_err;
+ }
+ file_config[0] = GTP_REG_CONFIG_DATA >> 8;
+ file_config[1] = GTP_REG_CONFIG_DATA & 0xff;
+ file_cfg_len = gtp_ascii_to_array(fw_cfg->data, fw_cfg->size,
+ &file_config[GTP_ADDR_LENGTH]);
+ if (file_cfg_len < 0) {
+ dev_err(&client->dev, "failed covert ascii to hex");
+ ret = -EFAULT;
+ goto update_cfg_file_failed;
+ }
+
+ GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len);
+
+ i = 0;
+ while (i++ < 5) {
+ ret = gtp_i2c_write(client, file_config, file_cfg_len + 2);
+ if (ret > 0) {
+ dev_info(&client->dev, "Send config SUCCESS.");
+ msleep(DELAY_FOR_SENDCFG);
+ break;
+ }
+ dev_err(&ts->client->dev, "Send config i2c error.");
+ }
+
+update_cfg_file_failed:
+ kfree(file_config);
+cfg_fw_err:
+ release_firmware(fw_cfg);
+ return ret;
+}
+
+static u8 gup_check_firmware_name(struct i2c_client *client,
+ u8 **path_p)
+{
+ u8 len;
+ u8 *fname;
+
+ if (!(*path_p)) {
+ *path_p = GOODIX_FIRMWARE_FILE_NAME;
+ return 0;
+ }
+
+ len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX);
+ if (len >= FIRMWARE_NAME_LEN_MAX) {
+ dev_err(&client->dev, "firmware name too long!");
+ return -EINVAL;
+ }
+
+ fname = strrchr(*path_p, '/');
+ if (fname) {
+ fname = fname + 1;
+ *path_p = fname;
+ }
+
+ return 0;
+}
+
+static u8 gup_get_update_file(struct i2c_client *client,
+ struct st_fw_head *fw_head, u8 *path)
+{
+ s32 ret = 0;
+ s32 i = 0;
+ s32 fw_checksum = 0;
+ struct goodix_ts_data *ts = i2c_get_clientdata(client);
+
+ if (ts->pdata->auto_update_cfg) {
+ ret = gup_update_config(client);
+ if (ret <= 0)
+ dev_err(&client->dev, "Update config failed.");
+ }
+
+ ret = gup_check_firmware_name(client, &path);
+ if (ret < 0)
+ return FAIL;
+
+ ret = request_firmware(&update_msg.fw, path, &client->dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed get firmware:%d\n", ret);
+ return FAIL;
+ }
+
+ dev_info(&client->dev, "FW File: %s size=%zu",
+ path, update_msg.fw->size);
+ update_msg.fw_data = update_msg.fw->data;
+ update_msg.fw_total_len = update_msg.fw->size;
+
+ if (update_msg.fw_total_len <
+ FW_HEAD_LENGTH + FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH +
+ FW_DSP_LENGTH + FW_BOOT_LENGTH) {
+ dev_err(&client->dev,
+ "INVALID bin file(size: %d), update aborted.",
+ update_msg.fw_total_len);
+ goto invalied_fw;
+ }
+
+ update_msg.fw_total_len -= FW_HEAD_LENGTH;
+
+ dev_dbg(&client->dev, "Bin firmware actual size: %d(%dK)",
+ update_msg.fw_total_len, update_msg.fw_total_len/1024);
+
+ memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH);
+
+ /* check firmware legality */
+ fw_checksum = 0;
+ for (i = 0; i < update_msg.fw_total_len; i += 2) {
+ u16 temp;
+
+ temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) +
+ update_msg.fw_data[FW_HEAD_LENGTH + i + 1];
+ fw_checksum += temp;
+ }
+
+ dev_dbg(&client->dev, "firmware checksum:%x", fw_checksum&0xFFFF);
+ if (fw_checksum & 0xFFFF) {
+ dev_err(&client->dev, "Illegal firmware file.");
+ goto invalied_fw;
+ }
+
+ return SUCCESS;
+
+invalied_fw:
+ update_msg.fw_data = NULL;
+ update_msg.fw_total_len = 0;
+ release_firmware(update_msg.fw);
+ return FAIL;
+}
+
+static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf,
+ u16 start_addr, u16 total_length)
+{
+ s32 ret = 0;
+ u16 burn_addr = start_addr;
+ u16 frame_length = 0;
+ u16 burn_length = 0;
+ u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ u8 retry = 0;
+
+ dev_dbg(&client->dev, "Begin burn %dk data to addr 0x%x",
+ total_length / 1024, start_addr);
+ while (burn_length < total_length) {
+ dev_dbg(&client->dev,
+ "B/T:%04d/%04d", burn_length, total_length);
+ frame_length = ((total_length - burn_length)
+ > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length);
+ wr_buf[0] = (u8)(burn_addr>>8);
+ rd_buf[0] = wr_buf[0];
+ wr_buf[1] = (u8)burn_addr;
+ rd_buf[1] = wr_buf[1];
+ memcpy(&wr_buf[GTP_ADDR_LENGTH],
+ &burn_buf[burn_length], frame_length);
+
+ for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) {
+ ret = gtp_i2c_write(client,
+ wr_buf, GTP_ADDR_LENGTH + frame_length);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "Write frame data i2c error.");
+ continue;
+ }
+ ret = gtp_i2c_read(client, rd_buf,
+ GTP_ADDR_LENGTH + frame_length);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "Read back frame data i2c error.");
+ continue;
+ }
+ if (memcmp(&wr_buf[GTP_ADDR_LENGTH],
+ &rd_buf[GTP_ADDR_LENGTH], frame_length)) {
+ dev_err(&client->dev,
+ "Check frame data fail,not equal.");
+ dev_dbg(&client->dev, "write array:");
+ GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH],
+ frame_length);
+ dev_dbg(&client->dev, "read array:");
+ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH],
+ frame_length);
+ continue;
+ } else {
+ /* dev_dbg(&client->dev,
+ * "Check frame data success.");
+ */
+ break;
+ }
+ }
+ if (retry >= MAX_FRAME_CHECK_TIME) {
+ dev_err(&client->dev,
+ "Burn frame data time out,exit.");
+ return FAIL;
+ }
+ burn_length += frame_length;
+ burn_addr += frame_length;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_load_section_file(u8 *buf, u32 offset, u16 length, u8 set_or_end)
+{
+ if (!update_msg.fw_data ||
+ update_msg.fw_total_len < FW_HEAD_LENGTH + offset + length) {
+ pr_err("<<-GTP->> cannot load section data. fw_len=%d read end=%d\n",
+ update_msg.fw_total_len,
+ FW_HEAD_LENGTH + offset + length);
+ return FAIL;
+ }
+
+ if (set_or_end == SEEK_SET) {
+ memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset],
+ length);
+ } else {
+ /* seek end */
+ memcpy(buf, &update_msg.fw_data[update_msg.fw_total_len +
+ FW_HEAD_LENGTH - offset], length);
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src,
+ u16 start_rd_addr, u16 chk_length)
+{
+ u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH];
+ s32 ret = 0;
+ u16 recall_addr = start_rd_addr;
+ u16 recall_length = 0;
+ u16 frame_length = 0;
+
+ while (recall_length < chk_length) {
+ frame_length = ((chk_length - recall_length)
+ > PACK_SIZE) ? PACK_SIZE :
+ (chk_length - recall_length);
+ ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length);
+ if (ret <= 0) {
+ dev_err(&client->dev, "recall i2c error,exit");
+ return FAIL;
+ }
+
+ if (memcmp(&rd_buf[GTP_ADDR_LENGTH],
+ &chk_src[recall_length], frame_length)) {
+ dev_err(&client->dev, "Recall frame data fail,not equal.");
+ dev_dbg(&client->dev, "chk_src array:");
+ GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length);
+ dev_dbg(&client->dev, "recall array:");
+ GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length);
+ return FAIL;
+ }
+
+ recall_length += frame_length;
+ recall_addr += frame_length;
+ }
+ dev_dbg(&client->dev,
+ "Recall check %dk firmware success.",
+ (chk_length/1024));
+
+ return SUCCESS;
+}
+
+static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section,
+ u16 start_addr, u8 bank_cmd)
+{
+ s32 ret = 0;
+ u8 rd_buf[5];
+
+ /* step1:hold ss51 & dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_section]hold ss51 & dsp fail.");
+ return FAIL;
+ }
+
+ /* step2:set scramble */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_section]set scramble fail.");
+ return FAIL;
+ }
+
+ /* step3:select bank */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK,
+ (bank_cmd >> 4)&0x0F);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_section]select bank %d fail.",
+ (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ /* step4:enable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_section]enable accessing code fail.");
+ return FAIL;
+ }
+
+ /* step5:burn 8k fw section */
+ ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_section]burn fw_section fail.");
+ return FAIL;
+ }
+
+ /* step6:hold ss51 & release dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_section]hold ss51 & release dsp fail.");
+ return FAIL;
+ }
+ /* must delay */
+ usleep_range(1000, 2000);
+
+ /* step7:send burn cmd to move data to flash from sram */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_section]send burn cmd fail.");
+ return FAIL;
+ }
+ dev_dbg(&client->dev,
+ "[burn_fw_section]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_section]Get burn state fail");
+ return FAIL;
+ }
+ usleep_range(10000, 11000);
+ /* dev_dbg(&client->dev, "[burn_fw_section]Get burn state:%d.",
+ * rd_buf[GTP_ADDR_LENGTH]);
+ */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step8:select bank */
+ ret = gup_set_ic_msg(client,
+ _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4) & 0x0F);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_section]select bank %d fail.",
+ (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ /* step9:enable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_section]enable accessing code fail.");
+ return FAIL;
+ }
+
+ /* step10:recall 8k fw section */
+ ret = gup_recall_check(client,
+ fw_section, start_addr, FW_SECTION_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_section]recall check %dk firmware fail.",
+ FW_SECTION_LENGTH / 1024);
+ return FAIL;
+ }
+
+ /* step11:disable accessing code */
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_section]disable accessing code fail.");
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_burn_dsp_isp(struct i2c_client *client)
+{
+ s32 ret = 0;
+ u8 *fw_dsp_isp = NULL;
+ u8 retry = 0;
+
+ dev_info(&client->dev, "[burn_dsp_isp]Begin burn dsp isp---->>");
+
+ /* step1:alloc memory */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL);
+ if (fw_dsp_isp == NULL) {
+ continue;
+ } else {
+ dev_info(&client->dev,
+ "[burn_dsp_isp]Alloc %dk byte memory success.",
+ FW_DSP_ISP_LENGTH / 1024);
+ break;
+ }
+ }
+ if (retry >= 5) {
+ dev_err(&client->dev, "[burn_dsp_isp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load dsp isp file data */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step2:load dsp isp file data");
+ ret = gup_load_section_file(fw_dsp_isp,
+ FW_DSP_ISP_LENGTH, FW_DSP_ISP_LENGTH, SEEK_END);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_dsp_isp]load firmware dsp_isp fail.");
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step3:disable wdt,clear cache enable */
+ dev_dbg(&client->dev,
+ "[burn_dsp_isp]step3:disable wdt,clear cache enable");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_dsp_isp]disable wdt fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_dsp_isp]clear cache enable fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step4:hold ss51 & dsp */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step4:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_dsp_isp]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step5:set boot from sram */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step5:set boot from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_dsp_isp]set boot from sram fail");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step6:software reboot */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step6:software reboot");
+ ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_dsp_isp]software reboot fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step7:select bank2 */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step7:select bank2");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_dsp_isp]select bank2 fail");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step8:enable accessing code */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step8:enable accessing code");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_dsp_isp]enable accessing code fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step9:burn 4k dsp_isp */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step9:burn 4k dsp_isp");
+ ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev, "[burn_dsp_isp]burn dsp_isp fail.");
+ goto exit_burn_dsp_isp;
+ }
+
+ /* step10:set scramble */
+ dev_dbg(&client->dev, "[burn_dsp_isp]step10:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_dsp_isp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_dsp_isp;
+ }
+ update_msg.fw_burned_len += FW_DSP_ISP_LENGTH;
+ dev_dbg(&client->dev, "[burn_dsp_isp]Burned length:%d",
+ update_msg.fw_burned_len);
+ ret = SUCCESS;
+
+exit_burn_dsp_isp:
+ kfree(fw_dsp_isp);
+
+ return ret;
+}
+
+static u8 gup_burn_fw_ss51(struct i2c_client *client)
+{
+ u8 *fw_ss51 = NULL;
+ u8 retry = 0;
+ s32 ret = 0;
+
+ dev_info(&client->dev, "[burn_fw_ss51]Begin burn ss51 firmware---->>");
+
+ /* step1:alloc memory */
+ dev_dbg(&client->dev, "[burn_fw_ss51]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+ if (fw_ss51 == NULL) {
+ continue;
+ } else {
+ dev_dbg(&client->dev,
+ "[burn_fw_ss51]Alloc %dk byte memory success.",
+ (FW_SECTION_LENGTH / 1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ dev_err(&client->dev, "[burn_fw_ss51]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ dev_info(&client->dev, "[burn_fw_ss51]Reset first 8K of ss51 to 0xFF.");
+ dev_dbg(&client->dev, "[burn_fw_ss51]step2: reset bank0 0xC000~0xD000");
+ memset(fw_ss51, 0xFF, FW_SECTION_LENGTH);
+
+ /* step3:clear control flag */
+ dev_dbg(&client->dev, "[burn_fw_ss51]step3:clear control flag");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_ss51]clear control flag fail.");
+ ret = FAIL;
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step4:burn ss51 firmware section 1 */
+ dev_dbg(&client->dev,
+ "[burn_fw_ss51]step4:burn ss51 firmware section 1");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_ss51]burn ss51 firmware section 1 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step5:load ss51 firmware section 2 file data */
+ dev_dbg(&client->dev,
+ "[burn_fw_ss51]step5:load ss51 firmware section 2 file data");
+ ret = gup_load_section_file(fw_ss51,
+ FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_ss51]load ss51 firmware section 2 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step6:burn ss51 firmware section 2 */
+ dev_dbg(&client->dev,
+ "[burn_fw_ss51]step6:burn ss51 firmware section 2");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_ss51]burn ss51 firmware section 2 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step7:load ss51 firmware section 3 file data */
+ dev_dbg(&client->dev,
+ "[burn_fw_ss51]step7:load ss51 firmware section 3 file data");
+ ret = gup_load_section_file(fw_ss51,
+ 2 * FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_ss51]load ss51 firmware section 3 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step8:burn ss51 firmware section 3 */
+ dev_dbg(&client->dev,
+ "[burn_fw_ss51]step8:burn ss51 firmware section 3");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_ss51]burn ss51 firmware section 3 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step9:load ss51 firmware section 4 file data */
+ dev_dbg(&client->dev,
+ "[burn_fw_ss51]step9:load ss51 firmware section 4 file data");
+ ret = gup_load_section_file(fw_ss51,
+ 3 * FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_ss51]load ss51 firmware section 4 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ /* step10:burn ss51 firmware section 4 */
+ dev_dbg(&client->dev,
+ "[burn_fw_ss51]step10:burn ss51 firmware section 4");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_ss51]burn ss51 firmware section 4 fail.");
+ goto exit_burn_fw_ss51;
+ }
+
+ update_msg.fw_burned_len += (FW_SECTION_LENGTH*4);
+ dev_dbg(&client->dev, "[burn_fw_ss51]Burned length:%d",
+ update_msg.fw_burned_len);
+ ret = SUCCESS;
+
+exit_burn_fw_ss51:
+ kfree(fw_ss51);
+ return ret;
+}
+
+static u8 gup_burn_fw_dsp(struct i2c_client *client)
+{
+ s32 ret = 0;
+ u8 *fw_dsp = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ dev_info(&client->dev, "[burn_fw_dsp]Begin burn dsp firmware---->>");
+ /* step1:alloc memory */
+ dev_dbg(&client->dev, "[burn_fw_dsp]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL);
+ if (fw_dsp == NULL) {
+ continue;
+ } else {
+ dev_dbg(&client->dev,
+ "[burn_fw_dsp]Alloc %dk byte memory success.",
+ FW_SECTION_LENGTH / 1024);
+ break;
+ }
+ }
+ if (retry >= 5) {
+ dev_err(&client->dev, "[burn_fw_dsp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load firmware dsp */
+ dev_dbg(&client->dev, "[burn_fw_dsp]step2:load firmware dsp");
+ ret = gup_load_section_file(fw_dsp,
+ 4 * FW_SECTION_LENGTH, FW_DSP_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev, "[burn_fw_dsp]load firmware dsp fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step3:select bank3 */
+ dev_dbg(&client->dev, "[burn_fw_dsp]step3:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_dsp]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step4:hold ss51 & dsp */
+ dev_dbg(&client->dev, "[burn_fw_dsp]step4:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_dsp]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step5:set scramble */
+ dev_dbg(&client->dev, "[burn_fw_dsp]step5:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_dsp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step6:release ss51 & dsp */
+ dev_dbg(&client->dev, "[burn_fw_dsp]step6:release ss51 & dsp");
+ ret = gup_set_ic_msg(
+ client, _rRW_MISCTL__SWRST_B0_, 0x04);/* 20121211 */
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_dsp]release ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_dsp;
+ }
+ /* must delay */
+ usleep_range(1000, 1100);
+
+ /* step7:burn 4k dsp firmware */
+ dev_dbg(&client->dev, "[burn_fw_dsp]step7:burn 4k dsp firmware");
+ ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev, "[burn_fw_dsp]burn fw_section fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ /* step8:send burn cmd to move data to flash from sram */
+ dev_dbg(&client->dev,
+ "[burn_fw_dsp]step8:send burn cmd to move data to flash from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_dsp]send burn cmd fail.");
+ goto exit_burn_fw_dsp;
+ }
+ dev_dbg(&client->dev, "[burn_fw_dsp]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_dsp]Get burn state fail");
+ goto exit_burn_fw_dsp;
+ }
+ usleep_range(10000, 11000);
+ /* dev_dbg(&client->dev, "[burn_fw_dsp]Get burn state:%d.",
+ * rd_buf[GTP_ADDR_LENGTH]);
+ */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step9:recall check 4k dsp firmware */
+ dev_dbg(&client->dev,
+ "[burn_fw_dsp]step9:recall check 4k dsp firmware");
+ ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_dsp]recall check 4k dsp firmware fail.");
+ goto exit_burn_fw_dsp;
+ }
+
+ update_msg.fw_burned_len += FW_DSP_LENGTH;
+ dev_dbg(&client->dev, "[burn_fw_dsp]Burned length:%d",
+ update_msg.fw_burned_len);
+ ret = SUCCESS;
+
+exit_burn_fw_dsp:
+ kfree(fw_dsp);
+
+ return ret;
+}
+
+static u8 gup_burn_fw_boot(struct i2c_client *client)
+{
+ s32 ret = 0;
+ u8 *fw_boot = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ dev_info(&client->dev,
+ "[burn_fw_boot]Begin burn bootloader firmware---->>");
+
+ /* step1:Alloc memory */
+ dev_dbg(&client->dev, "[burn_fw_boot]step1:Alloc memory");
+ while (retry++ < 5) {
+ fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL);
+ if (fw_boot == NULL) {
+ continue;
+ } else {
+ dev_dbg(&client->dev,
+ "[burn_fw_boot]Alloc %dk byte memory success.",
+ FW_BOOT_LENGTH / 1024);
+ break;
+ }
+ }
+ if (retry >= 5) {
+ dev_err(&client->dev, "[burn_fw_boot]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load firmware bootloader */
+ dev_dbg(&client->dev, "[burn_fw_boot]step2:load firmware bootloader");
+ ret = gup_load_section_file(fw_boot,
+ (4 * FW_SECTION_LENGTH + FW_DSP_LENGTH), FW_BOOT_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_boot]load firmware bootcode fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ /* step3:hold ss51 & dsp */
+ dev_dbg(&client->dev, "[burn_fw_boot]step3:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot]hold ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step4:set scramble */
+ dev_dbg(&client->dev, "[burn_fw_boot]step4:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step5:hold ss51 & release dsp */
+ dev_dbg(&client->dev, "[burn_fw_boot]step5:hold ss51 & release dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ /* 20121211 */
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot]release ss51 & dsp fail");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+ /* must delay */
+ usleep_range(1000, 1100);
+
+ /* step6:select bank3 */
+ dev_dbg(&client->dev, "[burn_fw_boot]step6:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot;
+ }
+
+ /* step6:burn 2k bootloader firmware */
+ dev_dbg(&client->dev,
+ "[burn_fw_boot]step6:burn 2k bootloader firmware");
+ ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev, "[burn_fw_boot]burn fw_boot fail.");
+ goto exit_burn_fw_boot;
+ }
+
+ /* step7:send burn cmd to move data to flash from sram */
+ dev_dbg(&client->dev,
+ "[burn_fw_boot]step7:send burn cmd to move data to flash from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot]send burn cmd fail.");
+ goto exit_burn_fw_boot;
+ }
+ dev_dbg(&client->dev,
+ "[burn_fw_boot]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_boot]Get burn state fail");
+ goto exit_burn_fw_boot;
+ }
+ usleep_range(10000, 11000);
+ /* dev_dbg(&client->dev, "[burn_fw_boot]Get burn state:%d.",
+ * rd_buf[GTP_ADDR_LENGTH]);
+ */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step8:recall check 2k bootloader firmware */
+ dev_dbg(&client->dev,
+ "[burn_fw_boot]step8:recall check 2k bootloader firmware");
+ ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_boot]recall check 2k bootcode firmware fail");
+ goto exit_burn_fw_boot;
+ }
+
+ update_msg.fw_burned_len += FW_BOOT_LENGTH;
+ dev_dbg(&client->dev, "[burn_fw_boot]Burned length:%d",
+ update_msg.fw_burned_len);
+ ret = SUCCESS;
+
+exit_burn_fw_boot:
+ kfree(fw_boot);
+
+ return ret;
+}
+static u8 gup_burn_fw_boot_isp(struct i2c_client *client)
+{
+ s32 ret = 0;
+ u8 *fw_boot_isp = NULL;
+ u8 retry = 0;
+ u8 rd_buf[5];
+
+ if (update_msg.fw_burned_len >= update_msg.fw_total_len) {
+ dev_dbg(&client->dev, "No need to upgrade the boot_isp code!");
+ return SUCCESS;
+ }
+ dev_info(&client->dev,
+ "[burn_fw_boot_isp]Begin burn boot_isp firmware---->>");
+
+ /* step1:Alloc memory */
+ dev_dbg(&client->dev, "[burn_fw_boot_isp]step1:Alloc memory");
+ while (retry++ < 5) {
+ fw_boot_isp = kzalloc(FW_BOOT_ISP_LENGTH, GFP_KERNEL);
+ if (fw_boot_isp == NULL) {
+ continue;
+ } else {
+ dev_dbg(&client->dev,
+ "[burn_fw_boot_isp]Alloc %dk byte memory success.",
+ (FW_BOOT_ISP_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ dev_err(&client->dev,
+ "[burn_fw_boot_isp]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load firmware bootloader */
+ dev_dbg(&client->dev,
+ "[burn_fw_boot_isp]step2:load firmware bootloader isp");
+ /* ret = gup_load_section_file(fw_boot_isp,
+ * (4*FW_SECTION_LENGTH+FW_DSP_LENGTH +
+ * FW_BOOT_LENGTH+FW_DSP_ISP_LENGTH), FW_BOOT_ISP_LENGTH, SEEK_SET);
+ */
+ ret = gup_load_section_file(fw_boot_isp,
+ (update_msg.fw_burned_len - FW_DSP_ISP_LENGTH),
+ FW_BOOT_ISP_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_boot_isp]load firmware boot_isp fail.");
+ goto exit_burn_fw_boot_isp;
+ }
+
+ /* step3:hold ss51 & dsp */
+ dev_dbg(&client->dev, "[burn_fw_boot_isp]step3:hold ss51 & dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot_isp]hold ss51 & dsp fail");
+ ret = FAIL;
+ goto exit_burn_fw_boot_isp;
+ }
+
+ /* step4:set scramble */
+ dev_dbg(&client->dev, "[burn_fw_boot_isp]step4:set scramble");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot_isp]set scramble fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot_isp;
+ }
+
+
+ /* step5:hold ss51 & release dsp */
+ dev_dbg(&client->dev,
+ "[burn_fw_boot_isp]step5:hold ss51 & release dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ /* 20121211 */
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_boot_isp]release ss51 & dsp fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot_isp;
+ }
+ /* must delay */
+ usleep_range(1000, 2000);
+
+ /* step6:select bank3 */
+ dev_dbg(&client->dev, "[burn_fw_boot_isp]step6:select bank3");
+ ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot_isp]select bank3 fail.");
+ ret = FAIL;
+ goto exit_burn_fw_boot_isp;
+ }
+
+ /* step7:burn 2k bootload_isp firmware */
+ dev_dbg(&client->dev,
+ "[burn_fw_boot_isp]step7:burn 2k bootloader firmware");
+ ret = gup_burn_proc(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_boot_isp]burn fw_section fail.");
+ goto exit_burn_fw_boot_isp;
+ }
+
+ /* step7:send burn cmd to move data to flash from sram */
+ dev_dbg(&client->dev,
+ "[burn_fw_boot_isp]step8:send burn cmd to move data to flash from sram");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x07);
+ if (ret <= 0) {
+ dev_err(&client->dev, "[burn_fw_boot_isp]send burn cmd fail.");
+ goto exit_burn_fw_boot_isp;
+ }
+ dev_dbg(&client->dev,
+ "[burn_fw_boot_isp]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_boot_isp]Get burn state fail");
+ goto exit_burn_fw_boot_isp;
+ }
+ usleep_range(10000, 11000);
+ /* dev_dbg(&client->dev, "[burn_fw_boot_isp]Get
+ * burn state:%d.", rd_buf[GTP_ADDR_LENGTH]);
+ */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step8:recall check 2k bootload_isp firmware */
+ dev_dbg(&client->dev,
+ "[burn_fw_boot_isp]step9:recall check 2k bootloader firmware");
+ ret = gup_recall_check(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_boot_isp]recall check 2k bootcode_isp firmware fail.");
+ goto exit_burn_fw_boot_isp;
+ }
+
+ update_msg.fw_burned_len += FW_BOOT_ISP_LENGTH;
+ dev_dbg(&client->dev,
+ "[burn_fw_boot_isp]Burned length:%d", update_msg.fw_burned_len);
+ ret = SUCCESS;
+
+exit_burn_fw_boot_isp:
+ kfree(fw_boot_isp);
+
+ return ret;
+}
+
+static u8 gup_burn_fw_link(struct i2c_client *client)
+{
+ u8 *fw_link = NULL;
+ u8 retry = 0;
+ s32 ret = 0;
+ u32 offset;
+
+ if (update_msg.fw_burned_len >= update_msg.fw_total_len) {
+ dev_dbg(&client->dev, "No need to upgrade the link code!");
+ return SUCCESS;
+ }
+ dev_info(&client->dev, "[burn_fw_link]Begin burn link firmware---->>");
+
+ /* step1:Alloc memory */
+ dev_dbg(&client->dev, "[burn_fw_link]step1:Alloc memory");
+ while (retry++ < 5) {
+ fw_link = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+ if (fw_link == NULL) {
+ continue;
+ } else {
+ dev_dbg(&client->dev,
+ "[burn_fw_link]Alloc %dk byte memory success.",
+ (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ dev_err(&client->dev, "[burn_fw_link]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* step2:load firmware link section 1 */
+ dev_dbg(&client->dev,
+ "[burn_fw_link]step2:load firmware link section 1");
+ offset = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH;
+ ret = gup_load_section_file(
+ fw_link, offset, FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_link]load firmware link section 1 fail.");
+ goto exit_burn_fw_link;
+ }
+
+ /* step3:burn link firmware section 1 */
+ dev_dbg(&client->dev,
+ "[burn_fw_link]step3:burn link firmware section 1");
+ ret = gup_burn_fw_gwake_section(
+ client, fw_link, 0x9000, FW_SECTION_LENGTH, 0x38);
+
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_link]burn link firmware section 1 fail.");
+ goto exit_burn_fw_link;
+ }
+
+ /* step4:load link firmware section 2 file data */
+ dev_dbg(&client->dev,
+ "[burn_fw_link]step4:load link firmware section 2 file data");
+ offset += FW_SECTION_LENGTH;
+ ret = gup_load_section_file(
+ fw_link, offset, FW_GLINK_LENGTH - FW_SECTION_LENGTH, SEEK_SET);
+
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_link]load link firmware section 2 fail.");
+ goto exit_burn_fw_link;
+ }
+
+ /* step5:burn link firmware section 2 */
+ dev_dbg(&client->dev,
+ "[burn_fw_link]step4:burn link firmware section 2");
+ ret = gup_burn_fw_gwake_section(client,
+ fw_link, 0x9000, FW_GLINK_LENGTH - FW_SECTION_LENGTH, 0x39);
+
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_link]burn link firmware section 2 fail.");
+ goto exit_burn_fw_link;
+ }
+
+ update_msg.fw_burned_len += FW_GLINK_LENGTH;
+ dev_dbg(&client->dev,
+ "[burn_fw_link]Burned length:%d", update_msg.fw_burned_len);
+ ret = SUCCESS;
+
+exit_burn_fw_link:
+ kfree(fw_link);
+
+ return ret;
+}
+
+static u8 gup_burn_fw_gwake_section(struct i2c_client *client,
+ u8 *fw_section, u16 start_addr, u32 len, u8 bank_cmd)
+{
+ s32 ret = 0;
+ u8 rd_buf[5];
+
+ /* step1:hold ss51 & dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_app_section]hold ss51 & dsp fail.");
+ return FAIL;
+ }
+
+ /* step2:set scramble */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_app_section]set scramble fail.");
+ return FAIL;
+ }
+
+ /* step3:hold ss51 & release dsp */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_app_section]hold ss51 & release dsp fail.");
+ return FAIL;
+ }
+ /* must delay */
+ usleep_range(1000, 2000);
+
+ /* step4:select bank */
+ ret = gup_set_ic_msg(
+ client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_section]select bank %d fail.",
+ (bank_cmd >> 4)&0x0F);
+ return FAIL;
+ }
+
+ /* step5:burn fw section */
+ ret = gup_burn_proc(client, fw_section, start_addr, len);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_app_section]burn fw_section fail.");
+ return FAIL;
+ }
+
+ /* step6:send burn cmd to move data to flash from sram */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0F);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_app_section]send burn cmd fail.");
+ return FAIL;
+ }
+ dev_dbg(&client->dev,
+ "[burn_fw_section]Wait for the burn is complete......");
+ do {
+ ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_app_section]Get burn state fail");
+ return FAIL;
+ }
+ usleep_range(10000, 11000);
+ /* dev_dbg(&client->dev, "[burn_fw_app_section]Get burn state:%d."
+ * rd_buf[GTP_ADDR_LENGTH]);
+ */
+ } while (rd_buf[GTP_ADDR_LENGTH]);
+
+ /* step7:recall fw section */
+ ret = gup_recall_check(client, fw_section, start_addr, len);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_app_section]recall check %dk firmware fail.",
+ len/1024);
+ return FAIL;
+ }
+
+ return SUCCESS;
+}
+
+static u8 gup_burn_fw_gwake(struct i2c_client *client)
+{
+ u8 *fw_gwake = NULL;
+ u8 retry = 0;
+ s32 ret = 0;
+ u16 start_index = 4*FW_SECTION_LENGTH +
+ FW_DSP_LENGTH + FW_BOOT_LENGTH +
+ FW_BOOT_ISP_LENGTH + FW_GLINK_LENGTH;/* 32 + 4 + 2 + 4 = 42K */
+ /* u16 start_index; */
+
+ if (start_index >= update_msg.fw_total_len) {
+ dev_dbg(&client->dev, "No need to upgrade the gwake code!");
+ return SUCCESS;
+ }
+ /* start_index = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; */
+ dev_info(&client->dev,
+ "[burn_fw_gwake]Begin burn gwake firmware---->>");
+
+ /* step1:alloc memory */
+ dev_dbg(&client->dev, "[burn_fw_gwake]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_gwake =
+ kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+ if (fw_gwake == NULL) {
+ continue;
+ } else {
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]Alloc %dk byte memory success.",
+ (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ dev_err(&client->dev, "[burn_fw_gwake]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ /* clear control flag */
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_finish]clear control flag fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* step2:load app_code firmware section 1 file data */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]step2:load app_code firmware section 1 file data");
+ ret = gup_load_section_file(fw_gwake,
+ start_index, FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_gwake]load app_code firmware section 1 fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* step3:burn app_code firmware section 1 */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]step3:burn app_code firmware section 1");
+ ret = gup_burn_fw_gwake_section(client,
+ fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3A);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_gwake]burn app_code firmware section 1 fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* step5:load app_code firmware section 2 file data */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]step5:load app_code firmware section 2 file data");
+ ret = gup_load_section_file(
+ fw_gwake, start_index+FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_gwake]load app_code firmware section 2 fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* step6:burn app_code firmware section 2 */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]step6:burn app_code firmware section 2");
+ ret = gup_burn_fw_gwake_section(client,
+ fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3B);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_gwake]burn app_code firmware section 2 fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* step7:load app_code firmware section 3 file data */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]step7:load app_code firmware section 3 file data");
+ ret = gup_load_section_file(
+ fw_gwake, start_index + 2*FW_SECTION_LENGTH,
+ FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_gwake]load app_code firmware section 3 fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* step8:burn app_code firmware section 3 */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]step8:burn app_code firmware section 3");
+ ret = gup_burn_fw_gwake_section(
+ client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3C);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_gwake]burn app_code firmware section 3 fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* step9:load app_code firmware section 4 file data */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]step9:load app_code firmware section 4 file data");
+ ret = gup_load_section_file(fw_gwake,
+ start_index + 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_gwake]load app_code firmware section 4 fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* step10:burn app_code firmware section 4 */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]step10:burn app_code firmware section 4");
+ ret = gup_burn_fw_gwake_section(
+ client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3D);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_gwake]burn app_code firmware section 4 fail.");
+ goto exit_burn_fw_gwake;
+ }
+
+ /* update_msg.fw_burned_len += FW_GWAKE_LENGTH; */
+ dev_dbg(&client->dev,
+ "[burn_fw_gwake]Burned length:%d", update_msg.fw_burned_len);
+ ret = SUCCESS;
+
+exit_burn_fw_gwake:
+ kfree(fw_gwake);
+
+ return ret;
+}
+
+static u8 gup_burn_fw_finish(struct i2c_client *client)
+{
+ u8 *fw_ss51 = NULL;
+ u8 retry = 0;
+ s32 ret = 0;
+
+ dev_info(&client->dev,
+ "[burn_fw_finish]burn first 8K of ss51 and finish update.");
+ /* step1:alloc memory */
+ dev_dbg(&client->dev, "[burn_fw_finish]step1:alloc memory");
+ while (retry++ < 5) {
+ fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL);
+ if (fw_ss51 == NULL) {
+ continue;
+ } else {
+ dev_dbg(&client->dev,
+ "[burn_fw_finish]Alloc %dk byte memory success.",
+ (FW_SECTION_LENGTH/1024));
+ break;
+ }
+ }
+ if (retry >= 5) {
+ dev_err(&client->dev,
+ "[burn_fw_finish]Alloc memory fail,exit.");
+ return FAIL;
+ }
+
+ dev_dbg(&client->dev, "[burn_fw_finish]step2: burn ss51 first 8K.");
+ ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH, SEEK_SET);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_finish]load ss51 firmware section 1 fail.");
+ goto exit_burn_fw_finish;
+ }
+
+ dev_dbg(&client->dev, "[burn_fw_finish]step3:clear control flag");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_finish]clear control flag fail.");
+ goto exit_burn_fw_finish;
+ }
+
+ dev_dbg(&client->dev,
+ "[burn_fw_finish]step4:burn ss51 firmware section 1");
+ ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01);
+ if (ret == FAIL) {
+ dev_err(&client->dev,
+ "[burn_fw_finish]burn ss51 firmware section 1 fail.");
+ goto exit_burn_fw_finish;
+ }
+
+ /* step11:enable download DSP code */
+ dev_dbg(&client->dev,
+ "[burn_fw_finish]step5:enable download DSP code ");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_finish]enable download DSP code fail.");
+ goto exit_burn_fw_finish;
+ }
+
+ /* step12:release ss51 & hold dsp */
+ dev_dbg(&client->dev, "[burn_fw_finish]step6:release ss51 & hold dsp");
+ ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08);
+ if (ret <= 0) {
+ dev_err(&client->dev,
+ "[burn_fw_finish]release ss51 & hold dsp fail.");
+ goto exit_burn_fw_finish;
+ }
+
+ if (fw_ss51 != NULL)
+ kfree(fw_ss51);
+ return SUCCESS;
+
+exit_burn_fw_finish:
+ if (fw_ss51 != NULL)
+ kfree(fw_ss51);
+
+ return FAIL;
+}
+
+/* return 0 can update, else no update condition */
+static int gup_update_condition_check(struct goodix_ts_data *ts)
+{
+ if (test_bit(SLEEP_MODE, &ts->flags)) {
+ dev_info(&ts->client->dev, "Update abort, tp in sleep mode\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+s32 gup_update_proc(void *dir)
+{
+ s32 ret = 0;
+ s32 update_ret = FAIL;
+ u8 retry = 0;
+ struct st_fw_head fw_head;
+ struct goodix_ts_data *ts = NULL;
+
+ ts = i2c_get_clientdata(i2c_connect_client);
+
+ dev_dbg(&ts->client->dev, "[update_proc]Begin update ......\n");
+
+ show_len = 1;
+ total_len = 100;
+
+ ret = gup_update_condition_check(ts);
+ if (ret) {
+ dev_warn(&ts->client->dev, "Update start failed\n");
+ return FAIL;
+ }
+
+ if (test_and_set_bit(FW_UPDATE_RUNNING, &ts->flags)) {
+ dev_warn(&ts->client->dev, "FW update may already running\n");
+ return FAIL;
+ }
+
+ ret = gup_get_update_file(i2c_connect_client, &fw_head, (u8 *)dir);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "Failed get valied firmware data\n");
+ clear_bit(FW_UPDATE_RUNNING, &ts->flags);
+ return FAIL;
+ }
+
+ gtp_work_control_enable(ts, false);
+ gtp_esd_off(ts);
+
+ ret = gup_get_ic_fw_msg(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev, "[update_proc]get ic message fail.");
+ goto file_fail;
+ }
+
+ if (ts->force_update || dir) {
+ dev_dbg(&ts->client->dev, "Enter force update.");
+ } else {
+ ret = gup_enter_update_judge(i2c_connect_client, &fw_head);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]Doesn't meet update condition\n");
+ goto file_fail;
+ }
+ }
+
+ ret = gup_enter_update_mode(ts->client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]enter update mode fail.");
+ goto update_fail;
+ }
+
+ while (retry++ < 5) {
+ show_len = 10;
+ total_len = 100;
+ update_msg.fw_burned_len = 0;
+ ret = gup_burn_dsp_isp(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]burn dsp isp fail.");
+ continue;
+ }
+
+ show_len = 20;
+ ret = gup_burn_fw_gwake(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]burn app_code firmware fail.");
+ continue;
+ }
+
+ show_len = 30;
+ ret = gup_burn_fw_ss51(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]burn ss51 firmware fail.");
+ continue;
+ }
+
+ show_len = 40;
+ ret = gup_burn_fw_dsp(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]burn dsp firmware fail.");
+ continue;
+ }
+
+ show_len = 50;
+ ret = gup_burn_fw_boot(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]burn bootloader firmware fail.");
+ continue;
+ }
+ show_len = 60;
+
+ ret = gup_burn_fw_boot_isp(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]burn boot_isp firmware fail.");
+ continue;
+ }
+
+ show_len = 70;
+ ret = gup_burn_fw_link(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]burn link firmware fail.");
+ continue;
+ }
+
+ show_len = 80;
+ ret = gup_burn_fw_finish(i2c_connect_client);
+ if (ret == FAIL) {
+ dev_err(&ts->client->dev,
+ "[update_proc]burn finish fail.");
+ continue;
+ }
+ show_len = 90;
+ dev_info(&ts->client->dev, "[update_proc]UPDATE SUCCESS.");
+ retry = 0;
+ break;
+ }
+
+ if (retry >= 5) {
+ dev_err(&ts->client->dev,
+ "[update_proc]retry timeout,UPDATE FAIL.");
+ update_ret = FAIL;
+ } else {
+ update_ret = SUCCESS;
+ }
+
+update_fail:
+ dev_dbg(&ts->client->dev, "[update_proc]leave update mode.");
+ gup_leave_update_mode(i2c_connect_client);
+
+ msleep(GTP_100_DLY_MS);
+
+ if (update_ret == SUCCESS) {
+ dev_info(&ts->client->dev,
+ "firmware error auto update, resent config!\n");
+ gup_init_panel(ts);
+ }
+ gtp_get_fw_info(ts->client, &ts->fw_info);
+
+file_fail:
+
+ update_msg.fw_data = NULL;
+ update_msg.fw_total_len = 0;
+ release_firmware(update_msg.fw);
+
+ clear_bit(FW_UPDATE_RUNNING, &ts->flags);
+ gtp_work_control_enable(ts, true);
+ gtp_esd_on(ts);
+ total_len = 100;
+ ts->force_update = false;
+ if (update_ret == SUCCESS) {
+ show_len = 100;
+ clear_bit(FW_ERROR, &ts->flags);
+ return SUCCESS;
+ }
+
+ show_len = 200;
+ return FAIL;
+}
+
+u8 gup_init_update_proc(struct goodix_ts_data *ts)
+{
+ struct task_struct *thread = NULL;
+
+ dev_info(&ts->client->dev, "Ready to run update thread.");
+
+ thread = kthread_run(gup_update_proc,
+ (void *)NULL, "guitar_update");
+
+ if (IS_ERR(thread)) {
+ dev_err(&ts->client->dev,
+ "Failed to create update thread.\n");
+ return -EPERM;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
index a15ccdc..d3c39f9 100644
--- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -1884,7 +1884,7 @@
}
rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK,
- &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ);
+ &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0);
if (rc) {
CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc);
goto detach_smmu;
diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
index 2c364e01..4256064 100644
--- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
+++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h
@@ -153,4 +153,10 @@
int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
void __iomem *icp_base, bool debug);
+/**
+ * cam_hfi_queue_dump() - utility function to dump hfi queues
+ */
+void cam_hfi_queue_dump(void);
+
+
#endif /* _HFI_INTF_H_ */
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index a0752f5..de72e85 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -47,6 +47,49 @@
static DEFINE_MUTEX(hfi_cmd_q_mutex);
static DEFINE_MUTEX(hfi_msg_q_mutex);
+void cam_hfi_queue_dump(void)
+{
+ struct hfi_qtbl *qtbl;
+ struct hfi_qtbl_hdr *qtbl_hdr;
+ struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr;
+ struct hfi_mem_info *hfi_mem = NULL;
+ uint32_t *read_q, *read_ptr;
+ int i;
+
+ hfi_mem = &g_hfi->map;
+ if (!hfi_mem) {
+ CAM_ERR(CAM_HFI, "Unable to dump queues hfi memory is NULL");
+ return;
+ }
+
+ qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva;
+ qtbl_hdr = &qtbl->q_tbl_hdr;
+ CAM_INFO(CAM_HFI,
+ "qtbl: version = %x size = %u num q = %u qhdr_size = %u",
+ qtbl_hdr->qtbl_version, qtbl_hdr->qtbl_size,
+ qtbl_hdr->qtbl_num_q, qtbl_hdr->qtbl_qhdr_size);
+
+ cmd_q_hdr = &qtbl->q_hdr[Q_CMD];
+ CAM_INFO(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x",
+ cmd_q_hdr->qhdr_q_size, cmd_q_hdr->qhdr_read_idx,
+ cmd_q_hdr->qhdr_write_idx, hfi_mem->cmd_q.iova);
+ read_q = (uint32_t *)g_hfi->map.cmd_q.kva;
+ read_ptr = (uint32_t *)(read_q + 0);
+ CAM_INFO(CAM_HFI, "CMD Q START");
+ for (i = 0; i < ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++)
+ CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]);
+
+ msg_q_hdr = &qtbl->q_hdr[Q_MSG];
+ CAM_INFO(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x",
+ msg_q_hdr->qhdr_q_size, msg_q_hdr->qhdr_read_idx,
+ msg_q_hdr->qhdr_write_idx, hfi_mem->msg_q.iova);
+ read_q = (uint32_t *)g_hfi->map.msg_q.kva;
+ read_ptr = (uint32_t *)(read_q + 0);
+ CAM_INFO(CAM_HFI, "MSG Q START");
+ for (i = 0; i < ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++)
+ CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]);
+}
+
int hfi_write_cmd(void *cmd_ptr)
{
uint32_t size_in_words, empty_space, new_write_idx, read_idx, temp;
@@ -92,7 +135,8 @@
(q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) :
(read_idx - q->qhdr_write_idx);
if (empty_space <= size_in_words) {
- CAM_ERR(CAM_HFI, "failed");
+ CAM_ERR(CAM_HFI, "failed: empty space %u, size_in_words %u",
+ empty_space, size_in_words);
rc = -EIO;
goto err;
}
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
index 16e97ea..3c5690d 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c
@@ -1833,7 +1833,7 @@
rc = hfi_read_message(icp_hw_mgr.msg_buf, Q_MSG, &read_len);
if (rc) {
- CAM_DBG(CAM_ICP, "Unable to read msg q");
+ CAM_DBG(CAM_ICP, "Unable to read msg q rc %d", rc);
} else {
read_len = read_len << BYTE_WORD_SHIFT;
msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf;
@@ -2323,6 +2323,7 @@
if (!rem_jiffies) {
rc = -ETIMEDOUT;
CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command");
+ cam_hfi_queue_dump();
}
kfree(abort_cmd);
@@ -2379,6 +2380,7 @@
if (icp_hw_mgr.a5_debug_type ==
HFI_DEBUG_MODE_QUEUE)
cam_icp_mgr_process_dbg_buf();
+ cam_hfi_queue_dump();
}
kfree(destroy_cmd);
return rc;
@@ -2680,6 +2682,7 @@
if (!rem_jiffies) {
rc = -ETIMEDOUT;
CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
+ cam_hfi_queue_dump();
}
CAM_DBG(CAM_ICP, "Done Waiting for INIT DONE Message");
@@ -2858,8 +2861,10 @@
struct hfi_cmd_work_data *task_data;
struct hfi_cmd_ipebps_async *hfi_cmd;
struct cam_hw_update_entry *hw_update_entries;
+ struct icp_frame_info *frame_info = NULL;
- request_id = *(uint64_t *)config_args->priv;
+ frame_info = (struct icp_frame_info *)config_args->priv;
+ request_id = frame_info->request_id;
hw_update_entries = config_args->hw_update_entries;
CAM_DBG(CAM_ICP, "req_id = %lld %pK", request_id, config_args->priv);
@@ -2881,6 +2886,82 @@
return rc;
}
+static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data,
+ uint32_t io_buf_addr)
+{
+ int rc = 0;
+ struct hfi_cmd_work_data *task_data;
+ struct hfi_cmd_ipebps_async ioconfig_cmd;
+ unsigned long rem_jiffies;
+ int timeout = 5000;
+ struct crm_workq_task *task;
+ uint32_t size_in_words;
+
+ task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+ if (!task)
+ return -ENOMEM;
+
+ ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
+ ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
+ if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
+ ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO;
+ else
+ ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
+
+ reinit_completion(&ctx_data->wait_complete);
+
+ ioconfig_cmd.num_fw_handles = 1;
+ ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle;
+ ioconfig_cmd.payload.indirect = io_buf_addr;
+ ioconfig_cmd.user_data1 = (uint64_t)ctx_data;
+ ioconfig_cmd.user_data2 = (uint64_t)0x0;
+ task_data = (struct hfi_cmd_work_data *)task->payload;
+ task_data->data = (void *)&ioconfig_cmd;
+ task_data->request_id = 0;
+ task_data->type = ICP_WORKQ_TASK_MSG_TYPE;
+ task->process_cb = cam_icp_mgr_process_cmd;
+ size_in_words = (*(uint32_t *)task_data->data) >> 2;
+ CAM_INFO(CAM_ICP, "size_in_words %u", size_in_words);
+ rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+ CRM_TASK_PRIORITY_0);
+ if (rc)
+ return rc;
+
+ rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
+ msecs_to_jiffies((timeout)));
+ if (!rem_jiffies) {
+ rc = -ETIMEDOUT;
+ CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
+ cam_hfi_queue_dump();
+ }
+
+ return rc;
+}
+
+static int cam_icp_mgr_send_recfg_io(struct cam_icp_hw_ctx_data *ctx_data,
+ struct hfi_cmd_ipebps_async *ioconfig_cmd, uint64_t req_id)
+{
+ int rc = 0;
+ struct hfi_cmd_work_data *task_data;
+ struct crm_workq_task *task;
+
+ task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
+ if (!task)
+ return -ENOMEM;
+
+ task_data = (struct hfi_cmd_work_data *)task->payload;
+ task_data->data = (void *)ioconfig_cmd;
+ task_data->request_id = req_id;
+ task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
+ task->process_cb = cam_icp_mgr_process_cmd;
+ rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
+ CRM_TASK_PRIORITY_0);
+ if (rc)
+ return rc;
+
+ return rc;
+}
+
static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args)
{
int rc = 0;
@@ -2889,6 +2970,7 @@
struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv;
struct cam_hw_config_args *config_args = config_hw_args;
struct cam_icp_hw_ctx_data *ctx_data = NULL;
+ struct icp_frame_info *frame_info = NULL;
if (!hw_mgr || !config_args) {
CAM_ERR(CAM_ICP, "Invalid arguments %pK %pK",
@@ -2912,11 +2994,23 @@
return -EINVAL;
}
- req_id = *(uint64_t *)config_args->priv;
+ frame_info = (struct icp_frame_info *)config_args->priv;
+ req_id = frame_info->request_id;
idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id);
ctx_data->hfi_frame_process.fw_process_flag[idx] = true;
cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx);
+ CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id,
+ frame_info->io_config);
+
+ if (frame_info->io_config != 0) {
+ CAM_INFO(CAM_ICP, "Send recfg io");
+ rc = cam_icp_mgr_send_recfg_io(ctx_data,
+ &frame_info->hfi_cfg_io_cmd, req_id);
+ if (rc)
+ CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd");
+ }
+
rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args);
if (rc)
goto config_err;
@@ -3147,7 +3241,9 @@
struct icp_cmd_generic_blob *blob;
struct cam_icp_hw_ctx_data *ctx_data;
uint32_t index;
+ size_t io_buf_size;
int rc = 0;
+ uint64_t pResource;
if (!blob_data || (blob_size == 0)) {
CAM_ERR(CAM_ICP, "Invalid blob info %pK %d", blob_data,
@@ -3176,6 +3272,28 @@
clk_info->compressed_bw);
break;
+ case CAM_ICP_CMD_GENERIC_BLOB_CFG_IO:
+ CAM_DBG(CAM_ICP, "CAM_ICP_CMD_GENERIC_BLOB_CFG_IO");
+ pResource = *((uint32_t *)blob_data);
+ if (copy_from_user(&ctx_data->icp_dev_io_info,
+ (void __user *)pResource,
+ sizeof(struct cam_icp_acquire_dev_info))) {
+ CAM_ERR(CAM_ICP, "Failed in copy from user");
+ return -EFAULT;
+ }
+ CAM_DBG(CAM_ICP, "buf handle %d",
+ ctx_data->icp_dev_io_info.io_config_cmd_handle);
+ rc = cam_mem_get_io_buf(
+ ctx_data->icp_dev_io_info.io_config_cmd_handle,
+ icp_hw_mgr.iommu_hdl,
+ blob->io_buf_addr, &io_buf_size);
+ if (rc)
+ CAM_ERR(CAM_ICP, "Failed in blob update");
+ else
+ CAM_DBG(CAM_ICP, "io buf addr %llu",
+ *blob->io_buf_addr);
+ break;
+
default:
CAM_WARN(CAM_ICP, "Invalid blob type %d", blob_type);
break;
@@ -3186,7 +3304,8 @@
static int cam_icp_process_generic_cmd_buffer(
struct cam_packet *packet,
struct cam_icp_hw_ctx_data *ctx_data,
- int32_t index)
+ int32_t index,
+ uint64_t *io_buf_addr)
{
int i, rc = 0;
struct cam_cmd_buf_desc *cmd_desc = NULL;
@@ -3194,6 +3313,7 @@
cmd_generic_blob.ctx = ctx_data;
cmd_generic_blob.frame_info_idx = index;
+ cmd_generic_blob.io_buf_addr = io_buf_addr;
cmd_desc = (struct cam_cmd_buf_desc *)
((uint32_t *) &packet->payload + packet->cmd_buf_offset/4);
@@ -3213,6 +3333,28 @@
return rc;
}
+static int cam_icp_mgr_process_cfg_io_cmd(
+ struct cam_icp_hw_ctx_data *ctx_data,
+ struct hfi_cmd_ipebps_async *ioconfig_cmd,
+ uint64_t request_id,
+ uint64_t io_config)
+{
+ ioconfig_cmd->size = sizeof(struct hfi_cmd_ipebps_async);
+ ioconfig_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
+ if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
+ ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO;
+ else
+ ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
+
+ ioconfig_cmd->num_fw_handles = 1;
+ ioconfig_cmd->fw_handles[0] = ctx_data->fw_handle;
+ ioconfig_cmd->payload.indirect = io_config;
+ ioconfig_cmd->user_data1 = (uint64_t)ctx_data;
+ ioconfig_cmd->user_data2 = request_id;
+
+ return 0;
+}
+
static int cam_icp_mgr_update_hfi_frame_process(
struct cam_icp_hw_ctx_data *ctx_data,
struct cam_packet *packet,
@@ -3220,6 +3362,7 @@
int32_t *idx)
{
int32_t index, rc;
+ struct hfi_cmd_ipebps_async *hfi_cmd = NULL;
index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap,
ctx_data->hfi_frame_process.bits);
@@ -3231,15 +3374,27 @@
ctx_data->hfi_frame_process.request_id[index] =
packet->header.request_id;
- rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index);
+ ctx_data->hfi_frame_process.frame_info[index].request_id =
+ packet->header.request_id;
+ ctx_data->hfi_frame_process.frame_info[index].io_config = 0;
+ rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index,
+ &ctx_data->hfi_frame_process.frame_info[index].io_config);
if (rc) {
clear_bit(index, ctx_data->hfi_frame_process.bitmap);
ctx_data->hfi_frame_process.request_id[index] = -1;
return rc;
}
+
+ if (ctx_data->hfi_frame_process.frame_info[index].io_config) {
+ hfi_cmd = (struct hfi_cmd_ipebps_async *)&ctx_data->
+ hfi_frame_process.frame_info[index].hfi_cfg_io_cmd;
+ rc = cam_icp_mgr_process_cfg_io_cmd(ctx_data, hfi_cmd,
+ packet->header.request_id, ctx_data->
+ hfi_frame_process.frame_info[index].io_config);
+ }
*idx = index;
- return 0;
+ return rc;
}
static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv,
@@ -3320,7 +3475,7 @@
prepare_args->num_hw_update_entries = 1;
prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd;
- prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx];
+ prepare_args->priv = &ctx_data->hfi_frame_process.frame_info[idx];
CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u",
packet->header.request_id, ctx_data->ctx_id);
@@ -3584,53 +3739,6 @@
return rc;
}
-static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data,
- uint32_t io_buf_addr)
-{
- int rc = 0;
- struct hfi_cmd_work_data *task_data;
- struct hfi_cmd_ipebps_async ioconfig_cmd;
- unsigned long rem_jiffies;
- int timeout = 5000;
- struct crm_workq_task *task;
-
- task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work);
- if (!task)
- return -ENOMEM;
-
- ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
- ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
- if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS)
- ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO;
- else
- ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO;
-
- reinit_completion(&ctx_data->wait_complete);
- ioconfig_cmd.num_fw_handles = 1;
- ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle;
- ioconfig_cmd.payload.indirect = io_buf_addr;
- ioconfig_cmd.user_data1 = (uint64_t)ctx_data;
- ioconfig_cmd.user_data2 = (uint64_t)0x0;
- task_data = (struct hfi_cmd_work_data *)task->payload;
- task_data->data = (void *)&ioconfig_cmd;
- task_data->request_id = 0;
- task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
- task->process_cb = cam_icp_mgr_process_cmd;
- rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
- CRM_TASK_PRIORITY_0);
- if (rc)
- return rc;
-
- rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
- msecs_to_jiffies((timeout)));
- if (!rem_jiffies) {
- rc = -ETIMEDOUT;
- CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
- }
-
- return rc;
-}
-
static int cam_icp_mgr_create_handle(uint32_t dev_type,
struct cam_icp_hw_ctx_data *ctx_data)
{
@@ -3665,6 +3773,7 @@
if (!rem_jiffies) {
rc = -ETIMEDOUT;
CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
+ cam_hfi_queue_dump();
}
if (ctx_data->fw_handle == 0) {
@@ -3710,6 +3819,7 @@
if (!rem_jiffies) {
rc = -ETIMEDOUT;
CAM_ERR(CAM_ICP, "FW response timed out %d", rc);
+ cam_hfi_queue_dump();
}
return rc;
@@ -3843,6 +3953,8 @@
icp_dev_acquire_info = ctx_data->icp_dev_acquire_info;
+ CAM_DBG(CAM_ICP, "acquire io buf handle %d",
+ icp_dev_acquire_info->io_config_cmd_handle);
rc = cam_mem_get_io_buf(
icp_dev_acquire_info->io_config_cmd_handle,
hw_mgr->iommu_hdl,
@@ -4134,21 +4246,22 @@
int i;
rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK,
- &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ);
+ &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ,
+ 0);
if (rc) {
CAM_ERR(CAM_ICP, "unable to create a command worker");
goto cmd_work_failed;
}
rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK,
- &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ);
+ &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0);
if (rc) {
CAM_ERR(CAM_ICP, "unable to create a message worker");
goto msg_work_failed;
}
rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK,
- &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ);
+ &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0);
if (rc) {
CAM_ERR(CAM_ICP, "unable to create a timer worker");
goto timer_work_failed;
diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
index 8746ee2..3e3c0e0 100644
--- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
+++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h
@@ -126,6 +126,19 @@
};
/**
+ * struct icp_frame_info
+ * @request_id: request id
+ * @io_config: the address of io config
+ * @hfi_cfg_io_cmd: command struct to be sent to hfi
+ */
+struct icp_frame_info {
+ uint64_t request_id;
+ uint64_t io_config;
+ struct hfi_cmd_ipebps_async hfi_cfg_io_cmd;
+};
+
+
+/**
* struct hfi_frame_process_info
* @hfi_frame_cmd: Frame process command info
* @bitmap: Bitmap for hfi_frame_cmd
@@ -136,6 +149,7 @@
* @out_resource: Out sync info
* @fw_process_flag: Frame process flag
* @clk_info: Clock information for a request
+ * @frame_info: information needed to process request
*/
struct hfi_frame_process_info {
struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX];
@@ -149,6 +163,7 @@
uint32_t in_free_resource[CAM_FRAME_CMD_MAX];
uint32_t fw_process_flag[CAM_FRAME_CMD_MAX];
struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX];
+ struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX];
};
/**
@@ -189,6 +204,7 @@
* @clk_info: Current clock info of a context
* @watch_dog: watchdog timer handle
* @watch_dog_reset_counter: Counter for watch dog reset
+ * @icp_dev_io_info: io config resource
*/
struct cam_icp_hw_ctx_data {
void *context_priv;
@@ -208,16 +224,19 @@
struct cam_ctx_clk_info clk_info;
struct cam_req_mgr_timer *watch_dog;
uint32_t watch_dog_reset_counter;
+ struct cam_icp_acquire_dev_info icp_dev_io_info;
};
/**
* struct icp_cmd_generic_blob
* @ctx: Current context info
* @frame_info_idx: Index used for frame process info
+ * @io_buf_addr: pointer to io buffer address
*/
struct icp_cmd_generic_blob {
struct cam_icp_hw_ctx_data *ctx;
uint32_t frame_info_idx;
+ uint64_t *io_buf_addr;
};
/**
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
index c1aa501..e5c54d6 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c
@@ -225,6 +225,8 @@
CAM_ERR(CAM_ISP, "Can not start HW resources");
goto err;
}
+ CAM_DBG(CAM_ISP, "Start HW %d Res %d", hw_intf->hw_idx,
+ isp_hw_res->hw_res[i]->res_id);
} else {
CAM_ERR(CAM_ISP, "function null");
goto err;
@@ -366,7 +368,8 @@
isp_res = hw_mgr_res->hw_res[i];
if (isp_res->hw_intf->hw_idx != base_idx)
continue;
-
+ CAM_DBG(CAM_ISP, "base_idx %d res_id %d cnt %u",
+ base_idx, isp_res->res_id, cnt);
stop_res[cnt] = isp_res;
cnt++;
}
@@ -483,8 +486,8 @@
"Add split id = %d for base idx = %d num_base=%d",
split_id, base_idx, ctx->num_base);
} else {
- /*Check if base index is alreay exist in the list */
- for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
+ /*Check if base index already exists in the list */
+ for (i = 0; i < ctx->num_base; i++) {
if (ctx->base[i].idx == base_idx) {
if (split_id != CAM_ISP_HW_SPLIT_MAX &&
ctx->base[i].split_id ==
@@ -495,7 +498,7 @@
}
}
- if (i == CAM_IFE_HW_NUM_MAX) {
+ if (i == ctx->num_base) {
ctx->base[ctx->num_base].split_id = split_id;
ctx->base[ctx->num_base].idx = base_idx;
ctx->num_base++;
@@ -845,7 +848,8 @@
}
ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node;
CAM_DBG(CAM_ISP,
- "acquire success res type :0x%x res id:0x%x",
+ "acquire success IFE:%d res type :0x%x res id:0x%x",
+ hw_intf->hw_idx,
ife_src_res->hw_res[i]->res_type,
ife_src_res->hw_res[i]->res_id);
@@ -871,29 +875,75 @@
static int cam_ife_mgr_acquire_cid_res(
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port,
- uint32_t *cid_res_id,
+ struct cam_ife_hw_mgr_res **cid_res,
enum cam_ife_pix_path_res_id csid_path)
{
int rc = -1;
int i, j;
struct cam_ife_hw_mgr *ife_hw_mgr;
- struct cam_ife_hw_mgr_res *cid_res;
struct cam_hw_intf *hw_intf;
+ struct cam_ife_hw_mgr_res *cid_res_temp, *cid_res_iterator;
struct cam_csid_hw_reserve_resource_args csid_acquire;
+ uint32_t acquired_cnt = 0;
ife_hw_mgr = ife_ctx->hw_mgr;
+ *cid_res = NULL;
- rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res);
+ rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, cid_res);
if (rc) {
CAM_ERR(CAM_ISP, "No more free hw mgr resource");
- goto err;
+ goto end;
}
- cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res);
+
+ cid_res_temp = *cid_res;
csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
csid_acquire.in_port = in_port;
csid_acquire.res_id = csid_path;
+ CAM_DBG(CAM_ISP, "path %d", csid_path);
+ /* Try acquiring CID resource from previously acquired HW */
+ list_for_each_entry(cid_res_iterator, &ife_ctx->res_list_ife_cid,
+ list) {
+
+ for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+ if (!cid_res_iterator->hw_res[i])
+ continue;
+
+ hw_intf = cid_res_iterator->hw_res[i]->hw_intf;
+ rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+ &csid_acquire, sizeof(csid_acquire));
+ if (rc) {
+ CAM_DBG(CAM_ISP,
+ "No ife cid resource from hw %d",
+ hw_intf->hw_idx);
+ continue;
+ }
+
+ cid_res_temp->hw_res[acquired_cnt++] =
+ csid_acquire.node_res;
+
+ CAM_DBG(CAM_ISP,
+ "acquired csid(%s)=%d CID rsrc successfully",
+ (i == 0) ? "left" : "right",
+ hw_intf->hw_idx);
+
+ if (in_port->usage_type && acquired_cnt == 1 &&
+ csid_path == CAM_IFE_PIX_PATH_RES_IPP)
+ /* Continue to acquire Right */
+ continue;
+
+ if (acquired_cnt)
+ /*
+ * If successfully acquired CID from
+ * previously acquired HW, skip the next
+ * part
+ */
+ goto acquire_successful;
+ }
+ }
+
+ /* Acquire Left if not already acquired */
for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) {
if (!ife_hw_mgr->csid_devices[i])
continue;
@@ -903,31 +953,45 @@
sizeof(csid_acquire));
if (rc)
continue;
- else
+ else {
+ cid_res_temp->hw_res[acquired_cnt++] =
+ csid_acquire.node_res;
break;
+ }
}
if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) {
- CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource");
- goto err;
+ CAM_ERR(CAM_ISP, "Can not acquire ife cid resource for path %d",
+ csid_path);
+ goto put_res;
}
- cid_res->res_type = CAM_IFE_HW_MGR_RES_CID;
- cid_res->res_id = csid_acquire.node_res->res_id;
- cid_res->is_dual_vfe = in_port->usage_type;
- cid_res->hw_res[0] = csid_acquire.node_res;
- cid_res->hw_res[1] = NULL;
- /* CID(DT_ID) value of acquire device, require for path */
- *cid_res_id = csid_acquire.node_res->res_id;
+acquire_successful:
+ CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d",
+ in_port->usage_type);
- if (cid_res->is_dual_vfe) {
+ cid_res_temp->res_type = CAM_IFE_HW_MGR_RES_CID;
+ /* CID(DT_ID) value of acquire device, require for path */
+ cid_res_temp->res_id = csid_acquire.node_res->res_id;
+ cid_res_temp->is_dual_vfe = in_port->usage_type;
+ cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, cid_res);
+
+ /*
+ * Acquire Right if not already acquired.
+ * Dual IFE for RDI is not currently supported.
+ */
+ if (cid_res_temp->is_dual_vfe && csid_path
+ == CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) {
csid_acquire.node_res = NULL;
csid_acquire.res_type = CAM_ISP_RESOURCE_CID;
csid_acquire.in_port = in_port;
- for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
+ for (j = 0; j < CAM_IFE_CSID_HW_NUM_MAX; j++) {
if (!ife_hw_mgr->csid_devices[j])
continue;
+ if (j == cid_res_temp->hw_res[0]->hw_intf->hw_idx)
+ continue;
+
hw_intf = ife_hw_mgr->csid_devices[j];
rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
&csid_acquire, sizeof(csid_acquire));
@@ -940,16 +1004,20 @@
if (j == CAM_IFE_CSID_HW_NUM_MAX) {
CAM_ERR(CAM_ISP,
"Can not acquire ife csid rdi resource");
- goto err;
+ goto end;
}
- cid_res->hw_res[1] = csid_acquire.node_res;
+ cid_res_temp->hw_res[1] = csid_acquire.node_res;
+ CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d",
+ in_port->usage_type);
}
- cid_res->parent = &ife_ctx->res_list_ife_in;
+ cid_res_temp->parent = &ife_ctx->res_list_ife_in;
ife_ctx->res_list_ife_in.child[
- ife_ctx->res_list_ife_in.num_children++] = cid_res;
+ ife_ctx->res_list_ife_in.num_children++] = cid_res_temp;
return 0;
-err:
+put_res:
+ cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, cid_res);
+end:
return rc;
}
@@ -966,35 +1034,25 @@
struct cam_ife_hw_mgr_res *csid_res;
struct cam_ife_hw_mgr_res *cid_res;
struct cam_hw_intf *hw_intf;
- uint32_t cid_res_id;
struct cam_csid_hw_reserve_resource_args csid_acquire;
+ ife_hw_mgr = ife_ctx->hw_mgr;
/* get cid resource */
- rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id,
+ rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res,
CAM_IFE_PIX_PATH_RES_IPP);
if (rc) {
CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
- goto err;
+ goto end;
}
- ife_hw_mgr = ife_ctx->hw_mgr;
-
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res);
if (rc) {
CAM_ERR(CAM_ISP, "No more free hw mgr resource");
- goto err;
+ goto end;
}
- cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
-
- csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH;
- csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP;
- csid_acquire.cid = cid_res_id;
- csid_acquire.in_port = in_port;
- csid_acquire.out_port = in_port->data;
csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH;
csid_res->res_id = CAM_IFE_PIX_PATH_RES_IPP;
- csid_res->is_dual_vfe = in_port->usage_type;
if (in_port->usage_type)
csid_res->is_dual_vfe = 1;
@@ -1003,66 +1061,60 @@
csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE;
}
- list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid,
- list) {
- if (cid_res->res_id != cid_res_id)
- continue;
+ /* IPP resource needs to be from same HW as CID resource */
+ for (i = 0; i <= csid_res->is_dual_vfe; i++) {
+ CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe);
+ csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH;
+ csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP;
+ csid_acquire.cid = cid_res->hw_res[i]->res_id;
+ csid_acquire.in_port = in_port;
+ csid_acquire.out_port = in_port->data;
+ csid_acquire.node_res = NULL;
- for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
- if (!cid_res->hw_res[i])
- continue;
+ hw_intf = cid_res->hw_res[i]->hw_intf;
- hw_intf = ife_hw_mgr->csid_devices[
- cid_res->hw_res[i]->hw_intf->hw_idx];
-
- csid_acquire.node_res = NULL;
- if (csid_res->is_dual_vfe) {
- if (i == CAM_ISP_HW_SPLIT_LEFT) {
- master_idx = hw_intf->hw_idx;
- csid_acquire.sync_mode =
- CAM_ISP_HW_SYNC_MASTER;
- } else {
- if (master_idx == -1) {
- CAM_ERR(CAM_ISP,
- "No Master found");
- goto err;
- }
- csid_acquire.sync_mode =
- CAM_ISP_HW_SYNC_SLAVE;
- csid_acquire.master_idx = master_idx;
+ if (csid_res->is_dual_vfe) {
+ if (i == CAM_ISP_HW_SPLIT_LEFT) {
+ master_idx = hw_intf->hw_idx;
+ csid_acquire.sync_mode =
+ CAM_ISP_HW_SYNC_MASTER;
+ } else {
+ if (master_idx == -1) {
+ CAM_ERR(CAM_ISP,
+ "No Master found");
+ goto put_res;
}
+ csid_acquire.sync_mode =
+ CAM_ISP_HW_SYNC_SLAVE;
+ csid_acquire.master_idx = master_idx;
}
-
- rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
- &csid_acquire, sizeof(csid_acquire));
- if (rc) {
- CAM_ERR(CAM_ISP,
- "Cannot acquire ife csid ipp resource");
- goto err;
- }
-
- csid_res->hw_res[i] = csid_acquire.node_res;
- CAM_DBG(CAM_ISP,
- "acquired csid(%s)=%d ipp rsrc successfully",
- (i == 0) ? "left" : "right",
- hw_intf->hw_idx);
-
}
- if (i == CAM_IFE_CSID_HW_NUM_MAX) {
+ rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+ &csid_acquire, sizeof(csid_acquire));
+ if (rc) {
CAM_ERR(CAM_ISP,
- "Can not acquire ife csid ipp resource");
- goto err;
+ "Cannot acquire ife csid ipp resource");
+ goto put_res;
}
- csid_res->parent = cid_res;
- cid_res->child[cid_res->num_children++] = csid_res;
+ csid_res->hw_res[i] = csid_acquire.node_res;
+ CAM_DBG(CAM_ISP,
+ "acquired csid(%s)=%d ipp rsrc successfully",
+ (i == 0) ? "left" : "right",
+ hw_intf->hw_idx);
}
+ cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
+
+ csid_res->parent = cid_res;
+ cid_res->child[cid_res->num_children++] = csid_res;
CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id);
return 0;
-err:
+put_res:
+ cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res);
+end:
return rc;
}
@@ -1099,111 +1151,88 @@
struct cam_ife_hw_mgr_ctx *ife_ctx,
struct cam_isp_in_port_info *in_port)
{
- int rc = -1;
- int i, j;
+ int rc = -EINVAL;
+ int i;
struct cam_ife_hw_mgr *ife_hw_mgr;
struct cam_ife_hw_mgr_res *csid_res;
struct cam_ife_hw_mgr_res *cid_res;
struct cam_hw_intf *hw_intf;
struct cam_isp_out_port_info *out_port;
- uint32_t cid_res_id;
struct cam_csid_hw_reserve_resource_args csid_acquire;
+ enum cam_ife_pix_path_res_id path_type;
ife_hw_mgr = ife_ctx->hw_mgr;
for (i = 0; i < in_port->num_out_res; i++) {
out_port = &in_port->data[i];
- if (!cam_ife_hw_mgr_is_rdi_res(out_port->res_type))
+ path_type = cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
+ out_port->res_type);
+ if (path_type == CAM_IFE_PIX_PATH_RES_MAX)
continue;
- /* get cid resource */
- rc = cam_ife_mgr_acquire_cid_res(ife_ctx,
- in_port, &cid_res_id,
- cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
- out_port->res_type));
- if (rc) {
- CAM_ERR(CAM_ISP,
- "Acquire IFE CID resource Failed");
- goto err;
+ /* get cid resource */
+ rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res,
+ path_type);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed");
+ goto end;
}
+ /* For each RDI we need CID + PATH resource */
rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list,
&csid_res);
if (rc) {
CAM_ERR(CAM_ISP, "No more free hw mgr resource");
- goto err;
+ goto end;
}
- cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
-
- /*
- * no need to check since we are doing one to one mapping
- * between the csid rdi type and out port rdi type
- */
memset(&csid_acquire, 0, sizeof(csid_acquire));
- csid_acquire.res_id =
- cam_ife_hw_mgr_get_ife_csid_rdi_res_type(
- out_port->res_type);
+ csid_acquire.res_id = path_type;
csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH;
- csid_acquire.cid = cid_res_id;
+ csid_acquire.cid = cid_res->hw_res[0]->res_id;
csid_acquire.in_port = in_port;
csid_acquire.out_port = out_port;
csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE;
+ csid_acquire.node_res = NULL;
- list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid,
- list) {
- if (cid_res->res_id != cid_res_id)
- continue;
+ hw_intf = cid_res->hw_res[0]->hw_intf;
+ rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
+ &csid_acquire, sizeof(csid_acquire));
+ if (rc) {
+ CAM_ERR(CAM_ISP,
+ "CSID Path reserve failed hw=%d rc=%d cid=%d",
+ hw_intf->hw_idx, rc,
+ cid_res->hw_res[0]->res_id);
- for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) {
- if (!cid_res->hw_res[j])
- continue;
-
- csid_acquire.node_res = NULL;
-
- hw_intf = ife_hw_mgr->csid_devices[
- cid_res->hw_res[j]->hw_intf->hw_idx];
- rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv,
- &csid_acquire, sizeof(csid_acquire));
- if (rc) {
- CAM_DBG(CAM_ISP,
- "CSID Path reserve failed hw=%d rc=%d",
- hw_intf->hw_idx, rc);
- continue;
- }
-
- /* RDI does not need Dual ISP. Break */
- break;
- }
-
- if (j == CAM_ISP_HW_SPLIT_MAX &&
- csid_acquire.node_res == NULL) {
- CAM_ERR(CAM_ISP,
- "acquire csid rdi rsrc failed, cid %d",
- cid_res_id);
- goto err;
- }
-
- csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH;
- csid_res->res_id = csid_acquire.res_id;
- csid_res->is_dual_vfe = 0;
- csid_res->hw_res[0] = csid_acquire.node_res;
- csid_res->hw_res[1] = NULL;
- CAM_DBG(CAM_ISP, "acquire res %d",
- csid_acquire.res_id);
- csid_res->parent = cid_res;
- cid_res->child[cid_res->num_children++] =
- csid_res;
-
- /* Done with cid_res_id. Break */
- break;
+ goto put_res;
}
+
+ if (csid_acquire.node_res == NULL) {
+ CAM_ERR(CAM_ISP, "Acquire CSID RDI rsrc failed");
+
+ goto put_res;
+ }
+
+ csid_res->res_type = (enum cam_ife_hw_mgr_res_type)
+ CAM_ISP_RESOURCE_PIX_PATH;
+ csid_res->res_id = csid_acquire.res_id;
+ csid_res->is_dual_vfe = 0;
+ csid_res->hw_res[0] = csid_acquire.node_res;
+ csid_res->hw_res[1] = NULL;
+ CAM_DBG(CAM_ISP, "acquire res %d",
+ csid_acquire.res_id);
+ csid_res->parent = cid_res;
+ cid_res->child[cid_res->num_children++] =
+ csid_res;
+ cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res);
}
return 0;
-err:
+put_res:
+ cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res);
+end:
return rc;
}
@@ -1870,6 +1899,24 @@
*/
if (i == ctx->num_base)
master_base_idx = ctx->base[0].idx;
+ CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx);
+
+ /* Stop the master CSID path first */
+ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
+ master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+
+ /* stop rest of the CSID paths */
+ for (i = 0; i < ctx->num_base; i++) {
+ if (ctx->base[i].idx == master_base_idx)
+ continue;
+ CAM_DBG(CAM_ISP, "Stopping CSID idx %d i %d master %d",
+ ctx->base[i].idx, i, master_base_idx);
+
+ cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
+ ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY);
+ }
+
+ CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx);
/* Stop the master CIDs first */
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
@@ -1877,26 +1924,14 @@
/* stop rest of the CIDs */
for (i = 0; i < ctx->num_base; i++) {
- if (i == master_base_idx)
+ if (ctx->base[i].idx == master_base_idx)
continue;
+ CAM_DBG(CAM_ISP, "Stopping CID idx %d i %d master %d",
+ ctx->base[i].idx, i, master_base_idx);
cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid,
ctx->base[i].idx, csid_halt_type);
}
- /* Stop the master CSID path first */
- cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
- master_base_idx, csid_halt_type);
-
- /* stop rest of the CSID paths */
- for (i = 0; i < ctx->num_base; i++) {
- if (i == master_base_idx)
- continue;
-
- cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid,
- ctx->base[i].idx, csid_halt_type);
- }
-
-
/* Deinit IFE CID */
list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) {
CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__);
@@ -4218,7 +4253,7 @@
/* Create Worker for ife_hw_mgr with 10 tasks */
rc = cam_req_mgr_workq_create("cam_ife_worker", 10,
- &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ);
+ &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0);
if (rc < 0) {
CAM_ERR(CAM_ISP, "Unable to create worker");
goto end;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
index e869e2b..1444911 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c
@@ -70,6 +70,12 @@
hw_entry[num_ent].handle = kmd_buf_info->handle;
hw_entry[num_ent].len = get_base.cmd.used_bytes;
hw_entry[num_ent].offset = kmd_buf_info->offset;
+ CAM_DBG(CAM_ISP,
+ "num_ent=%d handle=0x%x, len=%u, offset=%u",
+ num_ent,
+ hw_entry[num_ent].handle,
+ hw_entry[num_ent].len,
+ hw_entry[num_ent].offset);
kmd_buf_info->used_bytes += get_base.cmd.used_bytes;
kmd_buf_info->offset += get_base.cmd.used_bytes;
@@ -184,6 +190,16 @@
return -EINVAL;
}
+ cmd_update.cmd_type = hw_cmd_type;
+ cmd_update.cmd.cmd_buf_addr = cmd_buf_addr;
+ cmd_update.cmd.size = kmd_buf_remain_size;
+ cmd_update.cmd.used_bytes = 0;
+ cmd_update.data = cmd_update_data;
+ CAM_DBG(CAM_ISP, "cmd_type %u cmd buffer 0x%pK, size %d",
+ cmd_update.cmd_type,
+ cmd_update.cmd.cmd_buf_addr,
+ cmd_update.cmd.size);
+
for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
if (!hw_mgr_res->hw_res[i])
continue;
@@ -193,14 +209,7 @@
res = hw_mgr_res->hw_res[i];
cmd_update.res = res;
- cmd_update.cmd_type = hw_cmd_type;
- cmd_update.cmd.cmd_buf_addr = cmd_buf_addr;
- cmd_update.cmd.size = kmd_buf_remain_size;
- cmd_update.data = cmd_update_data;
- CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d",
- cmd_update.cmd.cmd_buf_addr,
- cmd_update.cmd.size);
rc = res->hw_intf->hw_ops.process_cmd(
res->hw_intf->hw_priv,
cmd_update.cmd_type, &cmd_update,
@@ -280,6 +289,12 @@
hw_entry[num_ent].handle =
cmd_desc[i].mem_handle;
hw_entry[num_ent].offset = cmd_desc[i].offset;
+ CAM_DBG(CAM_ISP,
+ "Meta_Left num_ent=%d handle=0x%x, len=%u, offset=%u",
+ num_ent,
+ hw_entry[num_ent].handle,
+ hw_entry[num_ent].len,
+ hw_entry[num_ent].offset);
if (cmd_meta_data ==
CAM_ISP_PACKET_META_DMI_LEFT)
@@ -295,6 +310,12 @@
hw_entry[num_ent].handle =
cmd_desc[i].mem_handle;
hw_entry[num_ent].offset = cmd_desc[i].offset;
+ CAM_DBG(CAM_ISP,
+ "Meta_Right num_ent=%d handle=0x%x, len=%u, offset=%u",
+ num_ent,
+ hw_entry[num_ent].handle,
+ hw_entry[num_ent].len,
+ hw_entry[num_ent].offset);
if (cmd_meta_data ==
CAM_ISP_PACKET_META_DMI_RIGHT)
@@ -308,7 +329,12 @@
hw_entry[num_ent].handle =
cmd_desc[i].mem_handle;
hw_entry[num_ent].offset = cmd_desc[i].offset;
-
+ CAM_DBG(CAM_ISP,
+ "Meta_Common num_ent=%d handle=0x%x, len=%u, offset=%u",
+ num_ent,
+ hw_entry[num_ent].handle,
+ hw_entry[num_ent].len,
+ hw_entry[num_ent].offset);
if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_COMMON)
hw_entry[num_ent].flags = 0x1;
@@ -647,6 +673,12 @@
prepare->hw_update_entries[num_ent].len = io_cfg_used_bytes;
prepare->hw_update_entries[num_ent].offset =
kmd_buf_info->offset;
+ CAM_DBG(CAM_ISP,
+ "num_ent=%d handle=0x%x, len=%u, offset=%u",
+ num_ent,
+ prepare->hw_update_entries[num_ent].handle,
+ prepare->hw_update_entries[num_ent].len,
+ prepare->hw_update_entries[num_ent].offset);
num_ent++;
kmd_buf_info->used_bytes += io_cfg_used_bytes;
@@ -741,6 +773,12 @@
prepare->hw_update_entries[num_ent].len = reg_update_size;
prepare->hw_update_entries[num_ent].offset =
kmd_buf_info->offset;
+ CAM_DBG(CAM_ISP,
+ "num_ent=%d handle=0x%x, len=%u, offset=%u",
+ num_ent,
+ prepare->hw_update_entries[num_ent].handle,
+ prepare->hw_update_entries[num_ent].len,
+ prepare->hw_update_entries[num_ent].offset);
num_ent++;
kmd_buf_info->used_bytes += reg_update_size;
diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
index 3edae4a..29b9e11 100644
--- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
+++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c
@@ -20,6 +20,7 @@
#include "cam_soc_util.h"
#include "cam_io_util.h"
#include "cam_debug_util.h"
+#include "cam_cpas_api.h"
/* Timeout value in msec */
#define IFE_CSID_TIMEOUT 1000
@@ -286,67 +287,49 @@
}
static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw,
- struct cam_isp_resource_node **res, int32_t vc, uint32_t dt,
- uint32_t res_type)
+ struct cam_isp_resource_node **res, int32_t vc, uint32_t dt)
{
- int rc = 0;
struct cam_ife_csid_cid_data *cid_data;
- uint32_t i = 0, j = 0;
+ uint32_t i = 0;
+ *res = NULL;
+
+ /* Return already reserved CID if the VC/DT matches */
for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) {
if (csid_hw->cid_res[i].res_state >=
CAM_ISP_RESOURCE_STATE_RESERVED) {
cid_data = (struct cam_ife_csid_cid_data *)
csid_hw->cid_res[i].res_priv;
- if (res_type == CAM_ISP_IFE_IN_RES_TPG) {
- if (cid_data->tpg_set) {
- cid_data->cnt++;
- *res = &csid_hw->cid_res[i];
- break;
- }
- } else {
- if (cid_data->vc == vc && cid_data->dt == dt) {
- cid_data->cnt++;
- *res = &csid_hw->cid_res[i];
- break;
- }
+ if (cid_data->vc == vc && cid_data->dt == dt) {
+ cid_data->cnt++;
+ *res = &csid_hw->cid_res[i];
+ return 0;
}
}
}
- if (i == CAM_IFE_CSID_CID_RES_MAX) {
- if (res_type == CAM_ISP_IFE_IN_RES_TPG) {
- CAM_ERR(CAM_ISP, "CSID:%d TPG CID not available",
- csid_hw->hw_intf->hw_idx);
- rc = -EINVAL;
- }
-
- for (j = 0; j < CAM_IFE_CSID_CID_RES_MAX; j++) {
- if (csid_hw->cid_res[j].res_state ==
- CAM_ISP_RESOURCE_STATE_AVAILABLE) {
- cid_data = (struct cam_ife_csid_cid_data *)
- csid_hw->cid_res[j].res_priv;
- cid_data->vc = vc;
- cid_data->dt = dt;
- cid_data->cnt = 1;
- csid_hw->cid_res[j].res_state =
- CAM_ISP_RESOURCE_STATE_RESERVED;
- *res = &csid_hw->cid_res[j];
- CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated",
- csid_hw->hw_intf->hw_idx,
- csid_hw->cid_res[j].res_id);
- break;
- }
- }
-
- if (j == CAM_IFE_CSID_CID_RES_MAX) {
- CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available",
- csid_hw->hw_intf->hw_idx);
- rc = -EINVAL;
+ for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) {
+ if (csid_hw->cid_res[i].res_state ==
+ CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+ cid_data = (struct cam_ife_csid_cid_data *)
+ csid_hw->cid_res[i].res_priv;
+ cid_data->vc = vc;
+ cid_data->dt = dt;
+ cid_data->cnt = 1;
+ csid_hw->cid_res[i].res_state =
+ CAM_ISP_RESOURCE_STATE_RESERVED;
+ *res = &csid_hw->cid_res[i];
+ CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated",
+ csid_hw->hw_intf->hw_idx,
+ csid_hw->cid_res[i].res_id);
+ return 0;
}
}
- return rc;
+ CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available",
+ csid_hw->hw_intf->hw_idx);
+
+ return -EINVAL;
}
@@ -547,6 +530,7 @@
{
int rc = 0;
struct cam_ife_csid_cid_data *cid_data;
+ uint32_t camera_hw_version;
CAM_DBG(CAM_ISP,
"CSID:%d res_sel:0x%x Lane type:%d lane_num:%d dt:%d vc:%d",
@@ -614,12 +598,40 @@
goto end;
}
- if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 &&
- csid_hw->hw_intf->hw_idx != 2) {
+ if (csid_hw->csi2_reserve_cnt == UINT_MAX) {
+ CAM_ERR(CAM_ISP,
+ "CSID%d reserve cnt reached max",
+ csid_hw->hw_intf->hw_idx);
rc = -EINVAL;
goto end;
}
+ rc = cam_cpas_get_cpas_hw_version(&camera_hw_version);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc);
+ goto end;
+ }
+ CAM_DBG(CAM_ISP, "HW version: %d", camera_hw_version);
+
+ switch (camera_hw_version) {
+ case CAM_CPAS_TITAN_NONE:
+ case CAM_CPAS_TITAN_MAX:
+ CAM_ERR(CAM_ISP, "Invalid HW version: %d", camera_hw_version);
+ break;
+ case CAM_CPAS_TITAN_170_V100:
+ case CAM_CPAS_TITAN_170_V110:
+ case CAM_CPAS_TITAN_170_V120:
+ if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 &&
+ csid_hw->hw_intf->hw_idx != 2) {
+ rc = -EINVAL;
+ goto end;
+ }
+ break;
+ default:
+ break;
+ }
+ CAM_DBG(CAM_ISP, "Reserve_cnt %u", csid_hw->csi2_reserve_cnt);
+
if (csid_hw->csi2_reserve_cnt) {
/* current configure res type should match requested res type */
if (csid_hw->res_type != cid_reserv->in_port->res_type) {
@@ -652,12 +664,53 @@
}
}
+ switch (cid_reserv->res_id) {
+ case CAM_IFE_PIX_PATH_RES_IPP:
+ if (csid_hw->ipp_res.res_state !=
+ CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+ CAM_DBG(CAM_ISP,
+ "CSID:%d IPP resource not available",
+ csid_hw->hw_intf->hw_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+ break;
+ case CAM_IFE_PIX_PATH_RES_RDI_0:
+ case CAM_IFE_PIX_PATH_RES_RDI_1:
+ case CAM_IFE_PIX_PATH_RES_RDI_2:
+ case CAM_IFE_PIX_PATH_RES_RDI_3:
+ if (csid_hw->rdi_res[cid_reserv->res_id].res_state !=
+ CAM_ISP_RESOURCE_STATE_AVAILABLE) {
+ CAM_ERR(CAM_ISP,
+ "CSID:%d RDI:%d resource not available",
+ csid_hw->hw_intf->hw_idx,
+ cid_reserv->res_id);
+ rc = -EINVAL;
+ goto end;
+ }
+ break;
+ default:
+ CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path",
+ csid_hw->hw_intf->hw_idx);
+ rc = -EINVAL;
+ goto end;
+ }
+
+ rc = cam_ife_csid_cid_get(csid_hw,
+ &cid_reserv->node_res,
+ cid_reserv->in_port->vc,
+ cid_reserv->in_port->dt);
+ if (rc) {
+ CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_type %d",
+ csid_hw->hw_intf->hw_idx,
+ cid_reserv->in_port->res_type);
+ goto end;
+ }
+ cid_data = (struct cam_ife_csid_cid_data *)
+ cid_reserv->node_res->res_priv;
+
if (!csid_hw->csi2_reserve_cnt) {
csid_hw->res_type = cid_reserv->in_port->res_type;
- /* Take the first CID resource*/
- csid_hw->cid_res[0].res_state = CAM_ISP_RESOURCE_STATE_RESERVED;
- cid_data = (struct cam_ife_csid_cid_data *)
- csid_hw->cid_res[0].res_priv;
csid_hw->csi2_rx_cfg.lane_cfg =
cid_reserv->in_port->lane_cfg;
@@ -699,71 +752,13 @@
csid_hw->csi2_rx_cfg.phy_sel =
(cid_reserv->in_port->res_type & 0xFF) - 1;
}
-
- cid_data->vc = cid_reserv->in_port->vc;
- cid_data->dt = cid_reserv->in_port->dt;
- cid_data->cnt = 1;
- cid_reserv->node_res = &csid_hw->cid_res[0];
- csid_hw->csi2_reserve_cnt++;
-
- CAM_DBG(CAM_ISP,
- "CSID:%d CID :%d resource acquired successfully",
- csid_hw->hw_intf->hw_idx,
- cid_reserv->node_res->res_id);
- } else {
- switch (cid_reserv->res_id) {
- case CAM_IFE_PIX_PATH_RES_IPP:
- if (csid_hw->ipp_res.res_state !=
- CAM_ISP_RESOURCE_STATE_AVAILABLE) {
- CAM_DBG(CAM_ISP,
- "CSID:%d IPP resource not available",
- csid_hw->hw_intf->hw_idx);
- rc = -EINVAL;
- goto end;
- }
- break;
- case CAM_IFE_PIX_PATH_RES_RDI_0:
- case CAM_IFE_PIX_PATH_RES_RDI_1:
- case CAM_IFE_PIX_PATH_RES_RDI_2:
- case CAM_IFE_PIX_PATH_RES_RDI_3:
- if (csid_hw->rdi_res[cid_reserv->res_id].res_state !=
- CAM_ISP_RESOURCE_STATE_AVAILABLE) {
- CAM_DBG(CAM_ISP,
- "CSID:%d RDI:%d resource not available",
- csid_hw->hw_intf->hw_idx,
- cid_reserv->res_id);
- rc = -EINVAL;
- goto end;
- }
- break;
- default:
- CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path",
- csid_hw->hw_intf->hw_idx);
- rc = -EINVAL;
- goto end;
- }
-
- rc = cam_ife_csid_cid_get(csid_hw,
- &cid_reserv->node_res,
- cid_reserv->in_port->vc,
- cid_reserv->in_port->dt,
- cid_reserv->in_port->res_type);
- /* if success then increment the reserve count */
- if (!rc) {
- if (csid_hw->csi2_reserve_cnt == UINT_MAX) {
- CAM_ERR(CAM_ISP,
- "CSID%d reserve cnt reached max",
- csid_hw->hw_intf->hw_idx);
- rc = -EINVAL;
- } else {
- csid_hw->csi2_reserve_cnt++;
- CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired",
- csid_hw->hw_intf->hw_idx,
- cid_reserv->node_res->res_id);
- }
- }
}
+ csid_hw->csi2_reserve_cnt++;
+ CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired",
+ csid_hw->hw_intf->hw_idx,
+ cid_reserv->node_res->res_id);
+
end:
return rc;
}
@@ -2415,12 +2410,24 @@
return -EINVAL;
}
csid_stop = (struct cam_csid_hw_stop_args *) stop_args;
+
+ if (!csid_stop->num_res) {
+ CAM_ERR(CAM_ISP, "CSID: Invalid args");
+ return -EINVAL;
+ }
+
csid_hw_info = (struct cam_hw_info *)hw_priv;
csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info;
+ CAM_DBG(CAM_ISP, "CSID:%d num_res %d",
+ csid_hw->hw_intf->hw_idx,
+ csid_stop->num_res);
/* Stop the resource first */
for (i = 0; i < csid_stop->num_res; i++) {
res = csid_stop->node_res[i];
+ CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d",
+ csid_hw->hw_intf->hw_idx,
+ res->res_type, res->res_id);
switch (res->res_type) {
case CAM_ISP_RESOURCE_CID:
if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG)
@@ -2777,6 +2784,7 @@
{
int rc = -EINVAL;
uint32_t i;
+ uint32_t num_paths;
struct cam_ife_csid_path_cfg *path_data;
struct cam_ife_csid_cid_data *cid_data;
struct cam_hw_info *csid_hw_info;
@@ -2828,8 +2836,10 @@
ife_csid_hw->hw_intf->hw_ops.write = cam_ife_csid_write;
ife_csid_hw->hw_intf->hw_ops.process_cmd = cam_ife_csid_process_cmd;
- /*Initialize the CID resoure */
- for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) {
+ num_paths = ife_csid_hw->csid_info->csid_reg->cmn_reg->no_pix +
+ ife_csid_hw->csid_info->csid_reg->cmn_reg->no_rdis;
+ /* Initialize the CID resource */
+ for (i = 0; i < num_paths; i++) {
ife_csid_hw->cid_res[i].res_type = CAM_ISP_RESOURCE_CID;
ife_csid_hw->cid_res[i].res_id = i;
ife_csid_hw->cid_res[i].res_state =
diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
index 97d076a..fdeee54 100644
--- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c
@@ -1171,7 +1171,7 @@
"jpeg_command_queue",
CAM_JPEG_WORKQ_NUM_TASK,
&g_jpeg_hw_mgr.work_process_frame,
- CRM_WORKQ_USAGE_NON_IRQ);
+ CRM_WORKQ_USAGE_NON_IRQ, 0);
if (rc) {
CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc);
goto work_process_frame_failed;
@@ -1181,7 +1181,7 @@
"jpeg_message_queue",
CAM_JPEG_WORKQ_NUM_TASK,
&g_jpeg_hw_mgr.work_process_irq_cb,
- CRM_WORKQ_USAGE_IRQ);
+ CRM_WORKQ_USAGE_IRQ, 0);
if (rc) {
CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc);
goto work_process_irq_cb_failed;
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
index a60661e..0f34c9f 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c
@@ -989,7 +989,8 @@
CAM_DBG(CAM_LRME, "Create submit workq for %s", buf);
rc = cam_req_mgr_workq_create(buf,
CAM_LRME_WORKQ_NUM_TASK,
- &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ);
+ &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ,
+ 0);
if (rc) {
CAM_ERR(CAM_LRME,
"Unable to create a worker, rc=%d", rc);
diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
index da42c84..ec392f5 100644
--- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
+++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -28,8 +28,6 @@
#include "cam_mem_mgr_api.h"
#include "cam_smmu_api.h"
-#define CAM_LRME_HW_WORKQ_NUM_TASK 30
-
static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core,
struct cam_hw_info *lrme_hw)
{
@@ -122,7 +120,7 @@
rc = cam_req_mgr_workq_create("cam_lrme_hw_worker",
CAM_LRME_HW_WORKQ_NUM_TASK,
- &lrme_core->work, CRM_WORKQ_USAGE_IRQ);
+ &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0);
if (rc) {
CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc);
goto free_memory;
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
index 4602d6c..060aaf2 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c
@@ -2324,6 +2324,7 @@
int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info)
{
int rc = 0;
+ int wq_flag = 0;
char buf[128];
struct cam_create_dev_hdl root_dev;
struct cam_req_mgr_core_session *cam_session;
@@ -2394,8 +2395,9 @@
/* Create worker for current link */
snprintf(buf, sizeof(buf), "%x-%x",
link_info->session_hdl, link->link_hdl);
+ wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL;
rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS,
- &link->workq, CRM_WORKQ_USAGE_NON_IRQ);
+ &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag);
if (rc < 0) {
CAM_ERR(CAM_CRM, "FATAL: unable to create worker");
__cam_req_mgr_destroy_link_info(link);
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
index 066efd6..3798ef8 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c
@@ -178,9 +178,10 @@
}
int cam_req_mgr_workq_create(char *name, int32_t num_tasks,
- struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq)
+ struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq,
+ int flags)
{
- int32_t i;
+ int32_t i, wq_flags = 0, max_active_tasks = 0;
struct crm_workq_task *task;
struct cam_req_mgr_core_workq *crm_workq = NULL;
char buf[128] = "crm_workq-";
@@ -192,10 +193,17 @@
if (crm_workq == NULL)
return -ENOMEM;
+ wq_flags |= WQ_UNBOUND;
+ if (flags & CAM_WORKQ_FLAG_HIGH_PRIORITY)
+ wq_flags |= WQ_HIGHPRI;
+
+ if (flags & CAM_WORKQ_FLAG_SERIAL)
+ max_active_tasks = 1;
+
strlcat(buf, name, sizeof(buf));
CAM_DBG(CAM_CRM, "create workque crm_workq-%s", name);
crm_workq->job = alloc_workqueue(buf,
- WQ_HIGHPRI | WQ_UNBOUND, 0, NULL);
+ wq_flags, max_active_tasks, NULL);
if (!crm_workq->job) {
kfree(crm_workq);
return -ENOMEM;
diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h
index eb3b804..af76ae46 100644
--- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h
+++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, 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
@@ -23,6 +23,15 @@
#include "cam_req_mgr_core.h"
+/* Flag to create a high priority workq */
+#define CAM_WORKQ_FLAG_HIGH_PRIORITY (1 << 0)
+
+/* This flag ensures only one task from a given
+ * workq will execute at any given point on any
+ * given CPU.
+ */
+#define CAM_WORKQ_FLAG_SERIAL (1 << 1)
+
/* Task priorities, lower the number higher the priority*/
enum crm_task_priority {
CRM_TASK_PRIORITY_0,
@@ -101,11 +110,14 @@
* @num_task : Num_tasks to be allocated for workq
* @workq : Double pointer worker
* @in_irq : Set to one if workq might be used in irq context
+ * @flags : Bitwise OR of Flags for workq behavior.
+ * e.g. CAM_REQ_MGR_WORKQ_HIGH_PRIORITY | CAM_REQ_MGR_WORKQ_SERIAL
* This function will allocate and create workqueue and pass
* the workq pointer to caller.
*/
int cam_req_mgr_workq_create(char *name, int32_t num_tasks,
- struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq);
+ struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq,
+ int flags);
/**
* cam_req_mgr_workq_destroy()
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
index a34d70c..da8ff21 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
@@ -53,6 +53,7 @@
free_power_settings:
kfree(power_info->power_setting);
+ power_info->power_setting = NULL;
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
index 96fdfeb..733c9e8 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -252,6 +252,8 @@
a_ctrl->io_master_info.cci_client = NULL;
kfree(power_info->power_setting);
kfree(power_info->power_down_setting);
+ power_info->power_setting = NULL;
+ power_info->power_down_setting = NULL;
kfree(a_ctrl->soc_info.soc_private);
kfree(a_ctrl->i2c_data.per_frame);
a_ctrl->i2c_data.per_frame = NULL;
@@ -284,6 +286,8 @@
kfree(power_info->power_setting);
kfree(power_info->power_down_setting);
kfree(a_ctrl->soc_info.soc_private);
+ power_info->power_setting = NULL;
+ power_info->power_down_setting = NULL;
a_ctrl->soc_info.soc_private = NULL;
kfree(a_ctrl);
return rc;
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
index 9b74826..f0efd4c 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c
@@ -191,25 +191,11 @@
int cam_flash_off(struct cam_flash_ctrl *flash_ctrl)
{
- int i = 0;
-
if (!flash_ctrl) {
CAM_ERR(CAM_FLASH, "Flash control Null");
return -EINVAL;
}
- for (i = 0; i < flash_ctrl->flash_num_sources; i++)
- if (flash_ctrl->flash_trigger[i])
- cam_res_mgr_led_trigger_event(
- flash_ctrl->flash_trigger[i],
- LED_OFF);
-
- for (i = 0; i < flash_ctrl->torch_num_sources; i++)
- if (flash_ctrl->torch_trigger[i])
- cam_res_mgr_led_trigger_event(
- flash_ctrl->torch_trigger[i],
- LED_OFF);
-
if (flash_ctrl->switch_trigger)
cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger,
LED_SWITCH_OFF);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
index dfcb9fc..6f77e0e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c
@@ -55,6 +55,7 @@
free_power_settings:
kfree(power_info->power_setting);
+ power_info->power_setting = NULL;
return rc;
}
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
index d742acf..5d16a4e 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -240,6 +240,8 @@
kfree(power_info->power_setting);
kfree(power_info->power_down_setting);
+ power_info->power_setting = NULL;
+ power_info->power_down_setting = NULL;
kfree(o_ctrl->soc_info.soc_private);
kfree(o_ctrl);
@@ -341,6 +343,8 @@
kfree(power_info->power_setting);
kfree(power_info->power_down_setting);
+ power_info->power_setting = NULL;
+ power_info->power_down_setting = NULL;
kfree(o_ctrl->soc_info.soc_private);
kfree(o_ctrl->io_master_info.cci_client);
kfree(o_ctrl);
diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
index 2133932..6fe051a 100644
--- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
+++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c
@@ -599,7 +599,8 @@
} else {
CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d",
cmd->handle_type);
- return -EINVAL;
+ rc = -EINVAL;
+ goto release_mutex;
}
pu = power_info->power_setting;
@@ -653,7 +654,7 @@
}
CAM_INFO(CAM_SENSOR,
- "Probe Succees,slot:%d,slave_addr:0x%x,sensor_id:0x%x",
+ "Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x",
s_ctrl->soc_info.index,
s_ctrl->sensordata->slave_info.sensor_slave_addr,
s_ctrl->sensordata->slave_info.sensor_id);
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
index 517b7df..55896f4 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c
@@ -46,6 +46,7 @@
}
*sync_obj = idx;
+ CAM_DBG(CAM_SYNC, "sync_obj: %i", *sync_obj);
spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
return rc;
@@ -170,21 +171,24 @@
INIT_LIST_HEAD(&sync_list);
if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) {
- CAM_ERR(CAM_SYNC, "Error: Out of range sync obj");
+ CAM_ERR(CAM_SYNC, "Error: Out of range sync obj (0 <= %d < %d)",
+ sync_obj, CAM_SYNC_MAX_OBJS);
return -EINVAL;
}
row = sync_dev->sync_table + sync_obj;
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
if (row->state == CAM_SYNC_STATE_INVALID) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
CAM_ERR(CAM_SYNC,
"Error: accessing an uninitialized sync obj = %d",
sync_obj);
return -EINVAL;
}
- spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]);
if (row->type == CAM_SYNC_TYPE_GROUP) {
spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]);
- CAM_ERR(CAM_SYNC, "Error: Signaling a GROUP sync object = %d",
+ CAM_ERR(CAM_SYNC,
+ "Error: Signaling a GROUP sync object = %d",
sync_obj);
return -EINVAL;
}
@@ -368,6 +372,7 @@
int cam_sync_destroy(int32_t sync_obj)
{
+ CAM_DBG(CAM_SYNC, "sync_obj: %i", sync_obj);
return cam_sync_deinit_object(sync_dev->sync_table, sync_obj);
}
diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
index ed69829..43bce51 100644
--- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
+++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -51,8 +51,9 @@
init_completion(&row->signaled);
INIT_LIST_HEAD(&row->callback_list);
INIT_LIST_HEAD(&row->user_payload_list);
- CAM_DBG(CAM_SYNC, "Sync object Initialised: sync_id:%u row_state:%u ",
- row->sync_id, row->state);
+ CAM_DBG(CAM_SYNC,
+ "row name:%s sync_id:%i [idx:%u] row_state:%u ",
+ row->name, row->sync_id, idx, row->state);
return 0;
}
@@ -74,9 +75,11 @@
* counts of error, active and success states of all children objects
*/
for (i = 0; i < num_objs; i++) {
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
child_row = table + sync_objs[i];
switch (child_row->state) {
case CAM_SYNC_STATE_SIGNALED_ERROR:
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
return CAM_SYNC_STATE_SIGNALED_ERROR;
case CAM_SYNC_STATE_SIGNALED_SUCCESS:
success_count++;
@@ -87,8 +90,10 @@
default:
CAM_ERR(CAM_SYNC,
"Invalid state of child object during merge");
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
return CAM_SYNC_STATE_SIGNALED_ERROR;
}
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
}
if (active_count)
@@ -209,12 +214,16 @@
if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS)
return -EINVAL;
+ CAM_DBG(CAM_SYNC,
+ "row name:%s sync_id:%i [idx:%u] row_state:%u",
+ row->name, row->sync_id, idx, row->state);
+
spin_lock_bh(&sync_dev->row_spinlocks[idx]);
if (row->state == CAM_SYNC_STATE_INVALID) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
CAM_ERR(CAM_SYNC,
"Error: accessing an uninitialized sync obj: idx = %d",
idx);
- spin_unlock_bh(&sync_dev->row_spinlocks[idx]);
return -EINVAL;
}
row->state = CAM_SYNC_STATE_INVALID;
@@ -252,9 +261,9 @@
spin_lock_bh(&sync_dev->row_spinlocks[child_info->sync_id]);
if (child_row->state == CAM_SYNC_STATE_INVALID) {
+ list_del_init(&child_info->list);
spin_unlock_bh(&sync_dev->row_spinlocks[
child_info->sync_id]);
- list_del_init(&child_info->list);
kfree(child_info);
continue;
}
@@ -262,9 +271,8 @@
cam_sync_util_cleanup_parents_list(child_row,
SYNC_LIST_CLEAN_ONE, idx);
- spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]);
-
list_del_init(&child_info->list);
+ spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]);
kfree(child_info);
}
@@ -277,9 +285,9 @@
spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
if (parent_row->state == CAM_SYNC_STATE_INVALID) {
+ list_del_init(&parent_info->list);
spin_unlock_bh(&sync_dev->row_spinlocks[
parent_info->sync_id]);
- list_del_init(&parent_info->list);
kfree(parent_info);
continue;
}
@@ -287,9 +295,8 @@
cam_sync_util_cleanup_children_list(parent_row,
SYNC_LIST_CLEAN_ONE, idx);
- spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
-
list_del_init(&parent_info->list);
+ spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]);
kfree(parent_info);
}
diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
index 30ab075..db2629d 100644
--- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
+++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 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
@@ -171,6 +171,24 @@
patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset,
patch_desc[i].src_buf_hdl, patch_desc[i].src_offset);
+ if (patch_desc[i].src_offset >= src_buf_size) {
+ CAM_ERR_RATE_LIMIT(CAM_UTIL,
+ "Inval src offset:0x%x src len:0x%x reqid:%lld",
+ patch_desc[i].src_offset,
+ (unsigned int)src_buf_size,
+ packet->header.request_id);
+ return -EINVAL;
+ }
+
+ if (patch_desc[i].dst_offset >= dst_buf_len) {
+ CAM_ERR_RATE_LIMIT(CAM_UTIL,
+ "Inval dst offset:0x%x dst len:0x%x reqid:%lld",
+ patch_desc[i].dst_offset,
+ (unsigned int)dst_buf_len,
+ packet->header.request_id);
+ return -EINVAL;
+ }
+
dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr +
patch_desc[i].dst_offset);
temp += patch_desc[i].src_offset;
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 7d37d7e..0811efb 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
@@ -32,6 +32,8 @@
#define MSM_JPEG_NAME "jpeg"
#define DEV_NAME_LEN 10
+static char devname[DEV_NAME_LEN];
+
static int msm_jpeg_open(struct inode *inode, struct file *filp)
{
int rc = 0;
@@ -159,7 +161,6 @@
struct msm_jpeg_device *msm_jpeg_device_p;
const struct of_device_id *device_id;
const struct msm_jpeg_priv_data *priv_data;
- char devname[DEV_NAME_LEN];
msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC);
if (!msm_jpeg_device_p) {
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index d77ea21..b878971 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -6724,6 +6724,7 @@
struct msm_vidc_buffer *temp;
bool found = false;
int i = 0;
+ u32 planes[VIDEO_MAX_PLANES] = {0};
mutex_lock(&inst->flush_lock);
mutex_lock(&inst->registeredbufs.lock);
@@ -6737,6 +6738,10 @@
}
}
if (found) {
+ /* save device_addr */
+ for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++)
+ planes[i] = mbuf->smem[i].device_addr;
+
/* send RBR event to client */
msm_vidc_queue_rbr_event(inst,
mbuf->vvb.vb2_buf.planes[0].m.fd,
@@ -6755,6 +6760,7 @@
if (!mbuf->smem[0].refcount) {
list_del(&mbuf->list);
kref_put_mbuf(mbuf);
+ mbuf = NULL;
}
} else {
print_vidc_buffer(VIDC_ERR, "mbuf not found", inst, mbuf);
@@ -6772,8 +6778,8 @@
*/
found = false;
list_for_each_entry(temp, &inst->registeredbufs.list, list) {
- if (msm_comm_compare_vb2_plane(inst, mbuf,
- &temp->vvb.vb2_buf, 0)) {
+ if (msm_comm_compare_device_plane(temp, planes, 0)) {
+ mbuf = temp;
found = true;
break;
}
@@ -6793,9 +6799,11 @@
/* don't queue the buffer */
found = false;
}
- /* clear DEFERRED flag, if any, as the buffer is going to be queued */
- if (found)
+ /* clear required flags as the buffer is going to be queued */
+ if (found) {
mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED;
+ mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING;
+ }
unlock:
mutex_unlock(&inst->registeredbufs.lock);
diff --git a/drivers/net/wireless/cnss2/debug.h b/drivers/net/wireless/cnss2/debug.h
index f31fdfe..bf2e755 100644
--- a/drivers/net/wireless/cnss2/debug.h
+++ b/drivers/net/wireless/cnss2/debug.h
@@ -26,23 +26,23 @@
} while (0)
#define cnss_pr_err(_fmt, ...) do { \
- pr_err("cnss: " _fmt, ##__VA_ARGS__); \
- cnss_ipc_log_string("ERR: " _fmt, ##__VA_ARGS__); \
+ printk("%scnss: " _fmt, KERN_ERR, ##__VA_ARGS__); \
+ cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
} while (0)
#define cnss_pr_warn(_fmt, ...) do { \
- pr_warn("cnss: " _fmt, ##__VA_ARGS__); \
- cnss_ipc_log_string("WRN: " _fmt, ##__VA_ARGS__); \
+ printk("%scnss: " _fmt, KERN_WARNING, ##__VA_ARGS__); \
+ cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
} while (0)
#define cnss_pr_info(_fmt, ...) do { \
- pr_info("cnss: " _fmt, ##__VA_ARGS__); \
- cnss_ipc_log_string("INF: " _fmt, ##__VA_ARGS__); \
+ printk("%scnss: " _fmt, KERN_INFO, ##__VA_ARGS__); \
+ cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
} while (0)
#define cnss_pr_dbg(_fmt, ...) do { \
- pr_debug("cnss: " _fmt, ##__VA_ARGS__); \
- cnss_ipc_log_string("DBG: " _fmt, ##__VA_ARGS__); \
+ printk("%scnss: " _fmt, KERN_DEBUG, ##__VA_ARGS__); \
+ cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\
} while (0)
#ifdef CONFIG_CNSS2_DEBUG
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index 2c29538..5d8b12b 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -2788,27 +2788,21 @@
return -GSI_STATUS_UNSUPPORTED_OP;
}
+ spin_lock_irqsave(&gsi_ctx->slock, flags);
if (curr == GSI_CHAN_MODE_CALLBACK &&
mode == GSI_CHAN_MODE_POLL) {
- spin_lock_irqsave(&gsi_ctx->slock, flags);
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0);
- spin_unlock_irqrestore(&gsi_ctx->slock, flags);
- spin_lock_irqsave(&ctx->ring.slock, flags);
atomic_set(&ctx->poll_mode, mode);
- spin_unlock_irqrestore(&ctx->ring.slock, flags);
ctx->stats.callback_to_poll++;
}
if (curr == GSI_CHAN_MODE_POLL &&
mode == GSI_CHAN_MODE_CALLBACK) {
- spin_lock_irqsave(&ctx->ring.slock, flags);
atomic_set(&ctx->poll_mode, mode);
- spin_unlock_irqrestore(&ctx->ring.slock, flags);
- spin_lock_irqsave(&gsi_ctx->slock, flags);
__gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0);
- spin_unlock_irqrestore(&gsi_ctx->slock, flags);
ctx->stats.poll_to_callback++;
}
+ spin_unlock_irqrestore(&gsi_ctx->slock, flags);
return GSI_STATUS_SUCCESS;
}
diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c
index 6e54fbf..05a8c66 100644
--- a/drivers/platform/msm/sps/sps.c
+++ b/drivers/platform/msm/sps/sps.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2018, 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
@@ -1020,8 +1020,6 @@
"sps:%s:BAMs are still registered", __func__);
sps_map_de_init();
-
- kfree(sps);
}
sps_mem_de_init();
@@ -3006,6 +3004,7 @@
.name = SPS_DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = msm_sps_match,
+ .suppress_bind_attrs = true,
},
.remove = msm_sps_remove,
};
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index d1b6bea..41b8d3c 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -452,13 +452,11 @@
}
#define MIN_FIFO_FULL_TIME_MS 12000
-static int process_rt_fifo_data(struct qpnp_qg *chip,
- bool update_vbat_low, bool update_smb)
+static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb)
{
int rc = 0;
ktime_t now = ktime_get();
s64 time_delta;
- u8 fifo_length;
/*
* Reject the FIFO read event if there are back-to-back requests
@@ -467,11 +465,10 @@
*/
time_delta = ktime_ms_delta(now, chip->last_user_update_time);
- qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_vbat_low=%d update_smb=%d\n",
- time_delta, update_vbat_low, update_smb);
+ qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_smb=%d\n",
+ time_delta, update_smb);
- if (time_delta > MIN_FIFO_FULL_TIME_MS || update_vbat_low
- || update_smb) {
+ if (time_delta > MIN_FIFO_FULL_TIME_MS || update_smb) {
rc = qg_master_hold(chip, true);
if (rc < 0) {
pr_err("Failed to hold master, rc=%d\n", rc);
@@ -484,20 +481,6 @@
goto done;
}
- if (update_vbat_low) {
- /* change FIFO length */
- fifo_length = chip->vbat_low ?
- chip->dt.s2_vbat_low_fifo_length :
- chip->dt.s2_fifo_length;
- rc = qg_update_fifo_length(chip, fifo_length);
- if (rc < 0)
- goto done;
-
- qg_dbg(chip, QG_DEBUG_STATUS,
- "FIFO length updated to %d vbat_low=%d\n",
- fifo_length, chip->vbat_low);
- }
-
if (update_smb) {
rc = qg_masked_write(chip, chip->qg_base +
QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT,
@@ -539,60 +522,67 @@
static int qg_vbat_low_wa(struct qpnp_qg *chip)
{
int rc, i, temp = 0;
- u32 vbat_low_uv = 0;
+ u32 vbat_low_uv = 0, fifo_length = 0;
- rc = qg_get_battery_temp(chip, &temp);
- if (rc < 0) {
- pr_err("Failed to read batt_temp rc=%d\n", rc);
- temp = 250;
- }
+ if ((chip->wa_flags & QG_VBAT_LOW_WA) && chip->vbat_low) {
+ rc = qg_get_battery_temp(chip, &temp);
+ if (rc < 0) {
+ pr_err("Failed to read batt_temp rc=%d\n", rc);
+ temp = 250;
+ }
- vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ?
- chip->dt.vbatt_low_cold_mv :
- chip->dt.vbatt_low_mv);
- vbat_low_uv += VBAT_LOW_HYST_UV;
-
- if (!(chip->wa_flags & QG_VBAT_LOW_WA) || !chip->vbat_low)
- return 0;
-
- /*
- * PMI632 1.0 does not generate a falling VBAT_LOW IRQ.
- * To exit from VBAT_LOW config, check if any of the FIFO
- * averages is > vbat_low threshold and reconfigure the
- * FIFO length to normal.
- */
- for (i = 0; i < chip->kdata.fifo_length; i++) {
- if (chip->kdata.fifo[i].v > vbat_low_uv) {
- rc = qg_master_hold(chip, true);
- if (rc < 0) {
- pr_err("Failed to hold master, rc=%d\n", rc);
- goto done;
- }
- rc = qg_update_fifo_length(chip,
- chip->dt.s2_fifo_length);
- if (rc < 0)
- goto done;
-
- rc = qg_master_hold(chip, false);
- if (rc < 0) {
- pr_err("Failed to release master, rc=%d\n", rc);
- goto done;
- }
- /* FIFOs restarted */
- chip->last_fifo_update_time = ktime_get();
-
- chip->vbat_low = false;
- pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n",
+ vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ?
+ chip->dt.vbatt_low_cold_mv :
+ chip->dt.vbatt_low_mv);
+ vbat_low_uv += VBAT_LOW_HYST_UV;
+ /*
+ * PMI632 1.0 does not generate a falling VBAT_LOW IRQ.
+ * To exit from VBAT_LOW config, check if any of the FIFO
+ * averages is > vbat_low threshold and reconfigure the
+ * FIFO length to normal.
+ */
+ for (i = 0; i < chip->kdata.fifo_length; i++) {
+ if (chip->kdata.fifo[i].v > vbat_low_uv) {
+ chip->vbat_low = false;
+ pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n",
chip->kdata.fifo[i].v, vbat_low_uv,
chip->dt.s2_fifo_length);
- break;
+ break;
+ }
}
}
- return 0;
+ rc = get_fifo_length(chip, &fifo_length, false);
+ if (rc < 0) {
+ pr_err("Failed to get FIFO length, rc=%d\n", rc);
+ return rc;
+ }
+ if (chip->vbat_low && fifo_length == chip->dt.s2_vbat_low_fifo_length)
+ return 0;
+
+ if (!chip->vbat_low && fifo_length == chip->dt.s2_fifo_length)
+ return 0;
+
+ rc = qg_master_hold(chip, true);
+ if (rc < 0) {
+ pr_err("Failed to hold master, rc=%d\n", rc);
+ goto done;
+ }
+
+ fifo_length = chip->vbat_low ? chip->dt.s2_vbat_low_fifo_length :
+ chip->dt.s2_fifo_length;
+
+ rc = qg_update_fifo_length(chip, fifo_length);
+ if (rc < 0)
+ goto done;
+
+ qg_dbg(chip, QG_DEBUG_STATUS, "FIFO length updated to %d vbat_low=%d\n",
+ fifo_length, chip->vbat_low);
done:
qg_master_hold(chip, false);
+ /* FIFOs restarted */
+ chip->last_fifo_update_time = ktime_get();
return rc;
}
@@ -1174,10 +1164,6 @@
chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT);
- rc = process_rt_fifo_data(chip, true, false);
- if (rc < 0)
- pr_err("Failed to process RT FIFO data, rc=%d\n", rc);
-
qg_dbg(chip, QG_DEBUG_IRQ, "VBAT_LOW = %d\n", chip->vbat_low);
done:
mutex_unlock(&chip->data_lock);
@@ -1950,7 +1936,7 @@
if (!chip->dt.qg_ext_sense)
update_smb = true;
- rc = process_rt_fifo_data(chip, false, update_smb);
+ rc = process_rt_fifo_data(chip, update_smb);
if (rc < 0)
pr_err("Failed to process RT FIFO data, rc=%d\n", rc);
@@ -3474,10 +3460,10 @@
return rc;
}
- chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
- chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
/* Clear suspend data as there has been a GOOD OCV */
memset(&chip->kdata, 0, sizeof(chip->kdata));
+ chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
+ chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
chip->suspend_data = false;
qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n",
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 6685f05..2c0c0ed 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -374,7 +374,6 @@
struct rx_msg *rx_ext_msg;
u32 received_pdos[PD_MAX_DATA_OBJ];
- u32 received_ado;
u16 src_cap_id;
u8 selected_pdo;
u8 requested_pdo;
@@ -443,6 +442,7 @@
u8 src_cap_ext_db[PD_SRC_CAP_EXT_DB_LEN];
bool send_get_pps_status;
u32 pps_status_db;
+ bool send_get_status;
u8 status_db[PD_STATUS_DB_LEN];
bool send_get_battery_cap;
u8 get_battery_cap_db;
@@ -2252,7 +2252,7 @@
pd->send_pr_swap = false;
ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
if (ret) {
- dev_err(&pd->dev, "Error sending PR Swap\n");
+ usbpd_err(&pd->dev, "Error sending PR Swap\n");
usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
break;
}
@@ -2263,7 +2263,7 @@
pd->send_dr_swap = false;
ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
if (ret) {
- dev_err(&pd->dev, "Error sending DR Swap\n");
+ usbpd_err(&pd->dev, "Error sending DR Swap\n");
usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET);
break;
}
@@ -2552,8 +2552,7 @@
ret = pd_send_msg(pd, MSG_GET_SOURCE_CAP_EXTENDED, NULL,
0, SOP_MSG);
if (ret) {
- dev_err(&pd->dev,
- "Error sending get_src_cap_ext\n");
+ usbpd_err(&pd->dev, "Error sending get_src_cap_ext\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
@@ -2572,8 +2571,7 @@
ret = pd_send_msg(pd, MSG_GET_PPS_STATUS, NULL,
0, SOP_MSG);
if (ret) {
- dev_err(&pd->dev,
- "Error sending get_pps_status\n");
+ usbpd_err(&pd->dev, "Error sending get_pps_status\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
@@ -2588,23 +2586,32 @@
sizeof(pd->pps_status_db));
complete(&pd->is_ready);
} else if (IS_DATA(rx_msg, MSG_ALERT)) {
- if (rx_msg->data_len != sizeof(pd->received_ado)) {
+ u32 ado;
+
+ if (rx_msg->data_len != sizeof(ado)) {
usbpd_err(&pd->dev, "Invalid ado\n");
break;
}
- memcpy(&pd->received_ado, rx_msg->payload,
- sizeof(pd->received_ado));
- ret = pd_send_msg(pd, MSG_GET_STATUS, NULL,
- 0, SOP_MSG);
+ memcpy(&ado, rx_msg->payload, sizeof(ado));
+ usbpd_dbg(&pd->dev, "Received Alert 0x%08x\n", ado);
+
+ /*
+ * Don't send Get_Status right away so we can coalesce
+ * multiple Alerts. 150ms should be enough to not get
+ * in the way of any other AMS that might happen.
+ */
+ pd->send_get_status = true;
+ kick_sm(pd, 150);
+ } else if (pd->send_get_status && is_sink_tx_ok(pd)) {
+ pd->send_get_status = false;
+ ret = pd_send_msg(pd, MSG_GET_STATUS, NULL, 0, SOP_MSG);
if (ret) {
- dev_err(&pd->dev,
- "Error sending get_status\n");
+ usbpd_err(&pd->dev, "Error sending get_status\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
kick_sm(pd, SENDER_RESPONSE_TIME);
- } else if (rx_msg &&
- IS_EXT(rx_msg, MSG_STATUS)) {
+ } else if (rx_msg && IS_EXT(rx_msg, MSG_STATUS)) {
if (rx_msg->data_len != PD_STATUS_DB_LEN) {
usbpd_err(&pd->dev, "Invalid status db\n");
break;
@@ -2617,8 +2624,7 @@
ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_CAP,
&pd->get_battery_cap_db, 1, SOP_MSG);
if (ret) {
- dev_err(&pd->dev,
- "Error sending get_battery_cap\n");
+ usbpd_err(&pd->dev, "Error sending get_battery_cap\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
@@ -2637,8 +2643,7 @@
ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_STATUS,
&pd->get_battery_status_db, 1, SOP_MSG);
if (ret) {
- dev_err(&pd->dev,
- "Error sending get_battery_status\n");
+ usbpd_err(&pd->dev, "Error sending get_battery_status\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
@@ -2668,7 +2673,7 @@
pd->send_pr_swap = false;
ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG);
if (ret) {
- dev_err(&pd->dev, "Error sending PR Swap\n");
+ usbpd_err(&pd->dev, "Error sending PR Swap\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
@@ -2679,7 +2684,7 @@
pd->send_dr_swap = false;
ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG);
if (ret) {
- dev_err(&pd->dev, "Error sending DR Swap\n");
+ usbpd_err(&pd->dev, "Error sending DR Swap\n");
usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET);
break;
}
@@ -3297,9 +3302,9 @@
"explicit" : "implicit");
add_uevent_var(env, "ALT_MODE=%d", pd->vdm_state == MODE_ENTERED);
- add_uevent_var(env, "ADO=%08x", pd->received_ado);
- for (i = 0; i < PD_STATUS_DB_LEN; i++)
- add_uevent_var(env, "SDB%d=%08x", i, pd->status_db[i]);
+ add_uevent_var(env, "SDB=%02x %02x %02x %02x %02x", pd->status_db[0],
+ pd->status_db[1], pd->status_db[2], pd->status_db[3],
+ pd->status_db[4]);
return 0;
}
@@ -3690,12 +3695,40 @@
return ret;
for (i = 0; i < PD_SRC_CAP_EXT_DB_LEN; i++)
- len += snprintf(buf + len, PAGE_SIZE - len, "%d\n",
- pd->src_cap_ext_db[i]);
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x",
+ i ? " " : "", pd->src_cap_ext_db[i]);
+
+ buf[len++] = '\n';
+ buf[len] = '\0';
+
return len;
}
static DEVICE_ATTR_RO(get_src_cap_ext);
+static ssize_t get_status_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, ret, len = 0;
+ struct usbpd *pd = dev_get_drvdata(dev);
+
+ if (pd->spec_rev == USBPD_REV_20)
+ return -EINVAL;
+
+ ret = trigger_tx_msg(pd, &pd->send_get_status);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < PD_STATUS_DB_LEN; i++)
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x",
+ i ? " " : "", pd->status_db[i]);
+
+ buf[len++] = '\n';
+ buf[len] = '\0';
+
+ return len;
+}
+static DEVICE_ATTR_RO(get_status);
+
static ssize_t get_pps_status_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -3709,20 +3742,10 @@
if (ret)
return ret;
- return snprintf(buf, PAGE_SIZE, "%d\n", pd->pps_status_db);
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->pps_status_db);
}
static DEVICE_ATTR_RO(get_pps_status);
-static ssize_t rx_ado_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct usbpd *pd = dev_get_drvdata(dev);
-
- /* dump the ADO as a hex string */
- return snprintf(buf, PAGE_SIZE, "%08x\n", pd->received_ado);
-}
-static DEVICE_ATTR_RO(rx_ado);
-
static ssize_t get_battery_cap_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
@@ -3751,8 +3774,12 @@
return -EINVAL;
for (i = 0; i < PD_BATTERY_CAP_DB_LEN; i++)
- len += snprintf(buf + len, PAGE_SIZE - len, "%d\n",
- pd->battery_cap_db[i]);
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x",
+ i ? " " : "", pd->battery_cap_db[i]);
+
+ buf[len++] = '\n';
+ buf[len] = '\0';
+
return len;
}
static DEVICE_ATTR_RW(get_battery_cap);
@@ -3783,7 +3810,7 @@
if (pd->get_battery_status_db == -EINVAL)
return -EINVAL;
- return snprintf(buf, PAGE_SIZE, "%d\n", pd->battery_sts_dobj);
+ return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->battery_sts_dobj);
}
static DEVICE_ATTR_RW(get_battery_status);
@@ -3807,8 +3834,8 @@
&dev_attr_rdo_h.attr,
&dev_attr_hard_reset.attr,
&dev_attr_get_src_cap_ext.attr,
+ &dev_attr_get_status.attr,
&dev_attr_get_pps_status.attr,
- &dev_attr_rx_ado.attr,
&dev_attr_get_battery_cap.attr,
&dev_attr_get_battery_status.attr,
NULL,
diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c
index 2997976..a1b8a32 100644
--- a/drivers/usb/pd/qpnp-pdphy.c
+++ b/drivers/usb/pd/qpnp-pdphy.c
@@ -50,7 +50,7 @@
#define TX_SIZE_MASK 0xF
#define USB_PDPHY_TX_CONTROL 0x44
-#define TX_CONTROL_RETRY_COUNT (BIT(6) | BIT(5))
+#define TX_CONTROL_RETRY_COUNT(n) (((n) & 0x3) << 5)
#define TX_CONTROL_FRAME_TYPE (BIT(4) | BIT(3) | BIT(2))
#define TX_CONTROL_FRAME_TYPE_CABLE_RESET (0x1 << 2)
#define TX_CONTROL_SEND_SIGNAL BIT(1)
@@ -80,6 +80,9 @@
#define VDD_PDPHY_VOL_MAX 3088000 /* uV */
#define VDD_PDPHY_HPM_LOAD 3000 /* uA */
+/* Message Spec Rev field */
+#define PD_MSG_HDR_REV(hdr) (((hdr) >> 6) & 3)
+
/* timers */
#define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */
#define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */
@@ -437,12 +440,12 @@
if (ret)
return ret;
- ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
+ ret = wait_event_interruptible_hrtimeout(pdphy->tx_waitq,
pdphy->tx_status != -EINPROGRESS,
- msecs_to_jiffies(HARD_RESET_COMPLETE_TIME));
- if (ret <= 0) {
+ ms_to_ktime(HARD_RESET_COMPLETE_TIME));
+ if (ret) {
dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
- return ret ? ret : -ETIMEDOUT;
+ return ret;
}
ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, 0);
@@ -520,18 +523,24 @@
usleep_range(2, 3);
- val = TX_CONTROL_RETRY_COUNT | (sop << 2) | TX_CONTROL_SEND_MSG;
+ val = (sop << 2) | TX_CONTROL_SEND_MSG;
+
+ /* nRetryCount == 2 for PD 3.0, 3 for PD 2.0 */
+ if (PD_MSG_HDR_REV(hdr) == USBPD_REV_30)
+ val |= TX_CONTROL_RETRY_COUNT(2);
+ else
+ val |= TX_CONTROL_RETRY_COUNT(3);
ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val);
if (ret)
return ret;
- ret = wait_event_interruptible_timeout(pdphy->tx_waitq,
+ ret = wait_event_interruptible_hrtimeout(pdphy->tx_waitq,
pdphy->tx_status != -EINPROGRESS,
- msecs_to_jiffies(RECEIVER_RESPONSE_TIME));
- if (ret <= 0) {
+ ms_to_ktime(RECEIVER_RESPONSE_TIME));
+ if (ret) {
dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret);
- return ret ? ret : -ETIMEDOUT;
+ return ret;
}
if (hdr && !pdphy->tx_status)
diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h
index cd2d2d2..680d05b 100644
--- a/include/uapi/media/cam_icp.h
+++ b/include/uapi/media/cam_icp.h
@@ -59,8 +59,9 @@
/* Command meta types */
#define CAM_ICP_CMD_META_GENERIC_BLOB 0x1
-/* Generic blon types */
+/* Generic blob types */
#define CAM_ICP_CMD_GENERIC_BLOB_CLK 0x1
+#define CAM_ICP_CMD_GENERIC_BLOB_CFG_IO 0x2
/**
* struct cam_icp_clk_bw_request
diff --git a/net/ipc_router/ipc_router_fifo_xprt.c b/net/ipc_router/ipc_router_fifo_xprt.c
index ae85fd1..c90534d 100644
--- a/net/ipc_router/ipc_router_fifo_xprt.c
+++ b/net/ipc_router/ipc_router_fifo_xprt.c
@@ -255,7 +255,7 @@
hdr_len = sizeof(struct rr_header_v1);
while (1) {
rx_avail = fifo_rx_avail(&xprtp->rx_pipe);
- if (!rx_avail || (rx_avail < hdr_len))
+ if (!rx_avail)
break;
fifo_rx_peak(&xprtp->rx_pipe, &hdr, 0, hdr_len);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index c88874f..0a67d80 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -949,6 +949,7 @@
nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE);
list_del_rcu(&wdev->list);
+ synchronize_rcu();
rdev->devlist_generation++;
switch (wdev->iftype) {
diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c
index ce1f0ad..fe29aed 100644
--- a/sound/usb/usb_audio_qmi_svc.c
+++ b/sound/usb/usb_audio_qmi_svc.c
@@ -110,8 +110,8 @@
unsigned long curr_xfer_buf_iova;
/* bit fields representing pcm card enabled */
unsigned long card_slot;
- /* cache event ring phys addr */
- u64 er_phys_addr;
+ /* indicate event ring mapped or not */
+ bool er_mapped;
};
static struct uaudio_qmi_dev *uaudio_qdev;
@@ -295,7 +295,7 @@
case MEM_EVENT_RING:
va = IOVA_BASE;
/* er already mapped */
- if (uaudio_qdev->er_phys_addr == pa)
+ if (uaudio_qdev->er_mapped)
map = false;
break;
case MEM_XFER_RING:
@@ -407,8 +407,8 @@
switch (mtype) {
case MEM_EVENT_RING:
- if (uaudio_qdev->er_phys_addr)
- uaudio_qdev->er_phys_addr = 0;
+ if (uaudio_qdev->er_mapped)
+ uaudio_qdev->er_mapped = false;
else
unmap = false;
break;
@@ -637,7 +637,7 @@
uaudio_qdev->sid);
resp->xhci_mem_info.evt_ring.pa = dma;
resp->xhci_mem_info.evt_ring.size = PAGE_SIZE;
- uaudio_qdev->er_phys_addr = xhci_pa;
+ uaudio_qdev->er_mapped = true;
resp->speed_info = get_speed_info(subs->dev->speed);
if (resp->speed_info == USB_AUDIO_DEVICE_SPEED_INVALID_V01)