diff options
| author | Michael Bestas <mkbestas@lineageos.org> | 2018-06-19 23:12:57 +0300 |
|---|---|---|
| committer | Michael Bestas <mkbestas@lineageos.org> | 2018-06-19 23:12:57 +0300 |
| commit | de6dac6df6807f901bac8e29de24a6a7981aea2d (patch) | |
| tree | a70d6303c33a857e730b5d920bfe7dc1047999dc | |
| parent | ed9b46f6268d2abcbb9079bf44261e3b6e8c424f (diff) | |
| parent | 44ff472b917252c55c8e96ce7e0612aed13269cb (diff) | |
Merge tag 'LA.UM.6.6.r1-08900-89xx.0' of kernel/msm-3.18 into lineage-15.1-caf-8996
Conflicts:
net/sctp/socket.c
Change-Id: I90c45f914ac4d11bbeee3722ede5ea55e52898e1
72 files changed, 8905 insertions, 239 deletions
diff --git a/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt b/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt index 7b89497f4638..49233d46a877 100644 --- a/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt +++ b/Documentation/devicetree/bindings/bluetooth/bluetooth_power.txt @@ -6,6 +6,7 @@ Required properties: - compatible: Should be set to one of the following: qca,ar3002 qca,qca6174 + qca,qca9379 qca,wcn3990 - qca,bt-reset-gpio: GPIO pin to bring BT Controller out of reset diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt new file mode 100644 index 000000000000..b54c85971927 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/himax.txt @@ -0,0 +1,22 @@ +Himax touch controller + +Required properties: + + - compatible : Should be "himax,hxcommon" + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - himax,irq-gpio : irq gpio. + - himax,reset-gpio : reset gpio. + - vdd-supply : Power supply needed to power up the device. + - avdd-supply : Power source required to power up i2c bus. + - himax,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. + - himax,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: + - himax,3v3-gpio : gpio acting as 3.3 v supply. + - report_type : Multi-touch protocol type. Default 0. + 0 for protocol A, 1 for protocol B. diff --git a/Documentation/devicetree/bindings/qseecom/qseecom.txt b/Documentation/devicetree/bindings/qseecom/qseecom.txt index dfc62b78f58d..1d48c7136a3e 100644 --- a/Documentation/devicetree/bindings/qseecom/qseecom.txt +++ b/Documentation/devicetree/bindings/qseecom/qseecom.txt @@ -27,6 +27,7 @@ Optional properties: - qcom,qsee-reentrancy-support: indicates the qsee reentrancy phase supported by the target - qcom,commonlib64-loaded-by-uefi: indicates commonlib64 is loaded by uefi already - qcom,fde-key-size: indicates which FDE key size is used in device. + - qcom,enable-key-wrap-in-ks: enables wrapping of ICE key with KS key. Example: qcom,qseecom@fe806000 { @@ -40,6 +41,7 @@ Example: qcom,hlos-ce-hw-instance = <1 2>; qcom,qsee-ce-hw-instance = <0>; qcom,support-fde; + qcom,enable-key-wrap-in-ks; qcom,support-pfe; qcom,msm_bus,name = "qseecom-noc"; qcom,msm_bus,num_cases = <4>; @@ -64,6 +66,7 @@ Example: The following dts setup is the same as the example above. reg = <0x7f00000 0x500000>; reg-names = "secapp-region"; qcom,support-fde; + qcom,enable-key-wrap-in-ks; qcom,full-disk-encrypt-info = <0 1 2>, <0 2 2>; qcom,support-pfe; qcom,per-file-encrypt-info = <0 1 0>, <0 2 0>; diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index db2682ff39b3..0ee9e79bf3e8 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -149,6 +149,7 @@ dtb-$(CONFIG_ARCH_MDM9650) += mdm9650-sim.dtb \ mdm9650-emmc-mtp.dtb \ mdm9650-nand-mtp.dtb \ mdm9650-ttp.dtb \ + mdm9650-pcie-ep-ttp.dtb \ mdm9650-nand-dualwifi-mtp.dtb \ mdm9650-v1.1-emmc-cdp.dtb \ mdm9650-v1.1-nand-cdp.dtb \ diff --git a/arch/arm/boot/dts/qcom/apq8053-camera-sensor-dragon.dtsi b/arch/arm/boot/dts/qcom/apq8053-camera-sensor-dragon.dtsi index 3b5225f50907..8230eab26da2 100644 --- a/arch/arm/boot/dts/qcom/apq8053-camera-sensor-dragon.dtsi +++ b/arch/arm/boot/dts/qcom/apq8053-camera-sensor-dragon.dtsi @@ -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 @@ -36,6 +36,109 @@ qcom,cam-vreg-op-mode = <80000>; }; + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + reg = <0x0>; + qcom,cci-master = <0>; + cam_vio-supply = <&pm8953_l6>; + cam_vdig-supply = <&pm8953_l2>; + cam_vana-supply = <&pm8953_l17>; + qcom,cam-vreg-name = "cam_vio", "cam_vdig", + "cam_vana"; + qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_default + &cam_sensor_rear_vana>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep + &cam_sensor_rear_vana_sleep>; + gpios = <&tlmm 26 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_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0"; + 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>; + }; + + eeprom1: qcom,eeprom@1 { + cell-index = <1>; + compatible = "qcom,eeprom"; + reg = <0x1>; + qcom,cci-master = <0>; + cam_vio-supply = <&pm8953_l6>; + cam_vdig-supply = <&pm8953_l2>; + cam_vana-supply = <&pm8953_l17>; + qcom,cam-vreg-name = "cam_vio", "cam_vdig", + "cam_vana"; + qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk1_sleep + &cam_sensor_front1_sleep>; + gpios = <&tlmm 27 0>, + <&tlmm 129 0>, + <&tlmm 130 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"; + 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>; + }; + + eeprom2: qcom,eeprom@2 { + cell-index = <2>; + compatible = "qcom,eeprom"; + reg = <0x2>; + qcom,cci-master = <0>; + cam_vio-supply = <&pm8953_l6>; + cam_vdig-supply = <&pm8953_l2>; + cam_vana-supply = <&pm8953_l17>; + qcom,cam-vreg-name = "cam_vio", "cam_vdig", + "cam_vana"; + qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep + &cam_sensor_front_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 131 0>, + <&tlmm 132 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"; + 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>; + }; + camera0: qcom,camera@0 { cell-index = <0>; compatible = "qcom,camera"; @@ -45,13 +148,14 @@ qcom,mount-angle = <0>; /*qcom,led-flash-src = <&led_flash0>;*/ qcom,actuator-src = <&actuator0>; + qcom,eeprom-src = <&eeprom0>; cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&eldo_cam0_vreg>; + cam_vdig-supply = <&pm8953_l2>; cam_vana-supply = <&pm8953_l17>; qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1100000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1100000 2850000>; + qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; qcom,cam-vreg-op-mode = <105000 0 100000>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_default @@ -86,14 +190,15 @@ qcom,csiphy-sd-index = <1>; qcom,csid-sd-index = <1>; qcom,mount-angle = <0>; - qcom,actuator-src = <&actuator1>; + qcom,actuator-src = <&actuator0>; + qcom,eeprom-src = <&eeprom1>; cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&eldo_cam1_vreg>; + cam_vdig-supply = <&pm8953_l2>; cam_vana-supply = <&pm8953_l17>; qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1100000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1100000 2850000>; + qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; qcom,cam-vreg-op-mode = <105000 0 100000>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_default @@ -110,7 +215,7 @@ qcom,gpio-req-tbl-label = "CAMIF_MCLK1", "CAM_RESET1", "CAM_STANDBY1"; - qcom,sensor-position = <0>; + qcom,sensor-position = <1>; qcom,sensor-mode = <0>; qcom,cci-master = <0>; status = "ok"; @@ -128,13 +233,14 @@ qcom,csid-sd-index = <2>; qcom,mount-angle = <0>; qcom,actuator-src = <&actuator0>; + qcom,eeprom-src = <&eeprom2>; cam_vio-supply = <&pm8953_l6>; - cam_vdig-supply = <&eldo_cam2_vreg>; + cam_vdig-supply = <&pm8953_l2>; cam_vana-supply = <&pm8953_l17>; qcom,cam-vreg-name = "cam_vio", "cam_vdig", "cam_vana"; - qcom,cam-vreg-min-voltage = <1800000 1100000 2850000>; - qcom,cam-vreg-max-voltage = <1800000 1100000 2850000>; + qcom,cam-vreg-min-voltage = <1800000 1200000 2850000>; + qcom,cam-vreg-max-voltage = <1800000 1200000 2850000>; qcom,cam-vreg-op-mode = <105000 0 100000>; /*qcom,gpio-no-mux = <0>;*/ pinctrl-names = "cam_default", "cam_suspend"; diff --git a/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi index 6286015ae2c2..8649b2000e70 100644 --- a/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -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 @@ -173,6 +173,23 @@ /delete-property/ qcom,msm-vdd-wsa-switch-current; }; +&pm8953_l2 { + status = "okay"; + regulator-always-on; +}; + +&camera0 { + qcom,mount-angle = <90>; +}; + +&camera1 { + qcom,mount-angle = <90>; +}; + +&camera2{ + qcom,mount-angle = <90>; +}; + &pm8953_diangu_dig { status = "ok"; }; @@ -537,3 +554,13 @@ status = "ok"; }; }; + +&soc { + qcom,wcnss-wlan@0a000000 { + status = "disabled"; + }; + + qcom,pronto@a21b000 { + status = "disabled"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/apq8053.dtsi b/arch/arm/boot/dts/qcom/apq8053.dtsi index 48529b041afc..b4aa9ae8b644 100644 --- a/arch/arm/boot/dts/qcom/apq8053.dtsi +++ b/arch/arm/boot/dts/qcom/apq8053.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * 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 @@ -52,3 +52,7 @@ &secure_mem { status = "disabled"; }; + +&qcom_seecom { + qcom,enable-key-wrap-in-ks; +}; diff --git a/arch/arm/boot/dts/qcom/mdm9650-pcie-ep-ttp.dts b/arch/arm/boot/dts/qcom/mdm9650-pcie-ep-ttp.dts new file mode 100644 index 000000000000..be1876886d6d --- /dev/null +++ b/arch/arm/boot/dts/qcom/mdm9650-pcie-ep-ttp.dts @@ -0,0 +1,185 @@ +/* + * 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. + */ + +/dts-v1/; + +#include "mdm9650-v1.1-mtp.dtsi" +/ { + model = "Qualcomm Technologies, Inc. MDM 9650 PCIE EP TTP"; + compatible = "qcom,mdm9650-ttp", "qcom,mdm9650", "qcom,ttp"; + qcom,board-id = <0x1e 2>; +}; + +&pmd9650_l13 { + regulator-always-on; +}; + +&i2c_1 { + status = "ok"; + bmi160@68{ + compatible = "bosch-sensortec,bmi160"; + reg = <0x68>; + pinctrl-names = "default"; + pinctrl-0 = <&bmi160_int1_default &bmi160_int2_default>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <0x0 0x2002>; + bmi,init-interval = <200>; + bmi,place = <1>; + bmi,gpio_irq = <&tlmm_pinmux 0x0 0x2002>; + }; +}; + +&i2c_3 { + status = "ok"; + smb1351_otg_supply: smb1351-charger@55{ + status = "disabled"; + }; +}; + +&soc { + tlmm_pinmux: pinctrl@1000000 { + i2c_1 { + i2c_1_active { + config { + pins = "gpio2", "gpio3"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + }; + + usb_detect { + compatible = "qcom,gpio-usbdetect"; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0x0d 0x0>; /* PMD9655 VBUS DETECT */ + interrupt-names = "vbus_det_irq"; + }; +}; + +&usb3 { + cpe-gpio = <&tlmm_pinmux 87 0>; +}; + +&spi_2 { + status = "ok"; + + can-controller@0 { + compatible = "fsl,k61"; + spi-max-frequency = <4800000>; + reg = <0>; + interrupt-parent = <&tlmm_pinmux>; + interrupts = <84 0>; + reset-gpio = <&tlmm_pinmux 68 0x1>; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&can_rst_on>; + pinctrl-1 = <&can_rst_off>; + }; +}; + +&blsp1_uart4b_hs { + status = "ok"; +}; + +&blsp1_uart2_hs { + status = "disabled"; +}; + +&snd_tasha { + pinctrl-names = + "all_off", + "pri_mi2s_aux_master_active", + "pri_mi2s_aux_slave_active", + "invalid_state_1", + "sec_mi2s_aux_master_active", + "pri_master_active_sec_master_active", + "pri_slave_active_sec_master_active", + "invalid_state_2", + "sec_mi2s_aux_slave_active", + "pri_master_active_sec_slave_active", + "pri_slave_active_sec_slave_active"; + pinctrl-0 = <&pri_ws_sleep &pri_sck_sleep + &pri_dout_sleep &pri_din_sleep + &sec_ws_b_sleep &sec_sck_b_sleep + &sec_dout_b_sleep &sec_din_b_sleep>; + pinctrl-1 = <&pri_ws_active_master &pri_sck_active_master + &pri_dout_active &pri_din_active + &sec_ws_b_sleep &sec_sck_b_sleep + &sec_dout_b_sleep &sec_din_b_sleep>; + pinctrl-2 = <&pri_ws_active_slave &pri_sck_active_slave + &pri_dout_active &pri_din_active + &sec_ws_b_sleep &sec_sck_b_sleep + &sec_dout_b_sleep &sec_din_b_sleep>; + pinctrl-3 = <&pri_ws_sleep &pri_sck_sleep + &pri_dout_sleep &pri_din_sleep + &sec_ws_b_sleep &sec_sck_b_sleep + &sec_dout_b_sleep &sec_din_b_sleep>; + pinctrl-4 = <&pri_ws_sleep &pri_sck_sleep + &pri_dout_sleep &pri_din_sleep + &sec_ws_b_active_master &sec_sck_b_active_master + &sec_dout_b_active &sec_din_b_active>; + pinctrl-5 = <&pri_ws_active_master &pri_sck_active_master + &pri_dout_active &pri_din_active + &sec_ws_b_active_master &sec_sck_b_active_master + &sec_dout_b_active &sec_din_b_active>; + pinctrl-6 = <&pri_ws_active_slave &pri_sck_active_slave + &pri_dout_active &pri_din_active + &sec_ws_b_active_master &sec_sck_b_active_master + &sec_dout_b_active &sec_din_b_active>; + pinctrl-7 = <&pri_ws_sleep &pri_sck_sleep + &pri_dout_sleep &pri_din_sleep + &sec_ws_b_sleep &sec_sck_b_sleep + &sec_dout_b_sleep &sec_din_b_sleep>; + pinctrl-8 = <&pri_ws_sleep &pri_sck_sleep + &pri_dout_sleep &pri_din_sleep + &sec_ws_b_active_slave &sec_sck_b_active_slave + &sec_dout_b_active &sec_din_b_active>; + pinctrl-9 = <&pri_ws_active_master &pri_sck_active_master + &pri_dout_active &pri_din_active + &sec_ws_b_active_slave &sec_sck_b_active_slave + &sec_dout_b_active &sec_din_b_active>; + pinctrl-10 = <&pri_ws_active_slave &pri_sck_active_slave + &pri_dout_active &pri_din_active + &sec_ws_b_active_slave &sec_sck_b_active_slave + &sec_dout_b_active &sec_din_b_active>; +}; + +&pcie_ep { + status = "ok"; + mdm2apstatus-gpio = <&tlmm_pinmux 85 0>; +}; + +&pcie0 { + status = "disabled"; +}; + +&cnss_pcie { + status = "disabled"; +}; + +&mhi_device { + status = "ok"; +}; + +&pcie0_mdm2apstatus_default { + mux { + pins = "gpio85"; + function = "gpio"; + }; + + config { + pins = "gpio85"; + drive-strength = <2>; + bias-pull-down; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909-1gb-cdp.dts b/arch/arm/boot/dts/qcom/msm8909-1gb-cdp.dts index bcc2b9049657..9e522bc8387e 100644 --- a/arch/arm/boot/dts/qcom/msm8909-1gb-cdp.dts +++ b/arch/arm/boot/dts/qcom/msm8909-1gb-cdp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 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 @@ -15,6 +15,7 @@ #include "msm8909-cdp.dtsi" #include "msm8909-pm8909.dtsi" #include "msm8909-pm8909-cdp.dtsi" +#include "msm8909-mtp_qseev4.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909-PM8909 1GB CDP"; diff --git a/arch/arm/boot/dts/qcom/msm8909-1gb-mtp.dts b/arch/arm/boot/dts/qcom/msm8909-1gb-mtp.dts index 3853148057d2..14606fa11713 100644 --- a/arch/arm/boot/dts/qcom/msm8909-1gb-mtp.dts +++ b/arch/arm/boot/dts/qcom/msm8909-1gb-mtp.dts @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 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 @@ -15,6 +15,7 @@ #include "msm8909-mtp.dtsi" #include "msm8909-pm8909.dtsi" #include "msm8909-pm8909-mtp.dtsi" +#include "msm8909-mtp_qseev4.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909-PM8909 1GB MTP"; diff --git a/arch/arm/boot/dts/qcom/msm8909-1gb-rcm.dts b/arch/arm/boot/dts/qcom/msm8909-1gb-rcm.dts index a15d8c91287f..7a46da8db1c6 100644 --- a/arch/arm/boot/dts/qcom/msm8909-1gb-rcm.dts +++ b/arch/arm/boot/dts/qcom/msm8909-1gb-rcm.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 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 @@ -16,6 +16,7 @@ #include "msm8909-cdp.dtsi" #include "msm8909-pm8909.dtsi" #include "msm8909-pm8909-cdp.dtsi" +#include "msm8909-mtp_qseev4.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909-PM8909 1GB RCM"; diff --git a/arch/arm/boot/dts/qcom/msm8909-camera-sensor-skue.dtsi b/arch/arm/boot/dts/qcom/msm8909-camera-sensor-skue.dtsi index 8a67a01cfa63..9e64171a7173 100644 --- a/arch/arm/boot/dts/qcom/msm8909-camera-sensor-skue.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-camera-sensor-skue.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-18 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 @@ -11,17 +11,20 @@ * GNU General Public License for more details. */ &soc { - SY7803_default: SY7803_default { - mux { - /* CLK, DATA */ - pins = "gpio31", "gpio32"; - function = "gpio"; - }; - config { - pins = "gpio31", "gpio32"; - bias-disable; /* No PULL */ - drive-strength = <2>; /* 2 MA */ + msm_gpio: pinctrl@1000000 { + SY7803_default: SY7803_default { + mux { + /* CLK, DATA */ + pins = "gpio31", "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; }; }; @@ -33,7 +36,7 @@ qcom,flash-en = <&msm_gpio 31 0>; qcom,flash-now = <&msm_gpio 32 0>; qcom,op-seq = "flash_en", "flash_now"; - qcom,torch-seq-val = <1 0>; + qcom,torch-seq-val = <0 1>; qcom,flash-seq-val = <1 1>; linux,name = "flashlight"; linux,default-trigger = "flashlight-trigger"; diff --git a/arch/arm/boot/dts/qcom/msm8909-gpu.dtsi b/arch/arm/boot/dts/qcom/msm8909-gpu.dtsi index ba87d663a8d4..51529a2ee8b2 100644 --- a/arch/arm/boot/dts/qcom/msm8909-gpu.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-gpu.dtsi @@ -19,26 +19,15 @@ /* To use BIMC based bus governor */ gpubw: qcom,gpubw { compatible = "qcom,devbw"; - governor = "bw_hwmon"; + governor = "bw_vbif"; qcom,src-dst-ports = <26 512>; qcom,bw-tbl = < 0 >, /* 9.6 MHz */ - < 381 >, /* 50.0 MHz */ - < 762 >, /* 100.0 MHz */ < 1525 >, /* 200.0 MHz */ < 3051 >, /* 400.0 MHz */ < 4066 >; /* 533.0 MHz */ }; - qcom,gpu-bwmon@410000 { - compatible = "qcom,bimc-bwmon2"; - reg = <0x00410000 0x300>, <0x00401000 0x200>; - reg-names = "base", "global_base"; - interrupts = <0 183 4>; - qcom,mport = <2>; - qcom,target-dev = <&gpubw>; - }; - msm_gpu: qcom,kgsl-3d0@01c00000 { label = "kgsl-3d0"; compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; @@ -105,24 +94,32 @@ reg = <0>; qcom,gpu-freq = <456000000>; qcom,bus-freq = <3>; + qcom,bus-min = <3>; + qcom,bus-max = <3>; }; qcom,gpu-pwrlevel@1 { reg = <1>; qcom,gpu-freq = <307200000>; qcom,bus-freq = <2>; + qcom,bus-min = <2>; + qcom,bus-max = <3>; }; qcom,gpu-pwrlevel@2 { reg = <2>; qcom,gpu-freq = <200000000>; - qcom,bus-freq = <1>; + qcom,bus-freq = <2>; + qcom,bus-min = <1>; + qcom,bus-max = <2>; }; qcom,gpu-pwrlevel@3 { reg = <3>; qcom,gpu-freq = <19200000>; qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; }; }; diff --git a/arch/arm/boot/dts/qcom/msm8909-ion.dtsi b/arch/arm/boot/dts/qcom/msm8909-ion.dtsi index 4655b758f8e5..98561498c82e 100644 --- a/arch/arm/boot/dts/qcom/msm8909-ion.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-ion.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, 2016-2017, Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2016-2018, 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 @@ -11,7 +11,7 @@ */ &soc { - qcom,ion { + ion: qcom,ion { compatible = "qcom,msm-ion"; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm/boot/dts/qcom/msm8909-mtp_qseev4.dtsi b/arch/arm/boot/dts/qcom/msm8909-mtp_qseev4.dtsi new file mode 100644 index 000000000000..67dca943a51f --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8909-mtp_qseev4.dtsi @@ -0,0 +1,29 @@ +/* + * 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. + */ + +&reserved_mem { + secure_display_memory: secure_region { + compatible = "shared-dma-pool"; + label = "secure_display_mem"; + size = <0 0x1400000>; + reusable; + }; +}; + +&ion { + secure_display_heap: qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "SECURE_DMA"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8916-1gb-rcm.dts b/arch/arm/boot/dts/qcom/msm8909-pm8916-1gb-rcm.dts index a80bd89c5c03..3c05965f9b90 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8916-1gb-rcm.dts +++ b/arch/arm/boot/dts/qcom/msm8909-pm8916-1gb-rcm.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * 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 @@ -15,6 +15,7 @@ #include "msm8909-cdp.dtsi" #include "msm8909-pm8916-cdp.dtsi" +#include "msm8909-mtp_qseev4.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909-PM8916 1GB RCM"; diff --git a/arch/arm/boot/dts/qcom/msm8909-pm8916-mtp.dts b/arch/arm/boot/dts/qcom/msm8909-pm8916-mtp.dts index fb37873cc661..5c5adb73a998 100644 --- a/arch/arm/boot/dts/qcom/msm8909-pm8916-mtp.dts +++ b/arch/arm/boot/dts/qcom/msm8909-pm8916-mtp.dts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 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 @@ -16,6 +16,7 @@ #include "msm8909-mtp.dtsi" #include "msm8909-pm8916.dtsi" #include "msm8909-pm8916-mtp.dtsi" +#include "msm8909-mtp_qseev4.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909-PM8916 1GB MTP"; diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi index f4b41b4f38ba..56d22b2045d2 100644 --- a/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909-qrd.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, 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 @@ -13,6 +13,7 @@ #include "msm8909.dtsi" #include "msm8909-pm8909.dtsi" #include "msm8909-pinctrl.dtsi" +#include "msm8909-qrd_qseev4.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8909 QRD"; diff --git a/arch/arm/boot/dts/qcom/msm8909-qrd_qseev4.dtsi b/arch/arm/boot/dts/qcom/msm8909-qrd_qseev4.dtsi new file mode 100644 index 000000000000..8c58d4689b77 --- /dev/null +++ b/arch/arm/boot/dts/qcom/msm8909-qrd_qseev4.dtsi @@ -0,0 +1,29 @@ +/* + * 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. + */ + +&reserved_mem { + secure_display_memory: secure_region { + compatible = "shared-dma-pool"; + label = "secure_display_mem"; + size = <0 0x800000>; + reusable; + }; +}; + +&ion { + secure_display_heap: qcom,ion-heap@10 { /* SECURE DISPLAY HEAP */ + reg = <10>; + memory-region = <&secure_display_memory>; + qcom,ion-heap-type = "SECURE_DMA"; + }; +}; diff --git a/arch/arm/boot/dts/qcom/msm8909.dtsi b/arch/arm/boot/dts/qcom/msm8909.dtsi index fd10716b1c6e..b14f0cb89ed2 100644 --- a/arch/arm/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm/boot/dts/qcom/msm8909.dtsi @@ -132,7 +132,7 @@ }; }; - reserved-memory { + reserved_mem: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; diff --git a/arch/arm/configs/msmcortex-perf_defconfig b/arch/arm/configs/msmcortex-perf_defconfig index 1d28f3770f0d..378119e357a0 100644 --- a/arch/arm/configs/msmcortex-perf_defconfig +++ b/arch/arm/configs/msmcortex-perf_defconfig @@ -285,7 +285,9 @@ CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CNSS_CRYPTO=y CONFIG_ATH_CARDS=y -CONFIG_CLD_LL_CORE=y +CONFIG_CNSS=y +CONFIG_CNSS_SDIO=y +CONFIG_CLD_HL_SDIO_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_INPUT_KEYRESET=y @@ -305,6 +307,10 @@ CONFIG_TOUCHSCREEN_ATMEL_MXT=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_MAXIM_STI=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_KEYCHORD=y diff --git a/arch/arm/configs/msmcortex_defconfig b/arch/arm/configs/msmcortex_defconfig index 1f27382f2f43..2400e9efbf3f 100644 --- a/arch/arm/configs/msmcortex_defconfig +++ b/arch/arm/configs/msmcortex_defconfig @@ -228,7 +228,6 @@ CONFIG_BT_BNEP_PROTO_FILTER=y CONFIG_BT_HIDP=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y -CONFIG_NL80211_TESTMODE=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y @@ -288,6 +287,9 @@ CONFIG_WCNSS_CORE_PRONTO=y CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CNSS_CRYPTO=y +CONFIG_CNSS=y +CONFIG_CNSS_SDIO=y +CONFIG_CLD_HL_SDIO_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_INPUT_EVBUG=m CONFIG_KEYBOARD_GPIO=y @@ -306,6 +308,10 @@ CONFIG_SECURE_TOUCH=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_MAXIM_STI=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_UINPUT=y diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index 3f2d53fa5a90..8485481d0c89 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, 2013-2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2010, 2013-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 @@ -36,6 +36,7 @@ static struct of_device_id bt_power_match_table[] = { { .compatible = "qca,ar3002" }, { .compatible = "qca,qca6174" }, + { .compatible = "qca,qca9379" }, { .compatible = "qca,wcn3990" }, {} }; diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index 41fcee399eed..df60c3ea077f 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-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 @@ -423,10 +423,6 @@ static int parse_legacy_cluster_params(struct device_node *node, return 0; failed: pr_err("%s(): Failed reading %s\n", __func__, key); - kfree(c->name); - kfree(c->lpm_dev); - c->name = NULL; - c->lpm_dev = NULL; return ret; } @@ -612,8 +608,6 @@ static int parse_cluster_level(struct device_node *node, return 0; failed: pr_err("Failed %s() key = %s ret = %d\n", __func__, key, ret); - kfree(level->mode); - level->mode = NULL; return ret; } @@ -808,19 +802,12 @@ static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) return 0; failed: - for (i = 0; i < c->cpu->nlevels; i++) { - kfree(c->cpu->levels[i].name); - c->cpu->levels[i].name = NULL; - } - kfree(c->cpu); - c->cpu = NULL; pr_err("%s(): Failed with error code:%d\n", __func__, ret); return ret; } void free_cluster_node(struct lpm_cluster *cluster) { - int i; struct lpm_cluster *cl, *m; list_for_each_entry_safe(cl, m, &cluster->child, list) { @@ -828,22 +815,6 @@ void free_cluster_node(struct lpm_cluster *cluster) free_cluster_node(cl); }; - if (cluster->cpu) { - for (i = 0; i < cluster->cpu->nlevels; i++) { - kfree(cluster->cpu->levels[i].name); - cluster->cpu->levels[i].name = NULL; - } - } - for (i = 0; i < cluster->nlevels; i++) { - kfree(cluster->levels[i].mode); - cluster->levels[i].mode = NULL; - } - kfree(cluster->cpu); - kfree(cluster->name); - kfree(cluster->lpm_dev); - cluster->cpu = NULL; - cluster->name = NULL; - cluster->lpm_dev = NULL; cluster->ndevices = 0; } @@ -957,9 +928,7 @@ failed_parse_cluster: list_del(&c->list); free_cluster_node(c); failed_parse_params: - c->parent = NULL; pr_err("Failed parse params\n"); - kfree(c); return NULL; } struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 6355831b34bb..0a44f538f192 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -1368,7 +1368,7 @@ static void _set_secvid(struct kgsl_device *device) adreno_writereg64(adreno_dev, ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE, ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE_HI, - KGSL_IOMMU_SECURE_BASE); + KGSL_IOMMU_SECURE_BASE(&device->mmu)); adreno_writereg(adreno_dev, ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_SIZE, KGSL_IOMMU_SECURE_SIZE); @@ -1790,7 +1790,7 @@ static int adreno_getproperty(struct kgsl_device *device, * anything to mmap(). */ shadowprop.gpuaddr = - (unsigned int) device->memstore.gpuaddr; + (unsigned long)device->memstore.gpuaddr; shadowprop.size = device->memstore.size; /* GSL needs this to be set, even if it appears to be meaningless */ diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index b112b041e8b9..002489226884 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2441,8 +2441,8 @@ static int a5xx_rb_start(struct adreno_device *adreno_dev, adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_CNTL, A5XX_CP_RB_CNTL_DEFAULT); - adreno_writereg(adreno_dev, ADRENO_REG_CP_RB_BASE, - rb->buffer_desc.gpuaddr); + adreno_writereg64(adreno_dev, ADRENO_REG_CP_RB_BASE, + ADRENO_REG_CP_RB_BASE_HI, rb->buffer_desc.gpuaddr); ret = a5xx_microcode_load(adreno_dev); if (ret) diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 0e9fa9ffdf12..2fe1fdc0baa0 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.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 @@ -38,9 +38,10 @@ #define _IOMMU_PRIV(_mmu) (&((_mmu)->priv.iommu)) -#define ADDR_IN_GLOBAL(_a) \ - (((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE) && \ - ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE + KGSL_IOMMU_GLOBAL_MEM_SIZE))) +#define ADDR_IN_GLOBAL(_mmu, _a) \ + (((_a) >= KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu)) && \ + ((_a) < (KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) + \ + KGSL_IOMMU_GLOBAL_MEM_SIZE))) static struct kgsl_mmu_pt_ops iommu_pt_ops; static bool need_iommu_sync; @@ -197,7 +198,7 @@ static void kgsl_iommu_add_global(struct kgsl_mmu *mmu, BUG_ON(global_pt_count >= GLOBAL_PT_ENTRIES); BUG_ON((global_pt_alloc + memdesc->size) >= KGSL_IOMMU_GLOBAL_MEM_SIZE); - memdesc->gpuaddr = KGSL_IOMMU_GLOBAL_MEM_BASE + global_pt_alloc; + memdesc->gpuaddr = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu) + global_pt_alloc; memdesc->priv |= KGSL_MEMDESC_GLOBAL; global_pt_alloc += memdesc->size; @@ -210,7 +211,7 @@ static void kgsl_iommu_add_global(struct kgsl_mmu *mmu, void kgsl_add_global_secure_entry(struct kgsl_device *device, struct kgsl_memdesc *memdesc) { - memdesc->gpuaddr = KGSL_IOMMU_SECURE_BASE; + memdesc->gpuaddr = KGSL_IOMMU_SECURE_BASE(&device->mmu); kgsl_global_secure_pt_entry = memdesc; } @@ -631,7 +632,7 @@ static void _find_mem_entries(struct kgsl_mmu *mmu, uint64_t faultaddr, /* Set the maximum possible size as an initial value */ nextentry->gpuaddr = (uint64_t) -1; - if (ADDR_IN_GLOBAL(faultaddr)) { + if (ADDR_IN_GLOBAL(mmu, faultaddr)) { _get_global_entries(faultaddr, preventry, nextentry); } else if (context) { private = context->proc_priv; @@ -1001,14 +1002,14 @@ static void setup_64bit_pagetable(struct kgsl_mmu *mmu, unsigned int secure_global_size = kgsl_global_secure_pt_entry != NULL ? kgsl_global_secure_pt_entry->size : 0; if (mmu->secured && pagetable->name == KGSL_MMU_SECURE_PT) { - pt->compat_va_start = KGSL_IOMMU_SECURE_BASE + + pt->compat_va_start = KGSL_IOMMU_SECURE_BASE(mmu) + secure_global_size; - pt->compat_va_end = KGSL_IOMMU_SECURE_END; - pt->va_start = KGSL_IOMMU_SECURE_BASE + secure_global_size; - pt->va_end = KGSL_IOMMU_SECURE_END; + pt->compat_va_end = KGSL_IOMMU_SECURE_END(mmu); + pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu) + secure_global_size; + pt->va_end = KGSL_IOMMU_SECURE_END(mmu); } else { pt->compat_va_start = KGSL_IOMMU_SVM_BASE32; - pt->compat_va_end = KGSL_IOMMU_SVM_END32; + pt->compat_va_end = KGSL_IOMMU_SECURE_BASE(mmu); pt->va_start = KGSL_IOMMU_VA_BASE64; pt->va_end = KGSL_IOMMU_VA_END64; } @@ -1017,7 +1018,7 @@ static void setup_64bit_pagetable(struct kgsl_mmu *mmu, pagetable->name != KGSL_MMU_SECURE_PT) { if ((BITS_PER_LONG == 32) || is_compat_task()) { pt->svm_start = KGSL_IOMMU_SVM_BASE32; - pt->svm_end = KGSL_IOMMU_SVM_END32; + pt->svm_end = KGSL_IOMMU_SECURE_BASE(mmu); } else { pt->svm_start = KGSL_IOMMU_SVM_BASE64; pt->svm_end = KGSL_IOMMU_SVM_END64; @@ -1033,22 +1034,22 @@ static void setup_32bit_pagetable(struct kgsl_mmu *mmu, kgsl_global_secure_pt_entry->size : 0; if (mmu->secured) { if (pagetable->name == KGSL_MMU_SECURE_PT) { - pt->compat_va_start = KGSL_IOMMU_SECURE_BASE + + pt->compat_va_start = KGSL_IOMMU_SECURE_BASE(mmu) + secure_global_size; - pt->compat_va_end = KGSL_IOMMU_SECURE_END; - pt->va_start = KGSL_IOMMU_SECURE_BASE + + pt->compat_va_end = KGSL_IOMMU_SECURE_END(mmu); + pt->va_start = KGSL_IOMMU_SECURE_BASE(mmu) + secure_global_size; - pt->va_end = KGSL_IOMMU_SECURE_END; + pt->va_end = KGSL_IOMMU_SECURE_END(mmu); } else { pt->va_start = KGSL_IOMMU_SVM_BASE32; - pt->va_end = KGSL_IOMMU_SECURE_BASE + + pt->va_end = KGSL_IOMMU_SECURE_BASE(mmu) + secure_global_size; pt->compat_va_start = pt->va_start; pt->compat_va_end = pt->va_end; } } else { pt->va_start = KGSL_IOMMU_SVM_BASE32; - pt->va_end = KGSL_IOMMU_GLOBAL_MEM_BASE; + pt->va_end = KGSL_IOMMU_GLOBAL_MEM_BASE(mmu); pt->compat_va_start = pt->va_start; pt->compat_va_end = pt->va_end; } @@ -2203,7 +2204,8 @@ static int kgsl_iommu_set_svm_region(struct kgsl_pagetable *pagetable, struct rb_node *node; /* Make sure the requested address doesn't fall in the global range */ - if (ADDR_IN_GLOBAL(gpuaddr) || ADDR_IN_GLOBAL(gpuaddr + size)) + if (ADDR_IN_GLOBAL(pagetable->mmu, gpuaddr) || + ADDR_IN_GLOBAL(pagetable->mmu, gpuaddr + size)) return -ENOMEM; spin_lock(&pagetable->lock); diff --git a/drivers/gpu/msm/kgsl_iommu.h b/drivers/gpu/msm/kgsl_iommu.h index 457522986fce..097dfe798bbe 100644 --- a/drivers/gpu/msm/kgsl_iommu.h +++ b/drivers/gpu/msm/kgsl_iommu.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -24,12 +24,17 @@ * are mapped into all pagetables. */ #define KGSL_IOMMU_GLOBAL_MEM_SIZE SZ_8M -#define KGSL_IOMMU_GLOBAL_MEM_BASE 0xf8000000 +#define KGSL_IOMMU_GLOBAL_MEM_BASE32 0xf8000000 +#define KGSL_IOMMU_GLOBAL_MEM_BASE64 0xfc000000 + +#define KGSL_IOMMU_GLOBAL_MEM_BASE(__mmu) \ + (MMU_FEATURE(__mmu, KGSL_MMU_64BIT) ? \ + KGSL_IOMMU_GLOBAL_MEM_BASE64 : KGSL_IOMMU_GLOBAL_MEM_BASE32) #define KGSL_IOMMU_SECURE_SIZE SZ_256M -#define KGSL_IOMMU_SECURE_END KGSL_IOMMU_GLOBAL_MEM_BASE -#define KGSL_IOMMU_SECURE_BASE \ - (KGSL_IOMMU_GLOBAL_MEM_BASE - KGSL_IOMMU_SECURE_SIZE) +#define KGSL_IOMMU_SECURE_END(_mmu) KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) +#define KGSL_IOMMU_SECURE_BASE(_mmu) \ + (KGSL_IOMMU_GLOBAL_MEM_BASE(_mmu) - KGSL_IOMMU_SECURE_SIZE) #define KGSL_IOMMU_SVM_BASE32 0x300000 #define KGSL_IOMMU_SVM_END32 (0xC0000000 - SZ_16M) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index dd9b928e3694..769849d2e43c 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1137,4 +1137,16 @@ config TOUCHSCREEN_MAXIM_STI source "drivers/input/touchscreen/gt9xx/Kconfig" +config TOUCHSCREEN_HIMAX_CHIPSET + bool "Himax touchpanel CHIPSET" + depends on I2C + help + Say Y here if you have a Himax CHIPSET touchscreen. + HIMAX controllers are multi touch controllers which can + report 10 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/hxchipset/Kconfig" + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index be0eb9b34f5b..499b8110fe6c 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -90,3 +90,4 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += synaptics_i2c_rmi4.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI4_DEV) += synaptics_rmi_dev.o obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_fw_update.o obj-$(CONFIG_TOUCHSCREEN_GT9XX) += gt9xx/ +obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ diff --git a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig new file mode 100644 index 000000000000..ebf3aa478af5 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Kconfig @@ -0,0 +1,21 @@ +# +# Himax Touchscreen driver configuration +# + +config TOUCHSCREEN_HIMAX_I2C + tristate "HIMAX chipset i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_CHIPSET + help + This enables support for HIMAX CHIPSET over I2C based touchscreens. + +config TOUCHSCREEN_HIMAX_DEBUG + tristate "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_I2C + help + This enables support for HIMAX debug function. + +config HMX_DB + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + This enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile new file mode 100644 index 000000000000..509d4913bc39 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Makefile @@ -0,0 +1,3 @@ +# Makefile for the Himax touchscreen drivers. + +obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c new file mode 100644 index 000000000000..417b0c08e361 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -0,0 +1,1936 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_common.h" +#include "himax_ic.h" + +#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) +#define FRAME_COUNT 5 + +#if defined(HX_AUTO_UPDATE_FW) + static unsigned char i_CTPM_FW[]= + { + #include "HX83100_Amber_0901_030B.i" + }; +#endif + +#ifdef HX_ESD_WORKAROUND + extern void HX_report_ESD_event(void); + unsigned char ESD_00_counter = 0; + unsigned char ESD_00_Flag = 0; +#endif + +//static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; // for Virtual key array + +struct himax_ts_data *private_ts; +struct himax_ic_data* ic_data; + +static int HX_TOUCH_INFO_POINT_CNT; + +#ifdef HX_AUTO_UPDATE_FW +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +#endif +extern unsigned long FW_VER_MAJ_FLASH_LENG; +extern unsigned long FW_VER_MIN_FLASH_LENG; +extern unsigned long CFG_VER_MAJ_FLASH_LENG; +extern unsigned long CFG_VER_MIN_FLASH_LENG; +extern unsigned char IC_TYPE; +extern unsigned char IC_CHECKSUM; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +extern int himax_touch_proc_init(void); +extern void himax_touch_proc_deinit(void); +//PROC-START +#ifdef HX_TP_PROC_FLASH_DUMP +extern void himax_ts_flash_func(void); +extern void setFlashBuffer(void); +extern bool getFlashDumpGoing(void); +extern uint8_t getSysOperation(void); +extern void setSysOperation(uint8_t operation); +#endif + +#ifdef HX_TP_PROC_HITOUCH +extern bool hitouch_is_connect; +#endif + +#ifdef HX_TP_PROC_DIAG + extern int touch_monitor_stop_flag; + extern int touch_monitor_stop_limit; + extern void himax_ts_diag_func(void); + extern int16_t *getMutualBuffer(void); + extern int16_t *getMutualNewBuffer(void); + extern int16_t *getMutualOldBuffer(void); + extern int16_t *getSelfBuffer(void); + extern uint8_t getXChannel(void); + extern uint8_t getYChannel(void); + extern uint8_t getDiagCommand(void); + extern void setXChannel(uint8_t x); + extern void setYChannel(uint8_t y); + extern void setMutualBuffer(void); + extern void setMutualNewBuffer(void); + extern void setMutualOldBuffer(void); + extern uint8_t coordinate_dump_enable; + extern struct file *coordinate_fn; + extern uint8_t diag_coor[128]; +#ifdef HX_TP_PROC_2T2R + extern int16_t *getMutualBuffer_2(void); + extern uint8_t getXChannel_2(void); + extern uint8_t getYChannel_2(void); + extern void setXChannel_2(uint8_t x); + extern void setYChannel_2(uint8_t y); + extern void setMutualBuffer_2(void); +#endif +#endif +//PROC-END +#endif + +extern int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata); +extern int himax_ts_pinctrl_init(struct himax_ts_data *ts); + +static uint8_t vk_press; +static uint8_t AA_press; +static uint8_t EN_NoiseFilter; +static uint8_t Last_EN_NoiseFilter; +static int hx_point_num; // for himax_ts_work_func use +static int p_point_num = 0xFFFF; +static int tpd_key; +static int tpd_key_old; +static int probe_fail_flag; +static bool config_load; +static struct himax_config *config_selected; + +//static int iref_number = 11; +//static bool iref_found = false; + +#ifdef HX_USB_DETECT2 +extern bool USB_Flag; +#endif + +#if defined(CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void himax_ts_early_suspend(struct early_suspend *h); +static void himax_ts_late_resume(struct early_suspend *h); +#endif + +int himax_input_register(struct himax_ts_data *ts) +{ + int ret; + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device\n", __func__); + return ret; + } + ts->input_dev->name = "himax-touchscreen"; + + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + + set_bit(KEY_BACK, ts->input_dev->keybit); + set_bit(KEY_HOME, ts->input_dev->keybit); + set_bit(KEY_MENU, ts->input_dev->keybit); + set_bit(KEY_SEARCH, ts->input_dev->keybit); +#if defined(HX_SMART_WAKEUP) + set_bit(KEY_POWER, ts->input_dev->keybit); + set_bit(KEY_CUST_01, ts->input_dev->keybit); + set_bit(KEY_CUST_02, ts->input_dev->keybit); + set_bit(KEY_CUST_03, ts->input_dev->keybit); + set_bit(KEY_CUST_04, ts->input_dev->keybit); + set_bit(KEY_CUST_05, ts->input_dev->keybit); + set_bit(KEY_CUST_06, ts->input_dev->keybit); + set_bit(KEY_CUST_07, ts->input_dev->keybit); + set_bit(KEY_CUST_08, ts->input_dev->keybit); + set_bit(KEY_CUST_09, ts->input_dev->keybit); + set_bit(KEY_CUST_10, ts->input_dev->keybit); + set_bit(KEY_CUST_11, ts->input_dev->keybit); + set_bit(KEY_CUST_12, ts->input_dev->keybit); + set_bit(KEY_CUST_13, ts->input_dev->keybit); + set_bit(KEY_CUST_14, ts->input_dev->keybit); + set_bit(KEY_CUST_15, ts->input_dev->keybit); +#endif + set_bit(BTN_TOUCH, ts->input_dev->keybit); + + set_bit(KEY_F10, ts->input_dev->keybit); + + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + //ts->input_dev->mtsize = ts->nFinger_support; + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, + 0, 3, 0, 0); + } else {/* PROTOCOL_TYPE_B */ + set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); + input_mt_init_slots(ts->input_dev, ts->nFinger_support,0); + } + + I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0); + +// input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0); +// input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0); + + return input_register_device(ts->input_dev); +} + +static void calcDataSize(uint8_t finger_num) +{ + struct himax_ts_data *ts_data = private_ts; + ts_data->coord_data_size = 4 * finger_num; + ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4; + ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1; + ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel * ts_data->y_channel + + ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size + + (((uint32_t)ts_data->x_channel * ts_data->y_channel + + ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size)? 1 : 0; + I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes); +} + +static void calculate_point_number(void) +{ + HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4 ; + + if ( (ic_data->HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4 ; + else + HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) +1) * 4 ; +} + +#if 0 +static int himax_read_Sensor_ID(struct i2c_client *client) +{ + uint8_t val_high[1], val_low[1], ID0=0, ID1=0; + char data[3]; + const int normalRetry = 10; + int sensor_id; + + data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + //read id pin high + i2c_himax_read(client, 0x57, val_high, 1, normalRetry); + + data[0] = 0x56; data[1] = 0x01; data[2] = 0x01;/*ID pin PULL Low*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + //read id pin low + i2c_himax_read(client, 0x57, val_low, 1, normalRetry); + + if((val_high[0] & 0x01) ==0) + ID0=0x02;/*GND*/ + else if((val_low[0] & 0x01) ==0) + ID0=0x01;/*Floating*/ + else + ID0=0x04;/*VCC*/ + + if((val_high[0] & 0x02) ==0) + ID1=0x02;/*GND*/ + else if((val_low[0] & 0x02) ==0) + ID1=0x01;/*Floating*/ + else + ID1=0x04;/*VCC*/ + if((ID0==0x04)&&(ID1!=0x04)) + { + data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/*ID pin PULL High,Low*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + } + else if((ID0!=0x04)&&(ID1==0x04)) + { + data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/*ID pin PULL Low,High*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + } + else if((ID0==0x04)&&(ID1==0x04)) + { + data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High,High*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + } + sensor_id=(ID1<<4)|ID0; + + data[0] = 0xE4; data[1] = sensor_id; + i2c_himax_master_write(client, &data[0],2,normalRetry);/*Write to MCU*/ + usleep_range(1000, 2000); + + return sensor_id; + +} +#endif +static void himax_power_on_initCMD(struct i2c_client *client) +{ + I("%s:\n", __func__); + + himax_touch_information(client); + + //himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM +} + +#ifdef HX_AUTO_UPDATE_FW +static int i_update_FW(void) +{ + int upgrade_times = 0; + unsigned char* ImageBuffer = i_CTPM_FW; + int fullFileLength = sizeof(i_CTPM_FW); + int i_FW_VER = 0, i_CFG_VER = 0; + uint8_t ret = -1, result = 0; +// uint8_t tmp_addr[4]; +// uint8_t tmp_data[4]; + int CRC_from_FW = 0; + int CRC_Check_result = 0; + + i_FW_VER = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; + i_CFG_VER = i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR]; + + I("%s: i_fullFileLength = %d\n", __func__,fullFileLength); + + himax_sense_off(private_ts->client); + msleep(500); + + CRC_from_FW = himax_check_CRC(private_ts->client,fw_image_64k); + CRC_Check_result = Calculate_CRC_with_AP(ImageBuffer, CRC_from_FW,fw_image_64k); + I("%s: Check sum result = %d\n", __func__,CRC_Check_result); + //I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", __func__,ic_data->vendor_fw_ver, i_FW_VER); + //I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", __func__,ic_data->vendor_config_ver, i_CFG_VER); + + if ((CRC_Check_result == 0)|| ( ic_data->vendor_fw_ver < i_FW_VER ) || ( ic_data->vendor_config_ver < i_CFG_VER )) + { + himax_int_enable(private_ts->client->irq,0); +update_retry: + if(fullFileLength == FW_SIZE_60k){ + ret = fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,ImageBuffer,fullFileLength,false); + }else if (fullFileLength == FW_SIZE_64k){ + ret = fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,ImageBuffer,fullFileLength,false); + }else if (fullFileLength == FW_SIZE_124k){ + ret = fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,ImageBuffer,fullFileLength,false); + }else if (fullFileLength == FW_SIZE_128k){ + ret = fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,ImageBuffer,fullFileLength,false); + } + if(ret == 0){ + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", __func__, upgrade_times); + if(upgrade_times < 3) + goto update_retry; + else + { + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + result = -1;//upgrade fail + } + } + else if(ret == 1){ +/* + // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); + + // 2. Write driver initial code condition + // write value from AHB I2C : 0x8001_C603 = 0x000000FF + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xFF; + himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); + + // 1. Set DDREG_Req = 0 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); +*/ + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + + ic_data->vendor_fw_ver = i_FW_VER; + ic_data->vendor_config_ver = i_CFG_VER; + result = 1;//upgrade success + I("%s: TP upgrade OK\n", __func__); + } + + himax_int_enable(private_ts->client->irq,1); + return result; + } + else + { + himax_sense_on(private_ts->client, 0x01); + return 0;//NO upgrade + } +} +#endif + +#ifdef HX_RST_PIN_FUNC +void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + return; + if (ts->rst_gpio) { + if(int_off) + { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq,0); + else { + hrtimer_cancel(&ts->timer); + ret = cancel_work_sync(&ts->work); + } + } + + I("%s: Now reset the Touch chip.\n", __func__); + + himax_rst_gpio_set(ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(ts->rst_gpio, 1); + msleep(20); + + if(loadconfig) + himax_loadSensorConfig(private_ts->client,private_ts->pdata); + + if(int_off) + { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq,1); + else + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + } +} +#endif + +int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata) +{ + + if (!client) { + E("%s: Necessary parameters client are null!\n", __func__); + return -EINVAL; + } + + if(config_load == false) + { + config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); + if (config_selected == NULL) { + E("%s: alloc config_selected fail!\n", __func__); + return -ENOMEM; + } + } + + himax_power_on_initCMD(client); + + himax_int_enable(client->irq,0); + himax_read_FW_ver(client); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + himax_int_enable(client->irq,1); + I("FW_VER : %X \n",ic_data->vendor_fw_ver); + + ic_data->vendor_sensor_id=0x2602; + I("sensor_id=%x.\n",ic_data->vendor_sensor_id); + + himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + I("%s: initialization complete\n", __func__); + + return 1; +} + +#ifdef HX_ESD_WORKAROUND +void ESD_HW_REST(void) +{ + I("START_Himax TP: ESD - Reset\n"); + + HX_report_ESD_event(); + ESD_00_counter = 0; + ESD_00_Flag = 0; + /*************************************/ + if (private_ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(private_ts->input_dev); + input_report_key(private_ts->input_dev, BTN_TOUCH, 0); + input_sync(private_ts->input_dev); + /*************************************/ + + I("END_Himax TP: ESD - Reset\n"); +} +#endif +#ifdef HX_HIGH_SENSE +void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable) +{ + uint8_t tmp_data[4]; + + if(HSEN_enable) + { + I(" %s in", __func__); + HSEN_bit_retry: + himax_set_HSEN_enable(client,HSEN_enable); + msleep(20); + himax_get_HSEN_enable(client,tmp_data); + I("%s: Read HSEN bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + if(tmp_data[0]!= 0x01) + { + I("%s: retry HSEN bit write data[0]=%x \n",__func__,tmp_data[0]); + goto HSEN_bit_retry; + } + } +} + +static void himax_HSEN_func(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, + hsen_work.work); + + himax_set_HSEN_func(ts->client, ts->HSEN_enable); +} + +#endif + +#ifdef HX_SMART_WAKEUP +#ifdef HX_GESTURE_TRACK +static void gest_pt_log_coordinate(int rx, int tx) +{ + //driver report x y with range 0 - 255 , we scale it up to x/y pixel + gest_pt_x[gest_pt_cnt] = rx*(ic_data->HX_X_RES)/255; + gest_pt_y[gest_pt_cnt] = tx*(ic_data->HX_Y_RES)/255; +} +#endif +static int himax_parse_wake_event(struct himax_ts_data *ts) +{ + uint8_t buf[64]; + unsigned char check_sum_cal = 0; +#ifdef HX_GESTURE_TRACK + int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF; + int gest_len; +#endif + int i=0, check_FC = 0, gesture_flag = 0; + + himax_burst_enable(ts->client, 0); + himax_read_event_stack(ts->client,buf,56); + + for(i=0;i<GEST_PTLG_ID_LEN;i++) + { + if (check_FC==0) + { + if((buf[0]!=0x00)&&((buf[0]<=0x0F)||(buf[0]==0x80))) + { + check_FC = 1; + gesture_flag = buf[i]; + } + else + { + check_FC = 0; + I("ID START at %x , value = %x skip the event\n", i, buf[i]); + break; + } + } + else + { + if(buf[i]!=gesture_flag) + { + check_FC = 0; + I("ID NOT the same %x != %x So STOP parse event\n", buf[i], gesture_flag); + break; + } + } + + I("0x%2.2X ", buf[i]); + if (i % 8 == 7) + I("\n"); + } + I("Himax gesture_flag= %x\n",gesture_flag ); + I("Himax check_FC is %d\n", check_FC); + + if (check_FC == 0) + return 0; + if(buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 || + buf[GEST_PTLG_ID_LEN+1] != GEST_PTLG_HDR_ID2) + return 0; + for(i=0;i<(GEST_PTLG_ID_LEN+GEST_PTLG_HDR_LEN);i++) + { + I("P[%x]=0x%2.2X \n", i, buf[i]); + I("checksum=0x%2.2X \n", check_sum_cal); + check_sum_cal += buf[i]; + } + if ((check_sum_cal != 0x00) ) + { + I(" %s : check_sum_cal: 0x%02X\n",__func__ ,check_sum_cal); + return 0; + } +#ifdef HX_GESTURE_TRACK + if(buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 && + buf[GEST_PTLG_ID_LEN+1] == GEST_PTLG_HDR_ID2) + { + gest_len = buf[GEST_PTLG_ID_LEN+2]; + + I("gest_len = %d ",gest_len); + + i = 0; + gest_pt_cnt = 0; + I("gest doornidate start \n %s",__func__); + while(i<(gest_len+1)/2) + { + gest_pt_log_coordinate(buf[GEST_PTLG_ID_LEN+4+i*2],buf[GEST_PTLG_ID_LEN+4+i*2+1]); + i++; + + I("gest_pt_x[%d]=%d \n",gest_pt_cnt,gest_pt_x[gest_pt_cnt]); + I("gest_pt_y[%d]=%d \n",gest_pt_cnt,gest_pt_y[gest_pt_cnt]); + + gest_pt_cnt +=1; + } + if(gest_pt_cnt) + { + for(i=0; i<gest_pt_cnt; i++) + { + if(tmp_max_x<gest_pt_x[i]) + tmp_max_x=gest_pt_x[i]; + if(tmp_min_x>gest_pt_x[i]) + tmp_min_x=gest_pt_x[i]; + if(tmp_max_y<gest_pt_y[i]) + tmp_max_y=gest_pt_y[i]; + if(tmp_min_y>gest_pt_y[i]) + tmp_min_y=gest_pt_y[i]; + } + I("gest_point x_min= %d, x_max= %d, y_min= %d, y_max= %d\n",tmp_min_x,tmp_max_x,tmp_min_y,tmp_max_y); + gest_start_x=gest_pt_x[0]; + gn_gesture_coor[0] = gest_start_x; + gest_start_y=gest_pt_y[0]; + gn_gesture_coor[1] = gest_start_y; + gest_end_x=gest_pt_x[gest_pt_cnt-1]; + gn_gesture_coor[2] = gest_end_x; + gest_end_y=gest_pt_y[gest_pt_cnt-1]; + gn_gesture_coor[3] = gest_end_y; + gest_width = tmp_max_x - tmp_min_x; + gn_gesture_coor[4] = gest_width; + gest_height = tmp_max_y - tmp_min_y; + gn_gesture_coor[5] = gest_height; + gest_mid_x = (tmp_max_x + tmp_min_x)/2; + gn_gesture_coor[6] = gest_mid_x; + gest_mid_y = (tmp_max_y + tmp_min_y)/2; + gn_gesture_coor[7] = gest_mid_y; + gn_gesture_coor[8] = gest_mid_x;//gest_up_x + gn_gesture_coor[9] = gest_mid_y-gest_height/2;//gest_up_y + gn_gesture_coor[10] = gest_mid_x;//gest_down_x + gn_gesture_coor[11] = gest_mid_y+gest_height/2; //gest_down_y + gn_gesture_coor[12] = gest_mid_x-gest_width/2; //gest_left_x + gn_gesture_coor[13] = gest_mid_y; //gest_left_y + gn_gesture_coor[14] = gest_mid_x+gest_width/2; //gest_right_x + gn_gesture_coor[15] = gest_mid_y; //gest_right_y + + } + + } +#endif + if(gesture_flag != 0x80) + { + if(!ts->gesture_cust_en[gesture_flag]) + { + I("%s NOT report customer key \n ",__func__); + return 0;//NOT report customer key + } + } + else + { + if(!ts->gesture_cust_en[0]) + { + I("%s NOT report report double click \n",__func__); + return 0;//NOT report power key + } + } + + if(gesture_flag == 0x80) + return EV_GESTURE_PWR; + else + return gesture_flag; +} + +void himax_wake_check_func(void) +{ + int ret_event = 0, KEY_EVENT = 0; + + ret_event = himax_parse_wake_event(private_ts); + switch (ret_event) { + case EV_GESTURE_PWR: + KEY_EVENT = KEY_POWER; + break; + case EV_GESTURE_01: + KEY_EVENT = KEY_CUST_01; + break; + case EV_GESTURE_02: + KEY_EVENT = KEY_CUST_02; + break; + case EV_GESTURE_03: + KEY_EVENT = KEY_CUST_03; + break; + case EV_GESTURE_04: + KEY_EVENT = KEY_CUST_04; + break; + case EV_GESTURE_05: + KEY_EVENT = KEY_CUST_05; + break; + case EV_GESTURE_06: + KEY_EVENT = KEY_CUST_06; + break; + case EV_GESTURE_07: + KEY_EVENT = KEY_CUST_07; + break; + case EV_GESTURE_08: + KEY_EVENT = KEY_CUST_08; + break; + case EV_GESTURE_09: + KEY_EVENT = KEY_CUST_09; + break; + case EV_GESTURE_10: + KEY_EVENT = KEY_CUST_10; + break; + case EV_GESTURE_11: + KEY_EVENT = KEY_CUST_11; + break; + case EV_GESTURE_12: + KEY_EVENT = KEY_CUST_12; + break; + case EV_GESTURE_13: + KEY_EVENT = KEY_CUST_13; + break; + case EV_GESTURE_14: + KEY_EVENT = KEY_CUST_14; + break; + case EV_GESTURE_15: + KEY_EVENT = KEY_CUST_15; + break; + } + if(ret_event) + { + I(" %s SMART WAKEUP KEY event %x press\n",__func__,KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + //msleep(100); + I(" %s SMART WAKEUP KEY event %x release\n",__func__,KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); + FAKE_POWER_KEY_SEND=true; +#ifdef HX_GESTURE_TRACK + I("gest_start_x= %d, gest_start_y= %d, gest_end_x= %d, gest_end_y= %d\n",gest_start_x,gest_start_y, + gest_end_x,gest_end_y); + I("gest_width= %d, gest_height= %d, gest_mid_x= %d, gest_mid_y= %d\n",gest_width,gest_height, + gest_mid_x,gest_mid_y); + I("gest_up_x= %d, gest_up_y= %d, gest_down_x= %d, gest_down_y= %d\n",gn_gesture_coor[8],gn_gesture_coor[9], + gn_gesture_coor[10],gn_gesture_coor[11]); + I("gest_left_x= %d, gest_left_y= %d, gest_right_x= %d, gest_right_y= %d\n",gn_gesture_coor[12],gn_gesture_coor[13], + gn_gesture_coor[14],gn_gesture_coor[15]); +#endif + } +} + +#endif +static void himax_ts_button_func(int tp_key_index,struct himax_ts_data *ts) +{ + uint16_t x_position = 0, y_position = 0; +if ( tp_key_index != 0x00) + { + I("virtual key index =%x\n",tp_key_index); + if ( tp_key_index == 0x01) { + vk_press = 1; + I("back key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[0].index) { + x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2; + y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_BACK, 1); + } + else if ( tp_key_index == 0x02) { + vk_press = 1; + I("home key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[1].index) { + x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2; + y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_HOME, 1); + } + else if ( tp_key_index == 0x04) { + vk_press = 1; + I("APP_switch key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[2].index) { + x_position = (ts->button[2].x_range_min + ts->button[2].x_range_max) / 2; + y_position = (ts->button[2].y_range_min + ts->button[2].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_F10, 1); + } + input_sync(ts->input_dev); + } +else/*tp_key_index =0x00*/ + { + I("virtual key released\n"); + vk_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_mt_sync(ts->input_dev); + } + else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + input_report_key(ts->input_dev, KEY_BACK, 0); + input_report_key(ts->input_dev, KEY_HOME, 0); + input_report_key(ts->input_dev, KEY_F10, 0); + input_sync(ts->input_dev); + } +} + +void himax_ts_work(struct himax_ts_data *ts) +{ + int ret = 0; + uint8_t finger_num, hw_reset_check[2]; + uint8_t buf[128]; + uint8_t finger_on = 0; + int32_t loop_i; + uint16_t check_sum_cal = 0; + int raw_cnt_max ; + int raw_cnt_rmd ; + int hx_touch_info_size; + uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; + +#ifdef HX_TP_PROC_DIAG + int16_t *mutual_data; + int16_t *self_data; + uint8_t diag_cmd; + int i; + int mul_num; + int self_num; + int RawDataLen = 0; + //coordinate dump start + char coordinate_char[15+(ic_data->HX_MAX_PT+5)*2*5+2]; + //coordinate dump end +#endif + + memset(buf, 0x00, sizeof(buf)); + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + + raw_cnt_max = ic_data->HX_MAX_PT/4; + raw_cnt_rmd = ic_data->HX_MAX_PT%4; + +#if defined(HX_USB_DETECT2) + himax_cable_detect_func(); +#endif + + if (raw_cnt_rmd != 0x00) //more than 4 fingers + { + RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+2)*4; + } + else //less than 4 fingers + { + RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+1)*4; + } + +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if( diag_cmd ){ + ret = read_event_stack(ts->client, buf, 128); + } + else{ + if(touch_monitor_stop_flag != 0){ + ret = read_event_stack(ts->client, buf, 128); + touch_monitor_stop_flag-- ; + } + else{ + ret = read_event_stack(ts->client, buf, hx_touch_info_size); + } + } + + if (!ret) +#else + if(!read_event_stack(ts->client, buf, hx_touch_info_size)) +#endif + { + E("%s: can't read data from chip!\n", __func__); + goto err_workqueue_out; + } + post_read_event_stack(ts->client); +#ifdef HX_ESD_WORKAROUND + for(i = 0; i < hx_touch_info_size; i++) + { + if(buf[i] == 0xED)/*case 1 ESD recovery flow*/ + { + check_sum_cal = 1; + + }else if(buf[i] == 0x00) + { + ESD_00_Flag = 1; + } + else + { + check_sum_cal = 0; + ESD_00_counter = 0; + ESD_00_Flag = 0; + i = hx_touch_info_size; + break; + } + } + if (ESD_00_Flag == 1){ + ESD_00_counter ++; + } + if (ESD_00_counter > 1){ + check_sum_cal = 2; + } + + if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) + { + I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); + ESD_HW_REST(); + return; + } + + if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) + { + I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); + ESD_HW_REST(); + return; + } + else if (HX_ESD_RESET_ACTIVATE) + { +#ifdef HX_SMART_WAKEUP + queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(50)); +#endif +#ifdef HX_HIGH_SENSE + queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(50)); +#endif + HX_ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ + I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__); + } +#endif + for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++) + check_sum_cal += buf[loop_i]; + + if ((check_sum_cal % 0x100 != 0) ) + { + I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal); + return; + } + + if (ts->debug_log_level & BIT(0)) { + I("%s: raw data:\n", __func__); + for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { + I("P %d = 0x%2.2X ", loop_i, buf[loop_i]); + if (loop_i % 8 == 7) + I("\n"); + } + } + + //touch monitor raw data fetch +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if (diag_cmd >= 1 && diag_cmd <= 6) + { + //Check 124th byte CRC + if(!diag_check_sum(hx_touch_info_size, buf)) + { + goto bypass_checksum_failed_packet; + } +#ifdef HX_TP_PROC_2T2R + if(Is_2T2R && diag_cmd == 4) + { + mutual_data = getMutualBuffer_2(); + self_data = getSelfBuffer(); + + // initiallize the block number of mutual and self + mul_num = getXChannel_2() * getYChannel_2(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel_2() + getYChannel_2() + ic_data->HX_BT_NUM; +#else + self_num = getXChannel_2() + getYChannel_2(); +#endif + } + else +#endif + { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + + // initiallize the block number of mutual and self + mul_num = getXChannel() * getYChannel(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel() + getYChannel() + ic_data->HX_BT_NUM; +#else + self_num = getXChannel() + getYChannel(); +#endif + } + + diag_parse_raw_data(hx_touch_info_size, RawDataLen, mul_num, self_num, buf, diag_cmd, mutual_data, self_data); + + } + else if (diag_cmd == 7) + { + memcpy(&(diag_coor[0]), &buf[0], 128); + } + //coordinate dump start + if (coordinate_dump_enable == 1) + { + for(i=0; i<(15 + (ic_data->HX_MAX_PT+5)*2*5); i++) + { + coordinate_char[i] = 0x20; + } + coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5] = 0xD; + coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5 + 1] = 0xA; + } + //coordinate dump end +bypass_checksum_failed_packet: +#endif + EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>3); + //I("EN_NoiseFilter=%d\n",EN_NoiseFilter); + EN_NoiseFilter = EN_NoiseFilter & 0x01; + //I("EN_NoiseFilter2=%d\n",EN_NoiseFilter); + +#if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) + tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>4); + if (tpd_key == 0x0F)/*All (VK+AA)leave*/ + { + tpd_key = 0x00; + } + //I("[DEBUG] tpd_key: %x\r\n", tpd_key); +#else + tpd_key = 0x00; +#endif + + p_point_num = hx_point_num; + + if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + hx_point_num = 0; + else + hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; + + // Touch Point information + if (hx_point_num != 0 ) { + if(vk_press == 0x00) + { + uint16_t old_finger = ts->pre_finger_mask; + ts->pre_finger_mask = 0; + finger_num = buf[coordInfoSize - 4] & 0x0F; + finger_on = 1; + AA_press = 1; + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + int base = loop_i * 4; + int x = buf[base] << 8 | buf[base + 1]; + int y = (buf[base + 2] << 8 | buf[base + 3]); + int w = buf[(ts->nFinger_support * 4) + loop_i]; + if(x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 && y <= ts->pdata->abs_y_max){ + finger_num--; + + if ((ts->debug_log_level & BIT(3)) > 0) + { + if (old_finger >> loop_i == 0) + { + if (ts->useScreenRes) + { + I("status: Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", + loop_i+1, x * ts->widthFactor >> SHIFTBITS, + y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter); + } + else + { + I("status: Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", + loop_i+1, x, y, w, EN_NoiseFilter); + } + } + } + + if (ts->protocol_type == PROTOCOL_TYPE_B) + { + input_mt_slot(ts->input_dev, loop_i); + } + + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); + + if (ts->protocol_type == PROTOCOL_TYPE_A) + { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i); + input_mt_sync(ts->input_dev); + } + else + { + ts->last_slot = loop_i; + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); + } + + if (!ts->first_pressed) + { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); + } + + ts->pre_finger_data[loop_i][0] = x; + ts->pre_finger_data[loop_i][1] = y; + + + if (ts->debug_log_level & BIT(1)) + I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n", + loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter); + + ts->pre_finger_mask = ts->pre_finger_mask + (1 << loop_i); + + } else { + if (ts->protocol_type == PROTOCOL_TYPE_B) + { + input_mt_slot(ts->input_dev, loop_i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + + if (loop_i == 0 && ts->first_pressed == 1) + { + ts->first_pressed = 2; + I("E1@%d, %d\n", + ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); + } + if ((ts->debug_log_level & BIT(3)) > 0) + { + if (old_finger >> loop_i == 1) + { + if (ts->useScreenRes) + { + I("status: Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", + loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); + } + else + { + I("status: Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", + loop_i+1, ts->pre_finger_data[loop_i][0], + ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); + } + } + } + } + } + + }else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { + //temp_x[0] = 0xFFFF; + //temp_y[0] = 0xFFFF; + //temp_x[1] = 0xFFFF; + //temp_y[1] = 0xFFFF; + himax_ts_button_func(tpd_key,ts); + finger_on = 0; + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if (hx_point_num == 0){ + if(AA_press) + { + // leave event + finger_on = 0; + AA_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { + if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, loop_i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + } + } + if (ts->pre_finger_mask > 0) { + for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) { + if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { + if (ts->useScreenRes) { + I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); + } else { + I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); + } + } + } + ts->pre_finger_mask = 0; + } + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n",ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); + } + + if (ts->debug_log_level & BIT(1)) + I("All Finger leave\n"); + + } + else if (tpd_key != 0x00) { + himax_ts_button_func(tpd_key,ts); + finger_on = 1; + } + else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { + himax_ts_button_func(tpd_key,ts); + finger_on = 0; + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } + tpd_key_old = tpd_key; + Last_EN_NoiseFilter = EN_NoiseFilter; + +workqueue_out: + return; + +err_workqueue_out: + I("%s: Now reset the Touch chip.\n", __func__); + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + + goto workqueue_out; +} +enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) +{ + struct himax_ts_data *ts; + + ts = container_of(timer, struct himax_ts_data, timer); + queue_work(ts->himax_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#if defined(HX_USB_DETECT) +static void himax_cable_tp_status_handler_func(int connect_status) +{ + struct himax_ts_data *ts; + I("Touch: cable change to %d\n", connect_status); + ts = private_ts; + if (ts->cable_config) { + if (!atomic_read(&ts->suspend_mode)) { + if ((!!connect_status) != ts->usb_connected) { + if (!!connect_status) { + ts->cable_config[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->cable_config[1] = 0x00; + ts->usb_connected = 0x00; + } + + i2c_himax_master_write(ts->client, ts->cable_config, + sizeof(ts->cable_config), HIMAX_I2C_RETRY_TIMES); + + I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]); + } else + I("%s: Cable status is the same as previous one, ignore.\n", __func__); + } else { + if (connect_status) + ts->usb_connected = 0x01; + else + ts->usb_connected = 0x00; + I("%s: Cable status remembered: 0x%2.2X\n", __func__, ts->usb_connected); + } + } +} + +static struct t_cable_status_notifier himax_cable_status_handler = { + .name = "usb_tp_connected", + .func = himax_cable_tp_status_handler_func, +}; + +#endif + +#if defined(HX_USB_DETECT2) +void himax_cable_detect_func(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + struct himax_ts_data *ts; + u32 connect_status = 0; + + connect_status = USB_Flag;//upmu_is_chr_det(); + ts = private_ts; + //I("Touch: cable status=%d, cable_config=%p, usb_connected=%d \n", connect_status,ts->cable_config, ts->usb_connected); + if (ts->cable_config) { + if ((!!connect_status) != ts->usb_connected) { + //notify USB plug/unplug + // 0x9008_8060 ==> 0x0000_0000/0001 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; + + if (!!connect_status) { + tmp_data[0] = 0x01; + ts->usb_connected = 0x01; + } else { + tmp_data[0] = 0x00; + ts->usb_connected = 0x00; + } + + himax_flash_write_burst(ts->client, tmp_addr, tmp_data); + + I("%s: Cable status change: 0x%2.2X\n", __func__, ts->usb_connected); + } + //else + //I("%s: Cable status is the same as previous one, ignore.\n", __func__); + } +} +#endif + +#ifdef CONFIG_FB +int himax_fb_register(struct himax_ts_data *ts) +{ + int ret = 0; + + I(" %s in", __func__); + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); + if (ret) + E(" Unable to register fb_notifier: %d\n", ret); + + return ret; +} +#endif + +#ifdef HX_SMART_WAKEUP +void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable) +{ + uint8_t tmp_data[4]; + + if(SMWP_enable) + { + SMWP_bit_retry: + himax_set_SMWP_enable(client, SMWP_enable); + msleep(20); + himax_get_SMWP_enable(client,tmp_data); + I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + if(tmp_data[0]!= 0x01) + { + I("%s: retry SMWP bit write data[0]=%x \n",__func__,tmp_data[0]); + goto SMWP_bit_retry; + } + } +} + +static void himax_SMWP_work(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, + smwp_work.work); + I(" %s in", __func__); + + himax_set_SMWP_func(ts->client,ts->SMWP_enable); + +} +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP +static void himax_ts_flash_work_func(struct work_struct *work) +{ + himax_ts_flash_func(); +} +#endif + +#ifdef HX_TP_PROC_DIAG +static void himax_ts_diag_work_func(struct work_struct *work) +{ + himax_ts_diag_func(); +} +#endif + +void himax_ts_init(struct himax_ts_data *ts) +{ + int ret = 0, err = 0; + struct himax_i2c_platform_data *pdata; + struct i2c_client *client; + + client = ts->client; + pdata = ts->pdata; + + I("%s: Start.\n", __func__); + + /* Set pinctrl in active state */ + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (ret < 0) { + E("Failed to set pin in active state %d",ret); + } + } + + himax_burst_enable(client, 0); + + //Get Himax IC Type / FW information / Calculate the point number + if (himax_check_chip_version(ts->client) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + if (himax_ic_package_check(ts->client) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + + if (pdata->virtual_key) + ts->button = pdata->virtual_key; +#ifdef HX_TP_PROC_FLASH_DUMP + ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); + if (!ts->flash_wq) + { + E("%s: create flash workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_wq_failed; + } + + INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); + + setSysOperation(0); + setFlashBuffer(); +#endif + +#ifdef HX_TP_PROC_DIAG + ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); + if (!ts->himax_diag_wq) + { + E("%s: create diag workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_wq_failed; + } + INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func); +#endif + +himax_read_FW_ver(client); + +#ifdef HX_AUTO_UPDATE_FW + I(" %s in", __func__); + if(i_update_FW() == false) + I("NOT Have new FW=NOT UPDATE=\n"); + else + I("Have new FW=UPDATE=\n"); +#endif + + //Himax Power On and Load Config + if (himax_loadSensorConfig(client, pdata) < 0) { + E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); + goto err_detect_failed; + } + + calculate_point_number(); +#ifdef HX_TP_PROC_DIAG + setXChannel(ic_data->HX_RX_NUM); // X channel + setYChannel(ic_data->HX_TX_NUM); // Y channel + + setMutualBuffer(); + setMutualNewBuffer(); + setMutualOldBuffer(); + if (getMutualBuffer() == NULL) { + E("%s: mutual buffer allocate fail failed\n", __func__); + return; + } +#ifdef HX_TP_PROC_2T2R + if(Is_2T2R){ + setXChannel_2(ic_data->HX_RX_NUM_2); // X channel + setYChannel_2(ic_data->HX_TX_NUM_2); // Y channel + + setMutualBuffer_2(); + + if (getMutualBuffer_2() == NULL) { + E("%s: mutual buffer 2 allocate fail failed\n", __func__); + return; + } + } +#endif +#endif +#ifdef CONFIG_OF + ts->power = pdata->power; +#endif + ts->pdata = pdata; + + ts->x_channel = ic_data->HX_RX_NUM; + ts->y_channel = ic_data->HX_TX_NUM; + ts->nFinger_support = ic_data->HX_MAX_PT; + //calculate the i2c data size + calcDataSize(ts->nFinger_support); + I("%s: calcDataSize complete\n", __func__); +#ifdef CONFIG_OF + ts->pdata->abs_pressure_min = 0; + ts->pdata->abs_pressure_max = 200; + ts->pdata->abs_width_min = 0; + ts->pdata->abs_width_max = 200; + pdata->cable_config[0] = 0x90; + pdata->cable_config[1] = 0x00; +#endif + ts->suspended = false; +#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + ts->cable_config = pdata->cable_config; +#endif + ts->protocol_type = pdata->protocol_type; + I("%s: Use Protocol Type %c\n", __func__, + ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); + + ret = himax_input_register(ts); + if (ret) { + E("%s: Unable to register %s input device\n", + __func__, ts->input_dev->name); + goto err_input_register_device_failed; + } +#ifdef HX_SMART_WAKEUP + ts->SMWP_enable=0; + wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX_common_NAME); + + ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK"); + if (!ts->himax_smwp_wq) { + E(" allocate himax_smwp_wq failed\n"); + err = -ENOMEM; + goto err_smwp_wq_failed; + } + INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work); +#endif +#ifdef HX_HIGH_SENSE + ts->HSEN_enable=0; + ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK"); + if (!ts->himax_hsen_wq) { + E(" allocate himax_hsen_wq failed\n"); + err = -ENOMEM; + goto err_hsen_wq_failed; + } + INIT_DELAYED_WORK(&ts->hsen_work, himax_HSEN_func); +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_init(); +#endif + +#if defined(HX_USB_DETECT) + if (ts->cable_config) + cable_detect_register_notifier(&himax_cable_status_handler); +#endif + + err = himax_ts_register_interrupt(ts->client); + if (err) + goto err_register_interrupt_failed; + return; + +err_register_interrupt_failed: +#ifdef HX_HIGH_SENSE +err_hsen_wq_failed: +#endif +#ifdef HX_SMART_WAKEUP +err_smwp_wq_failed: + wake_lock_destroy(&ts->ts_SMWP_wake_lock); +#endif +err_input_register_device_failed: + input_free_device(ts->input_dev); +err_detect_failed: +#ifdef HX_TP_PROC_FLASH_DUMP +err_create_wq_failed: +#endif +err_ic_package_failed: + +return; +} + +int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = 0; + struct himax_ts_data *ts; + struct himax_i2c_platform_data *pdata; + + //Check I2C functionality + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + E("%s: i2c check functionality error\n", __func__); + err = -ENODEV; + goto err_check_functionality_failed; + } + + ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); + if (ts == NULL) { + E("%s: allocate himax_ts_data failed\n", __func__); + err = -ENOMEM; + goto err_alloc_data_failed; + } + + i2c_set_clientdata(client, ts); + ts->client = client; + ts->dev = &client->dev; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (pdata == NULL) { /*Allocate Platform data space*/ + err = -ENOMEM; + goto err_dt_platform_data_fail; + } + + ic_data = kzalloc(sizeof(*ic_data), GFP_KERNEL); + if (ic_data == NULL) { /*Allocate IC data space*/ + err = -ENOMEM; + goto err_dt_ic_data_fail; + } + +#ifdef CONFIG_OF + if (client->dev.of_node) { /*DeviceTree Init Platform_data*/ + err = himax_parse_dt(ts, pdata); + if (err < 0) { + I(" pdata is NULL for DT\n"); + goto err_alloc_dt_pdata_failed; + } + } +#endif + +#ifdef HX_RST_PIN_FUNC + ts->rst_gpio = pdata->gpio_reset; +#endif + +himax_gpio_power_config(ts->client, pdata); + + err = himax_ts_pinctrl_init(ts); + if (err || ts->ts_pinctrl == NULL) { + E(" Pinctrl init failed\n"); + } + +#ifndef CONFIG_OF + if (pdata->power) { + err = pdata->power(1); + if (err < 0) { + E("%s: power on failed\n", __func__); + goto err_power_failed; + } + } +#endif + ts->pdata = pdata; + private_ts = ts; + + mutex_init(&ts->fb_mutex); + /* ts initialization is deferred till FB_UNBLACK event; + * probe is considered pending till then.*/ + ts->probe_done = false; +#ifdef CONFIG_FB + err = himax_fb_register(ts); + if (err) { + E("Falied to register fb notifier\n"); + err = -ENOMEM; + goto err_fb_notif_wq_create; + } +#endif + + return 0; + +#ifdef CONFIG_FB +err_fb_notif_wq_create: +#endif +#ifdef CONFIG_OF +err_alloc_dt_pdata_failed: +#else +err_power_failed: +err_get_platform_data_fail: +#endif + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + err = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (err) + E("failed to select relase pinctrl state %d\n", + err); + } + } + kfree(ic_data); + +err_dt_ic_data_fail: + kfree(pdata); + +err_dt_platform_data_fail: + kfree(ts); + +err_alloc_data_failed: + +err_check_functionality_failed: + probe_fail_flag = 1; + return err; + +} + +int himax_chip_common_remove(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret; +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_deinit(); +#endif +#ifdef CONFIG_FB + if (fb_unregister_client(&ts->fb_notif)) + dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); +#endif + + if (!ts->use_irq) + hrtimer_cancel(&ts->timer); + + destroy_workqueue(ts->himax_wq); + + if (ts->protocol_type == PROTOCOL_TYPE_B) + input_mt_destroy_slots(ts->input_dev); + + input_unregister_device(ts->input_dev); + + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (ret) + E("failed to select relase pinctrl state %d\n", + ret); + } + } +#ifdef HX_SMART_WAKEUP + wake_lock_destroy(&ts->ts_SMWP_wake_lock); +#endif + kfree(ts); + + return 0; + +} + +int himax_chip_common_suspend(struct himax_ts_data *ts) +{ + int ret; + + if(ts->suspended) + { + I("%s: Already suspended. Skipped. \n", __func__); + return 0; + } + else + { + ts->suspended = true; + I("%s: enter \n", __func__); + } + +#ifdef HX_TP_PROC_FLASH_DUMP + if (getFlashDumpGoing()) + { + I("[himax] %s: Flash dump is going, reject suspend\n",__func__); + return 0; + } +#endif +#ifdef HX_TP_PROC_HITOUCH + if(hitouch_is_connect) + { + I("[himax] %s: Hitouch connect, reject suspend\n",__func__); + return 0; + } +#endif +#ifdef HX_SMART_WAKEUP + if(ts->SMWP_enable) + { + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + FAKE_POWER_KEY_SEND=false; + I("[himax] %s: SMART_WAKEUP enable, reject suspend\n",__func__); + return 0; + } +#endif +#ifdef HX_ESD_WORKAROUND + ESD_00_counter = 0; + ESD_00_Flag = 0; +#endif + if (!ts->use_irq) { + ret = cancel_work_sync(&ts->work); + if (ret) + himax_int_enable(ts->client->irq,1); + } + + //ts->first_pressed = 0; + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_suspend); + if (ret < 0) { + E("Failed to get idle pinctrl state %d\n", ret); + } + } + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + + return 0; +} + +int himax_chip_common_resume(struct himax_ts_data *ts) +{ + int retval; + + I("%s: enter \n", __func__); + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(1); + + + /*************************************/ + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_sync(ts->input_dev); + /*************************************/ + + + if (ts->ts_pinctrl) { + retval = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (retval < 0) { + E("Cannot get default pinctrl state %d\n", retval); + goto err_pinctrl_select_resume; + } + } + + atomic_set(&ts->suspend_mode, 0); + + himax_int_enable(ts->client->irq,1); + + ts->suspended = false; +#if defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + himax_cable_detect_func(); +#endif +#ifdef HX_SMART_WAKEUP + queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(1000)); +#endif +#ifdef HX_HIGH_SENSE + queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(1000)); +#endif + return 0; +err_pinctrl_select_resume: + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + return retval; +} + diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h new file mode 100644 index 000000000000..27ce9aafd959 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -0,0 +1,395 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_COMMON_H +#define HIMAX_COMMON_H + +#include <asm/segment.h> +#include <asm/uaccess.h> +#include <asm/atomic.h> + +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/async.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/input/mt.h> +#include <linux/firmware.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/seq_file.h> +#include <linux/proc_fs.h> +#include "himax_platform.h" + +#if defined(CONFIG_FB) +#include <linux/notifier.h> +#include <linux/fb.h> +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include <linux/earlysuspend.h> +#endif + +#ifdef CONFIG_OF +#include <linux/of_gpio.h> +#endif +#define HIMAX_DRIVER_VER "0.2.4.0" + +#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" +#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +#define HX_TP_PROC_DIAG +#define HX_TP_PROC_REGISTER +#define HX_TP_PROC_DEBUG +#define HX_TP_PROC_FLASH_DUMP +#define HX_TP_PROC_SELF_TEST +#define HX_TP_PROC_RESET +#define HX_TP_PROC_SENSE_ON_OFF +//#define HX_TP_PROC_2T2R + +int himax_touch_proc_init(void); +void himax_touch_proc_deinit(void); +#endif + +//===========Himax Option function============= +//#define HX_RST_PIN_FUNC +//#define HX_AUTO_UPDATE_FW +//#define HX_HIGH_SENSE +//#define HX_SMART_WAKEUP +//#define HX_USB_DETECT +//#define HX_ESD_WORKAROUND +//#define HX_USB_DETECT2 + +//#define HX_EN_SEL_BUTTON // Support Self Virtual key ,default is close +#define HX_EN_MUT_BUTTON // Support Mutual Virtual Key ,default is close + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 + +#define HX_VKEY_0 KEY_BACK +#define HX_VKEY_1 KEY_HOME +#define HX_VKEY_2 KEY_RESERVED +#define HX_VKEY_3 KEY_RESERVED +#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} + +#define SHIFTBITS 5 +//#define FLASH_SIZE 131072 +#define FW_SIZE_60k 61440 +#define FW_SIZE_64k 65536 +#define FW_SIZE_124k 126976 +#define FW_SIZE_128k 131072 + +struct himax_ic_data { + int vendor_fw_ver; + int vendor_config_ver; + int vendor_sensor_id; + int HX_RX_NUM; + int HX_TX_NUM; + int HX_BT_NUM; + int HX_X_RES; + int HX_Y_RES; + int HX_MAX_PT; + bool HX_XY_REVERSE; + bool HX_INT_IS_EDGE; +#ifdef HX_TP_PROC_2T2R + int HX_RX_NUM_2; + int HX_TX_NUM_2; +#endif +}; + +struct himax_virtual_key { + int index; + int keycode; + int x_range_min; + int x_range_max; + int y_range_min; + int y_range_max; +}; + +struct himax_config { + uint8_t default_cfg; + uint8_t sensor_id; + uint8_t fw_ver; + uint16_t length; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + uint8_t c1[11]; + uint8_t c2[11]; + uint8_t c3[11]; + uint8_t c4[11]; + uint8_t c5[11]; + uint8_t c6[11]; + uint8_t c7[11]; + uint8_t c8[11]; + uint8_t c9[11]; + uint8_t c10[11]; + uint8_t c11[11]; + uint8_t c12[11]; + uint8_t c13[11]; + uint8_t c14[11]; + uint8_t c15[11]; + uint8_t c16[11]; + uint8_t c17[11]; + uint8_t c18[17]; + uint8_t c19[15]; + uint8_t c20[5]; + uint8_t c21[11]; + uint8_t c22[4]; + uint8_t c23[3]; + uint8_t c24[3]; + uint8_t c25[4]; + uint8_t c26[2]; + uint8_t c27[2]; + uint8_t c28[2]; + uint8_t c29[2]; + uint8_t c30[2]; + uint8_t c31[2]; + uint8_t c32[2]; + uint8_t c33[2]; + uint8_t c34[2]; + uint8_t c35[3]; + uint8_t c36[5]; + uint8_t c37[5]; + uint8_t c38[9]; + uint8_t c39[14]; + uint8_t c40[159]; + uint8_t c41[99]; +}; + +struct himax_ts_data { + bool suspended; + bool probe_done; + struct mutex fb_mutex; + atomic_t suspend_mode; + uint8_t x_channel; + uint8_t y_channel; + uint8_t useScreenRes; + uint8_t diag_command; + + uint8_t protocol_type; + uint8_t first_pressed; + uint8_t coord_data_size; + uint8_t area_data_size; + uint8_t raw_data_frame_size; + uint8_t raw_data_nframes; + uint8_t nFinger_support; + uint8_t irq_enabled; + uint8_t diag_self[50]; + + uint16_t finger_pressed; + uint16_t last_slot; + uint16_t pre_finger_mask; + + uint32_t debug_log_level; + uint32_t widthFactor; + uint32_t heightFactor; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + + int use_irq; + int (*power)(int on); + int pre_finger_data[10][2]; + + struct device *dev; + struct workqueue_struct *himax_wq; + struct work_struct work; + struct input_dev *input_dev; + struct hrtimer timer; + struct i2c_client *client; + struct himax_i2c_platform_data *pdata; + struct himax_virtual_key *button; + +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + struct workqueue_struct *flash_wq; + struct work_struct flash_work; +#endif + +#ifdef HX_RST_PIN_FUNC + int rst_gpio; +#endif + +#ifdef HX_TP_PROC_DIAG + struct workqueue_struct *himax_diag_wq; + struct delayed_work himax_diag_delay_wrok; +#endif +#ifdef HX_SMART_WAKEUP + uint8_t SMWP_enable; + uint8_t gesture_cust_en[16]; + struct wake_lock ts_SMWP_wake_lock; + struct workqueue_struct *himax_smwp_wq; + struct delayed_work smwp_work; +#endif + +#ifdef HX_HIGH_SENSE + uint8_t HSEN_enable; + struct workqueue_struct *himax_hsen_wq; + struct delayed_work hsen_work; +#endif + +#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) + uint8_t usb_connected; + uint8_t *cable_config; +#endif + + /* pinctrl data */ + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + struct pinctrl_state *pinctrl_state_release; +}; + +#define HX_CMD_NOP 0x00 +#define HX_CMD_SETMICROOFF 0x35 +#define HX_CMD_SETROMRDY 0x36 +#define HX_CMD_TSSLPIN 0x80 +#define HX_CMD_TSSLPOUT 0x81 +#define HX_CMD_TSSOFF 0x82 +#define HX_CMD_TSSON 0x83 +#define HX_CMD_ROE 0x85 +#define HX_CMD_RAE 0x86 +#define HX_CMD_RLE 0x87 +#define HX_CMD_CLRES 0x88 +#define HX_CMD_TSSWRESET 0x9E +#define HX_CMD_SETDEEPSTB 0xD7 +#define HX_CMD_SET_CACHE_FUN 0xDD +#define HX_CMD_SETIDLE 0xF2 +#define HX_CMD_SETIDLEDELAY 0xF3 +#define HX_CMD_SELFTEST_BUFFER 0x8D +#define HX_CMD_MANUALMODE 0x42 +#define HX_CMD_FLASH_ENABLE 0x43 +#define HX_CMD_FLASH_SET_ADDRESS 0x44 +#define HX_CMD_FLASH_WRITE_REGISTER 0x45 +#define HX_CMD_FLASH_SET_COMMAND 0x47 +#define HX_CMD_FLASH_WRITE_BUFFER 0x48 +#define HX_CMD_FLASH_PAGE_ERASE 0x4D +#define HX_CMD_FLASH_SECTOR_ERASE 0x4E +#define HX_CMD_CB 0xCB +#define HX_CMD_EA 0xEA +#define HX_CMD_4A 0x4A +#define HX_CMD_4F 0x4F +#define HX_CMD_B9 0xB9 +#define HX_CMD_76 0x76 + +enum input_protocol_type { + PROTOCOL_TYPE_A = 0x00, + PROTOCOL_TYPE_B = 0x01, +}; + +#ifdef HX_HIGH_SENSE +void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable); +#endif + +#ifdef HX_SMART_WAKEUP +#define GEST_PTLG_ID_LEN (4) +#define GEST_PTLG_HDR_LEN (4) +#define GEST_PTLG_HDR_ID1 (0xCC) +#define GEST_PTLG_HDR_ID2 (0x44) +#define GEST_PT_MAX_NUM (128) + +#ifdef HX_GESTURE_TRACK +static int gest_pt_cnt; +static int gest_pt_x[GEST_PT_MAX_NUM]; +static int gest_pt_y[GEST_PT_MAX_NUM]; +static int gest_start_x,gest_start_y,gest_end_x,gest_end_y; +static int gest_width,gest_height,gest_mid_x,gest_mid_y; +static int gn_gesture_coor[16]; +#endif + +void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable); +extern bool FAKE_POWER_KEY_SEND; + + enum gesture_event_type { + EV_GESTURE_01 = 0x01, + EV_GESTURE_02, + EV_GESTURE_03, + EV_GESTURE_04, + EV_GESTURE_05, + EV_GESTURE_06, + EV_GESTURE_07, + EV_GESTURE_08, + EV_GESTURE_09, + EV_GESTURE_10, + EV_GESTURE_11, + EV_GESTURE_12, + EV_GESTURE_13, + EV_GESTURE_14, + EV_GESTURE_15, + EV_GESTURE_PWR = 0x80, + }; + +#define KEY_CUST_01 251 +#define KEY_CUST_02 252 +#define KEY_CUST_03 253 +#define KEY_CUST_04 254 +#define KEY_CUST_05 255 +#define KEY_CUST_06 256 +#define KEY_CUST_07 257 +#define KEY_CUST_08 258 +#define KEY_CUST_09 259 +#define KEY_CUST_10 260 +#define KEY_CUST_11 261 +#define KEY_CUST_12 262 +#define KEY_CUST_13 263 +#define KEY_CUST_14 264 +#define KEY_CUST_15 265 +#endif + +#ifdef HX_ESD_WORKAROUND + extern u8 HX_ESD_RESET_ACTIVATE; +#endif + +extern int irq_enable_count; + +#ifdef QCT +irqreturn_t himax_ts_thread(int irq, void *ptr); +int himax_input_register(struct himax_ts_data *ts); +#endif + +extern int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id); +extern int himax_chip_common_remove(struct i2c_client *client); +extern int himax_chip_common_suspend(struct himax_ts_data *ts); +extern int himax_chip_common_resume(struct himax_ts_data *ts); +int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata); + +#ifdef HX_USB_DETECT2 +//extern kal_bool upmu_is_chr_det(void); +void himax_cable_detect_func(void); +#endif + +#endif + diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c new file mode 100644 index 000000000000..f8bee11b4351 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.c @@ -0,0 +1,2329 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_debug.h" +#include "himax_ic.h" + +//struct himax_debug_data* debug_data; + +extern struct himax_ic_data* ic_data; +extern struct himax_ts_data *private_ts; +extern unsigned char IC_TYPE; +extern unsigned char IC_CHECKSUM; +extern int himax_input_register(struct himax_ts_data *ts); +#ifdef QCT +extern irqreturn_t himax_ts_thread(int irq, void *ptr); +#endif +#ifdef MTK +#ifdef CONFIG_OF_TOUCH +extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); +#else +extern void tpd_eint_interrupt_handler(void); +#endif +#endif + +#ifdef HX_TP_PROC_DIAG +#ifdef HX_TP_PROC_2T2R +int HX_RX_NUM_2 = 0; +int HX_TX_NUM_2 = 0; +#endif +int touch_monitor_stop_flag = 0; +int touch_monitor_stop_limit = 5; +uint8_t g_diag_arr_num = 0; +#endif + +#ifdef HX_ESD_WORKAROUND +u8 HX_ESD_RESET_ACTIVATE; +#endif + +#ifdef HX_SMART_WAKEUP +bool FAKE_POWER_KEY_SEND; +#endif + +//============================================================================================================= +// +// Segment : Himax PROC Debug Function +// +//============================================================================================================= +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +static ssize_t himax_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + + ret += snprintf(temp_buf, len, "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", HIMAX_common_NAME, + ic_data->vendor_fw_ver, ic_data->vendor_config_ver, ic_data->vendor_sensor_id); + HX_PROC_SEND_FLAG=1; + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static const struct file_operations himax_proc_vendor_ops = +{ + .owner = THIS_MODULE, + .read = himax_vendor_read, +}; + +static ssize_t himax_attn_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + struct himax_ts_data *ts_data; + char *temp_buf; + + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + ret += snprintf(temp_buf, len, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq)); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + + +static const struct file_operations himax_proc_attn_ops = +{ + .owner = THIS_MODULE, + .read = himax_attn_read, +}; + +static ssize_t himax_int_en_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + ret += snprintf(temp_buf, len, "%d ", ts->irq_enabled); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static ssize_t himax_int_en_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[12]= {0}; + int value, ret=0; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + + if (buf_tmp[0] == '0') + value = false; + else if (buf_tmp[0] == '1') + value = true; + else + return -EINVAL; + + if (value) { + if(ic_data->HX_INT_IS_EDGE) + { +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + himax_int_enable(ts->client->irq,1); +#else + //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); + //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); + mt_eint_registration(ts->client->irq, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); +#endif +#endif +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts); +#endif + } + else + { +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + himax_int_enable(ts->client->irq,1); +#else + //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); + //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); + mt_eint_registration(ts->client->irq, EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); +#endif +#endif +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts); +#endif + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + } + } else { + himax_int_enable(ts->client->irq,0); + free_irq(ts->client->irq, ts); + ts->irq_enabled = 0; + } + + return len; +} + +static const struct file_operations himax_proc_int_en_ops = +{ + .owner = THIS_MODULE, + .read = himax_int_en_read, + .write = himax_int_en_write, +}; + +static ssize_t himax_layout_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); + ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_x_max); + ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_min); + ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_max); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_layout_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[5]; + int i = 0, j = 0, k = 0, ret; + unsigned long value; + int layout[4] = {0}; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + for (i = 0; i < 20; i++) { + if (buf[i] == ',' || buf[i] == '\n') { + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + if (i - j <= 5) + memcpy(buf_tmp, buf + j, i - j); + else { + I("buffer size is over 5 char\n"); + return len; + } + j = i + 1; + if (k < 4) { + ret = kstrtoul(buf_tmp, 10, &value); + layout[k++] = value; + } + } + } + if (k == 4) { + ts->pdata->abs_x_min=layout[0]; + ts->pdata->abs_x_max=layout[1]; + ts->pdata->abs_y_min=layout[2]; + ts->pdata->abs_y_max=layout[3]; + I("%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + input_unregister_device(ts->input_dev); + himax_input_register(ts); + } else + I("ERR@%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + return len; +} + +static const struct file_operations himax_proc_layout_ops = +{ + .owner = THIS_MODULE, + .read = himax_layout_read, + .write = himax_layout_write, +}; + +static ssize_t himax_debug_level_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts_data; + size_t ret = 0; + char *temp_buf; + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + ret += snprintf(temp_buf, len, "%d\n", ts_data->debug_log_level); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_debug_level_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts; + char buf_tmp[11]; + int i; + ts = private_ts; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + + ts->debug_log_level = 0; + for(i=0; i<len-1; i++) + { + if( buf_tmp[i]>='0' && buf_tmp[i]<='9' ) + ts->debug_log_level |= (buf_tmp[i]-'0'); + else if( buf_tmp[i]>='A' && buf_tmp[i]<='F' ) + ts->debug_log_level |= (buf_tmp[i]-'A'+10); + else if( buf_tmp[i]>='a' && buf_tmp[i]<='f' ) + ts->debug_log_level |= (buf_tmp[i]-'a'+10); + + if(i!=len-2) + ts->debug_log_level <<= 4; + } + + if (ts->debug_log_level & BIT(3)) { + if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && + (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && + (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { + ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)/(ts->pdata->abs_x_max - ts->pdata->abs_x_min); + ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS)/(ts->pdata->abs_y_max - ts->pdata->abs_y_min); + if (ts->widthFactor > 0 && ts->heightFactor > 0) + ts->useScreenRes = 1; + else { + ts->heightFactor = 0; + ts->widthFactor = 0; + ts->useScreenRes = 0; + } + } else + I("Enable finger debug with raw position mode!\n"); + } else { + ts->useScreenRes = 0; + ts->widthFactor = 0; + ts->heightFactor = 0; + } + + return len; +} + +static const struct file_operations himax_proc_debug_level_ops = +{ + .owner = THIS_MODULE, + .read = himax_debug_level_read, + .write = himax_debug_level_write, +}; + +#ifdef HX_TP_PROC_REGISTER +static ssize_t himax_proc_register_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + uint16_t loop_i; + uint8_t data[128]; + char *temp_buf; + + memset(data, 0x00, sizeof(data)); + + I("himax_register_show: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + himax_register_read(private_ts->client, register_command, 1, data); + + ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + + for (loop_i = 0; loop_i < 128; loop_i++) { + ret += snprintf(temp_buf+ret, len-ret, "0x%2.2X ", data[loop_i]); + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf+ret, len-ret, "\n"); + } + ret += snprintf(temp_buf+ret, len-ret, "\n"); + HX_PROC_SEND_FLAG=1; + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static ssize_t himax_proc_register_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[16], length = 0; + unsigned long result = 0; + uint8_t loop_i = 0; + uint16_t base = 5; + uint8_t write_da[128]; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memset(write_da, 0x0, sizeof(write_da)); + + I("himax %s \n",buf); + + if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { + + if (buf[2] == 'x') { + memcpy(buf_tmp, buf + 3, 8); + if (!kstrtoul(buf_tmp, 16, &result)) + { + register_command[0] = (uint8_t)result; + register_command[1] = (uint8_t)(result >> 8); + register_command[2] = (uint8_t)(result >> 16); + register_command[3] = (uint8_t)(result >> 24); + } + base = 11; + I("CMD: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + + for (loop_i = 0; loop_i < 128 && (base+10)<80; loop_i++) { + if (buf[base] == '\n') { + if (buf[0] == 'w') { + himax_register_write(private_ts->client, register_command, 1, write_da); + I("CMD: %x, %x, %x, %x, len=%d\n", write_da[0], write_da[1],write_da[2],write_da[3],length); + } + I("\n"); + return len; + } + if (buf[base + 1] == 'x') { + buf_tmp[10] = '\n'; + buf_tmp[11] = '\0'; + memcpy(buf_tmp, buf + base + 2, 8); + if (!kstrtoul(buf_tmp, 16, &result)) { + write_da[loop_i] = (uint8_t)result; + write_da[loop_i+1] = (uint8_t)(result >> 8); + write_da[loop_i+2] = (uint8_t)(result >> 16); + write_da[loop_i+3] = (uint8_t)(result >> 24); + } + length+=4; + } + base += 10; + } + } + } + return len; +} + +static const struct file_operations himax_proc_register_ops = +{ + .owner = THIS_MODULE, + .read = himax_proc_register_read, + .write = himax_proc_register_write, +}; +#endif + +#ifdef HX_TP_PROC_DIAG +int16_t *getMutualBuffer(void) +{ + return diag_mutual; +} +int16_t *getMutualNewBuffer(void) +{ + return diag_mutual_new; +} +int16_t *getMutualOldBuffer(void) +{ + return diag_mutual_old; +} +int16_t *getSelfBuffer(void) +{ + return &diag_self[0]; +} +uint8_t getXChannel(void) +{ + return x_channel; +} +uint8_t getYChannel(void) +{ + return y_channel; +} +uint8_t getDiagCommand(void) +{ + return diag_command; +} +void setXChannel(uint8_t x) +{ + x_channel = x; +} +void setYChannel(uint8_t y) +{ + y_channel = y; +} +void setMutualBuffer(void) +{ + diag_mutual = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} +void setMutualNewBuffer(void) +{ + diag_mutual_new = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} +void setMutualOldBuffer(void) +{ + diag_mutual_old = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} + +#ifdef HX_TP_PROC_2T2R +int16_t *getMutualBuffer_2(void) +{ + return diag_mutual_2; +} +uint8_t getXChannel_2(void) +{ + return x_channel_2; +} +uint8_t getYChannel_2(void) +{ + return y_channel_2; +} +void setXChannel_2(uint8_t x) +{ + x_channel_2 = x; +} +void setYChannel_2(uint8_t y) +{ + y_channel_2 = y; +} +void setMutualBuffer_2(void) +{ + diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); +} +#endif + +static ssize_t himax_diag_arrange_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + //struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + g_diag_arr_num = buf[0] - '0'; + I("%s: g_diag_arr_num = %d \n", __func__,g_diag_arr_num); + + return len; +} + +static const struct file_operations himax_proc_diag_arrange_ops = +{ + .owner = THIS_MODULE, + .write = himax_diag_arrange_write, +}; + +static void himax_diag_arrange_print(struct seq_file *s, int i, int j, int transpose) +{ + if(transpose) + seq_printf(s, "%6d", diag_mutual[ j + i*x_channel]); + else + seq_printf(s, "%6d", diag_mutual[ i + j*x_channel]); +} + +static void himax_diag_arrange_inloop(struct seq_file *s, int in_init,bool transpose, int j) +{ + int i; + int in_max = 0; + + if(transpose) + in_max = y_channel; + else + in_max = x_channel; + + if (in_init > 0) + { + for(i = in_init-1;i >= 0;i--) + { + himax_diag_arrange_print(s, i, j, transpose); + } + } + else + { + for (i = 0; i < in_max; i++) + { + himax_diag_arrange_print(s, i, j, transpose); + } + } +} + +static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int out_init, int in_init) +{ + int j; + int out_max = 0; + + if(transpose) + out_max = x_channel; + else + out_max = y_channel; + + if(out_init > 0) + { + for(j = out_init-1;j >= 0;j--) + { + himax_diag_arrange_inloop(s, in_init, transpose, j); + seq_printf(s, " %5d\n", diag_self[j]); + } + } + else + { + for(j = 0;j < out_max;j++) + { + himax_diag_arrange_inloop(s, in_init, transpose, j); + seq_printf(s, " %5d\n", diag_self[j]); + } + } +} + +static void himax_diag_arrange(struct seq_file *s) +{ + int bit2,bit1,bit0; + int i; + + bit2 = g_diag_arr_num >> 2; + bit1 = g_diag_arr_num >> 1 & 0x1; + bit0 = g_diag_arr_num & 0x1; + + if (g_diag_arr_num < 4) + { + himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, bit0 * x_channel); + for (i = y_channel; i < x_channel + y_channel; i++) { + seq_printf(s, "%6d", diag_self[i]); + } + } + else + { + himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, bit0 * y_channel); + for (i = x_channel; i < x_channel + y_channel; i++) { + seq_printf(s, "%6d", diag_self[i]); + } + } +} + +static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos>=1) return NULL; + return (void *)((unsigned long) *pos+1); +} + +static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; +} +static void himax_diag_seq_stop(struct seq_file *s, void *v) +{ +} +static int himax_diag_seq_read(struct seq_file *s, void *v) +{ + size_t count = 0; + int32_t loop_i;//,loop_j + uint16_t mutual_num, self_num, width; + +#ifdef HX_TP_PROC_2T2R + if(Is_2T2R && diag_command == 4) + { + mutual_num = x_channel_2 * y_channel_2; + self_num = x_channel_2 + y_channel_2; //don't add KEY_COUNT + width = x_channel_2; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2); + } + else +#endif + { + mutual_num = x_channel * y_channel; + self_num = x_channel + y_channel; //don't add KEY_COUNT + width = x_channel; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel); + } + + // start to show out the raw data in adb shell + if (diag_command >= 1 && diag_command <= 6) { + if (diag_command <= 3) { + himax_diag_arrange(s); + seq_printf(s, "\n\n"); +#ifdef HX_EN_SEL_BUTTON + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) + seq_printf(s, "%6d", diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); +#endif +#ifdef HX_TP_PROC_2T2R + }else if(Is_2T2R && diag_command == 4 ) { + for (loop_i = 0; loop_i < mutual_num; loop_i++) { + seq_printf(s, "%4d", diag_mutual_2[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, " %6d\n", diag_self[width + loop_i/width]); + } + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < width; loop_i++) { + seq_printf(s, "%6d", diag_self[loop_i]); + if (((loop_i) % width) == (width - 1)) + seq_printf(s, "\n"); + } +#ifdef HX_EN_SEL_BUTTON + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) + seq_printf(s, "%4d", diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); +#endif +#endif + } else if (diag_command > 4) { + for (loop_i = 0; loop_i < self_num; loop_i++) { + seq_printf(s, "%4d", diag_self[loop_i]); + if (((loop_i - mutual_num) % width) == (width - 1)) + seq_printf(s, "\n"); + } + } else { + for (loop_i = 0; loop_i < mutual_num; loop_i++) { + seq_printf(s, "%4d", diag_mutual[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, "\n"); + } + } + seq_printf(s, "ChannelEnd"); + seq_printf(s, "\n"); + } else if (diag_command == 7) { + for (loop_i = 0; loop_i < 128 ;loop_i++) { + if ((loop_i % 16) == 0) + seq_printf(s, "LineStart:"); + seq_printf(s, "%4d", diag_coor[loop_i]); + if ((loop_i % 16) == 15) + seq_printf(s, "\n"); + } + } else if (diag_command == 9 || diag_command == 91 || diag_command == 92){ + himax_diag_arrange(s); + seq_printf(s, "\n"); + } + + return count; +} +static const struct seq_operations himax_diag_seq_ops = +{ + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_seq_read, +}; +static int himax_diag_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_seq_ops); +}; +bool DSRAM_Flag; + +//DSRAM thread +void himax_ts_diag_func(void) +{ + int i=0, j=0; + unsigned int index = 0; + int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; + uint8_t info_data[total_size]; + int16_t *mutual_data = NULL; + int16_t *mutual_data_new = NULL; + int16_t *mutual_data_old = NULL; + int16_t new_data; + + himax_burst_enable(private_ts->client, 1); + if(diag_command == 9 || diag_command == 91) + { + mutual_data = getMutualBuffer(); + }else if(diag_command == 92){ + mutual_data = getMutualBuffer(); + mutual_data_new = getMutualNewBuffer(); + mutual_data_old = getMutualOldBuffer(); + } + himax_get_DSRAM_data(private_ts->client, info_data); + + index = 0; + for (i = 0; i < ic_data->HX_TX_NUM; i++) + { + for (j = 0; j < ic_data->HX_RX_NUM; j++) + { + new_data = (short)(info_data[index + 1] << 8 | info_data[index]); + if(diag_command == 9){ + mutual_data[i*ic_data->HX_RX_NUM+j] = new_data; + }else if(diag_command == 91){ //Keep max data for 100 frame + if(mutual_data[i * ic_data->HX_RX_NUM + j] < new_data) + mutual_data[i * ic_data->HX_RX_NUM + j] = new_data; + }else if(diag_command == 92){ //Cal data for [N]-[N-1] frame + mutual_data_new[i * ic_data->HX_RX_NUM + j] = new_data; + mutual_data[i * ic_data->HX_RX_NUM + j] = mutual_data_new[i * ic_data->HX_RX_NUM + j] - mutual_data_old[i * ic_data->HX_RX_NUM + j]; + } + index += 2; + } + } + if(diag_command == 92){ + memcpy(mutual_data_old,mutual_data_new,x_channel * y_channel * sizeof(int16_t)); //copy N data to N-1 array + } + diag_max_cnt++; + if(diag_command == 9 || diag_command == 92){ + queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); + }else if(diag_command == 91){ + if(diag_max_cnt > 100) //count for 100 frame + { + //Clear DSRAM flag + DSRAM_Flag = false; + + //Enable ISR + himax_int_enable(private_ts->client->irq,1); + + //===================================== + // test result command : 0x8002_0324 ==> 0x00 + //===================================== + himax_diag_register_set(private_ts->client, 0x00); + }else{ + queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); + } + } +} + +static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) +{ + char messages[80] = {0}; + + uint8_t command[2] = {0x00, 0x00}; + uint8_t receive[1]; + + memset(receive, 0x00, sizeof(receive)); + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(messages, buff, len)) + { + return -EFAULT; + } + if (messages[1] == 0x0A){ + diag_command =messages[0] - '0'; + }else{ + diag_command =(messages[0] - '0')*10 + (messages[1] - '0'); + } + + I("[Himax]diag_command=0x%x\n",diag_command); + if (diag_command < 0x04){ + if(DSRAM_Flag) + { + //1. Clear DSRAM flag + DSRAM_Flag = false; + + //2. Stop DSRAM thread + cancel_delayed_work_sync(&private_ts->himax_diag_delay_wrok); + + //3. Enable ISR + himax_int_enable(private_ts->client->irq,1); + } + command[0] = diag_command; + himax_diag_register_set(private_ts->client, command[0]); + } + //coordinate dump start + else if (diag_command == 0x08) { + E("%s: coordinate_dump_file_create error\n", __func__); + } + else if (diag_command == 0x09 || diag_command == 91 || diag_command == 92){ + diag_max_cnt = 0; + memset(diag_mutual, 0x00, x_channel * y_channel * sizeof(int16_t)); //Set data 0 everytime + + //1. Disable ISR + himax_int_enable(private_ts->client->irq,0); + + //2. Start DSRAM thread + //himax_diag_register_set(private_ts->client, 0x0A); + + queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 2*HZ/100); + + I("%s: Start get raw data in DSRAM\n", __func__); + + //3. Set DSRAM flag + DSRAM_Flag = true; + }else{ + command[0] = 0x00; + himax_diag_register_set(private_ts->client, command[0]); + E("[Himax]Diag command error!diag_command=0x%x\n",diag_command); + } + return len; +} + +static const struct file_operations himax_proc_diag_ops = +{ + .owner = THIS_MODULE, + .open = himax_diag_proc_open, + .read = seq_read, + .write = himax_diag_write, +}; +#endif + +#ifdef HX_TP_PROC_RESET +static ssize_t himax_reset_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[12]; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + //if (buf_tmp[0] == '1') + // ESD_HW_REST(); + + return len; +} + +static const struct file_operations himax_proc_reset_ops = +{ + .owner = THIS_MODULE, + .write = himax_reset_write, +}; +#endif + +#ifdef HX_TP_PROC_DEBUG +static ssize_t himax_debug_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf){ + HX_PROC_SEND_FLAG=0; + return count; + } + + if (debug_level_cmd == 't') + { + if (fw_update_complete) + count += snprintf(temp_buf+count, len-count, "FW Update Complete "); + else + { + count += snprintf(temp_buf+count, len-count, "FW Update Fail "); + } + } + else if (debug_level_cmd == 'h') + { + if (handshaking_result == 0) + { + count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Running)\n", handshaking_result); + } + else if (handshaking_result == 1) + { + count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Stop)\n", handshaking_result); + } + else if (handshaking_result == 2) + { + count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (I2C Error)\n", handshaking_result); + } + else + { + count += snprintf(temp_buf+count, len-count, "Handshaking Result = error\n"); + } + } + else if (debug_level_cmd == 'v') + { + count += snprintf(temp_buf+count, len-count, "FW_VER = "); + count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_fw_ver); + count += snprintf(temp_buf+count, len-count, "CONFIG_VER = "); + count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_config_ver); + count += snprintf(temp_buf+count, len-count, "\n"); + } + else if (debug_level_cmd == 'd') + { + count += snprintf(temp_buf+count, len-count, "Himax Touch IC Information :\n"); + if (IC_TYPE == HX_85XX_D_SERIES_PWON) + { + count += snprintf(temp_buf+count, len-count, "IC Type : D\n"); + } + else if (IC_TYPE == HX_85XX_E_SERIES_PWON) + { + count += snprintf(temp_buf+count, len-count, "IC Type : E\n"); + } + else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) + { + count += snprintf(temp_buf+count, len-count, "IC Type : ES\n"); + } + else if (IC_TYPE == HX_85XX_F_SERIES_PWON) + { + count += snprintf(temp_buf+count, len-count, "IC Type : F\n"); + } + else + { + count += snprintf(temp_buf+count, len-count, "IC Type error.\n"); + } + + if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) + { + count += snprintf(temp_buf+count, len-count, "IC Checksum : SW\n"); + } + else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) + { + count += snprintf(temp_buf+count, len-count, "IC Checksum : HW\n"); + } + else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) + { + count += snprintf(temp_buf+count, len-count, "IC Checksum : CRC\n"); + } + else + { + count += snprintf(temp_buf+count, len-count, "IC Checksum error.\n"); + } + + if (ic_data->HX_INT_IS_EDGE) + { + count += snprintf(temp_buf+count, len-count, "Interrupt : EDGE TIRGGER\n"); + } + else + { + count += snprintf(temp_buf+count, len-count, "Interrupt : LEVEL TRIGGER\n"); + } + + count += snprintf(temp_buf+count, len-count, "RX Num : %d\n", ic_data->HX_RX_NUM); + count += snprintf(temp_buf+count, len-count, "TX Num : %d\n", ic_data->HX_TX_NUM); + count += snprintf(temp_buf+count, len-count, "BT Num : %d\n", ic_data->HX_BT_NUM); + count += snprintf(temp_buf+count, len-count, "X Resolution : %d\n", ic_data->HX_X_RES); + count += snprintf(temp_buf+count, len-count, "Y Resolution : %d\n", ic_data->HX_Y_RES); + count += snprintf(temp_buf+count, len-count, "Max Point : %d\n", ic_data->HX_MAX_PT); + count += snprintf(temp_buf+count, len-count, "XY reverse : %d\n", ic_data->HX_XY_REVERSE); + #ifdef HX_TP_PROC_2T2R + if(Is_2T2R) + { + count += snprintf(temp_buf+count, len-count, "2T2R panel\n"); + count += snprintf(temp_buf+count, len-count, "RX Num_2 : %d\n", HX_RX_NUM_2); + count += snprintf(temp_buf+count, len-count, "TX Num_2 : %d\n", HX_TX_NUM_2); + } + #endif + } + else if (debug_level_cmd == 'i') + { + count += snprintf(temp_buf+count, len-count, "Himax Touch Driver Version:\n"); + count += snprintf(temp_buf+count, len-count, "%s\n", HIMAX_DRIVER_VER); + } + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + return count; +} + +static ssize_t himax_debug_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + const struct firmware *fw = NULL; + unsigned char *fw_data = NULL; + char fileName[128]; + char buf[80] = {0}; + int result; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if ( buf[0] == 'h') //handshaking + { + debug_level_cmd = buf[0]; + + himax_int_enable(private_ts->client->irq,0); + + handshaking_result = himax_hand_shaking(private_ts->client); //0:Running, 1:Stop, 2:I2C Fail + + himax_int_enable(private_ts->client->irq,1); + + return len; + } + + else if ( buf[0] == 'v') //firmware version + { + debug_level_cmd = buf[0]; + himax_int_enable(private_ts->client->irq,0); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false,false); +#endif + himax_read_FW_ver(private_ts->client); + //himax_check_chip_version(); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + himax_int_enable(private_ts->client->irq,1); + return len; + } + + else if ( buf[0] == 'd') //ic information + { + debug_level_cmd = buf[0]; + return len; + } + + else if ( buf[0] == 'i') //driver version + { + debug_level_cmd = buf[0]; + return len; + } + + else if (buf[0] == 't') + { + + himax_int_enable(private_ts->client->irq,0); + + debug_level_cmd = buf[0]; + fw_update_complete = false; + + memset(fileName, 0, 128); + // parse the file name + snprintf(fileName, len-4, "%s", &buf[4]); + I("%s: upgrade from file(%s) start!\n", __func__, fileName); + // open file + result = request_firmware(&fw, fileName, private_ts->dev); + if (result) { + E("%s: open firmware file failed\n", __func__); + goto firmware_upgrade_done; + //return len; + } + + I("%s: FW len %d\n", __func__, fw->size); + fw_data = (unsigned char *)fw->data; + + I("%s: FW image,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]); + + if (fw_data != NULL) + { + // start to upgrade + himax_int_enable(private_ts->client->irq,0); + + if ((buf[1] == '6') && (buf[2] == '0')) + { + if (fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,upgrade_fw, result, false) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + } + else if ((buf[1] == '6') && (buf[2] == '4')) + { + if (fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,upgrade_fw, result, false) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + } + else if ((buf[1] == '2') && (buf[2] == '4')) + { + if (fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,upgrade_fw, result, false) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + } + else if ((buf[1] == '2') && (buf[2] == '8')) + { + if (fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,upgrade_fw, result, false) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + } + else + { + E("%s: Flash command fail: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + release_firmware(fw); + goto firmware_upgrade_done; + //return count; + } + } + + firmware_upgrade_done: + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + himax_int_enable(private_ts->client->irq,1); + + //todo himax_chip->tp_firmware_upgrade_proceed = 0; + //todo himax_chip->suspend_state = 0; + //todo enable_irq(himax_chip->irq); + return len; +} + +static const struct file_operations himax_proc_debug_ops = +{ + .owner = THIS_MODULE, + .read = himax_debug_read, + .write = himax_debug_write, +}; + +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + +static uint8_t getFlashCommand(void) +{ + return flash_command; +} + +static uint8_t getFlashDumpProgress(void) +{ + return flash_progress; +} + +static uint8_t getFlashDumpComplete(void) +{ + return flash_dump_complete; +} + +static uint8_t getFlashDumpFail(void) +{ + return flash_dump_fail; +} + +uint8_t getSysOperation(void) +{ + return sys_operation; +} + +static uint8_t getFlashReadStep(void) +{ + return flash_read_step; +} +/* +static uint8_t getFlashDumpSector(void) +{ + return flash_dump_sector; +} + +static uint8_t getFlashDumpPage(void) +{ + return flash_dump_page; +} +*/ +bool getFlashDumpGoing(void) +{ + return flash_dump_going; +} + +void setFlashBuffer(void) +{ + flash_buffer = kzalloc(Flash_Size * sizeof(uint8_t), GFP_KERNEL); + if (flash_buffer) + memset(flash_buffer,0x00,Flash_Size); +} + +void setSysOperation(uint8_t operation) +{ + sys_operation = operation; +} + +static void setFlashDumpProgress(uint8_t progress) +{ + flash_progress = progress; + //I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress); +} + +static void setFlashDumpComplete(uint8_t status) +{ + flash_dump_complete = status; +} + +static void setFlashDumpFail(uint8_t fail) +{ + flash_dump_fail = fail; +} + +static void setFlashCommand(uint8_t command) +{ + flash_command = command; +} + +static void setFlashReadStep(uint8_t step) +{ + flash_read_step = step; +} + +static void setFlashDumpSector(uint8_t sector) +{ + flash_dump_sector = sector; +} + +static void setFlashDumpPage(uint8_t page) +{ + flash_dump_page = page; +} + +static void setFlashDumpGoing(bool going) +{ + flash_dump_going = going; +} + +static ssize_t himax_proc_flash_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + int loop_i; + uint8_t local_flash_read_step=0; + uint8_t local_flash_complete = 0; + uint8_t local_flash_progress = 0; + uint8_t local_flash_command = 0; + uint8_t local_flash_fail = 0; + char *temp_buf; + local_flash_complete = getFlashDumpComplete(); + local_flash_progress = getFlashDumpProgress(); + local_flash_command = getFlashCommand(); + local_flash_fail = getFlashDumpFail(); + + I("flash_progress = %d \n",local_flash_progress); + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + + if (local_flash_fail) + { + ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Fail \n"); + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (!local_flash_complete) + { + ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Ongoing:0x%2.2x \n",flash_progress); + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (local_flash_command == 1 && local_flash_complete) + { + ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Complete \n"); + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (local_flash_command == 3 && local_flash_complete) + { + ret += snprintf(temp_buf+ret, len-ret, "FlashStart: \n"); + for(loop_i = 0; loop_i < 128; loop_i++) + { + ret += snprintf(temp_buf+ret, len-ret, "x%2.2x", flash_buffer[loop_i]); + if ((loop_i % 16) == 15) + { + ret += snprintf(temp_buf+ret, len-ret, "\n"); + } + } + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + //flash command == 0 , report the data + local_flash_read_step = getFlashReadStep(); + + ret += snprintf(temp_buf+ret, len-ret, "FlashStart:%2.2x \n",local_flash_read_step); + + for (loop_i = 0; loop_i < 1024; loop_i++) + { + ret += snprintf(temp_buf+ret, len-ret, "x%2.2X", flash_buffer[local_flash_read_step*1024 + loop_i]); + + if ((loop_i % 16) == 15) + { + ret += snprintf(temp_buf+ret, len-ret, "\n"); + } + } + + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static ssize_t himax_proc_flash_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[6]; + unsigned long result = 0; + uint8_t loop_i = 0; + int base = 0; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + + I("%s: buf[0] = %s\n", __func__, buf); + + if (getSysOperation() == 1) + { + E("%s: PROC is busy , return!\n", __func__); + return len; + } + + if (buf[0] == '0') + { + setFlashCommand(0); + if (buf[1] == ':' && buf[2] == 'x') + { + memcpy(buf_tmp, buf + 3, 2); + I("%s: read_Step = %s\n", __func__, buf_tmp); + if (!kstrtoul(buf_tmp, 16, &result)) + { + I("%s: read_Step = %lu \n", __func__, result); + setFlashReadStep(result); + } + } + } + else if (buf[0] == '1')// 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k + { + setSysOperation(1); + setFlashCommand(1); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + if ((buf[1] == '_' ) && (buf[2] == '6' )){ + if (buf[3] == '0'){ + Flash_Size = FW_SIZE_60k; + }else if (buf[3] == '4'){ + Flash_Size = FW_SIZE_64k; + } + }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ + if (buf[3] == '4'){ + Flash_Size = FW_SIZE_124k; + }else if (buf[3] == '8'){ + Flash_Size = FW_SIZE_128k; + } + } + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '2') // 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k + { + setSysOperation(1); + setFlashCommand(2); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + if ((buf[1] == '_' ) && (buf[2] == '6' )){ + if (buf[3] == '0'){ + Flash_Size = FW_SIZE_60k; + }else if (buf[3] == '4'){ + Flash_Size = FW_SIZE_64k; + } + }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ + if (buf[3] == '4'){ + Flash_Size = FW_SIZE_124k; + }else if (buf[3] == '8'){ + Flash_Size = FW_SIZE_128k; + } + } + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '3') + { + setSysOperation(1); + setFlashCommand(3); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + setFlashDumpSector(result); + } + + memcpy(buf_tmp, buf + 7, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + setFlashDumpPage(result); + } + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '4') + { + I("%s: command 4 enter.\n", __func__); + setSysOperation(1); + setFlashCommand(4); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + setFlashDumpSector(result); + } + else + { + E("%s: command 4 , sector error.\n", __func__); + return len; + } + + memcpy(buf_tmp, buf + 7, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + setFlashDumpPage(result); + } + else + { + E("%s: command 4 , page error.\n", __func__); + return len; + } + + base = 11; + + I("=========Himax flash page buffer start=========\n"); + for(loop_i=0;loop_i<128 && base<80;loop_i++) + { + memcpy(buf_tmp, buf + base, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + flash_buffer[loop_i] = result; + I("%d ",flash_buffer[loop_i]); + if (loop_i % 16 == 15) + { + I("\n"); + } + } + base += 3; + } + I("=========Himax flash page buffer end=========\n"); + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + return len; +} + +static const struct file_operations himax_proc_flash_ops = +{ + .owner = THIS_MODULE, + .read = himax_proc_flash_read, + .write = himax_proc_flash_write, +}; + +void himax_ts_flash_func(void) +{ + uint8_t local_flash_command = 0; + + himax_int_enable(private_ts->client->irq,0); + setFlashDumpGoing(true); + + //sector = getFlashDumpSector(); + //page = getFlashDumpPage(); + + local_flash_command = getFlashCommand(); + + msleep(100); + + I("%s: local_flash_command = %d enter.\n", __func__,local_flash_command); + + if ((local_flash_command == 1 || local_flash_command == 2)|| (local_flash_command==0x0F)) + { + himax_flash_dump_func(private_ts->client, local_flash_command,Flash_Size, flash_buffer); + } + + I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); + + if (local_flash_command == 2) + { + E("Flash dump failed\n"); + } + + himax_int_enable(private_ts->client->irq,1); + setFlashDumpGoing(false); + + setFlashDumpComplete(1); + setSysOperation(0); + return; + +/* Flash_Dump_i2c_transfer_error: + + himax_int_enable(private_ts->client->irq,1); + setFlashDumpGoing(false); + setFlashDumpComplete(0); + setFlashDumpFail(1); + setSysOperation(0); + return; +*/ +} + +#endif + +#ifdef HX_TP_PROC_SELF_TEST +static ssize_t himax_self_test_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int val=0x00; + int ret = 0; + char *temp_buf; + + I("%s: enter, %d \n", __func__, __LINE__); + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + himax_int_enable(private_ts->client->irq,0);//disable irq + val = himax_chip_self_test(private_ts->client); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + himax_int_enable(private_ts->client->irq,1);//enable irq + + if (val == 0x01) { + ret += snprintf(temp_buf+ret, len-ret, "Self_Test Pass\n"); + } else { + ret += snprintf(temp_buf+ret, len-ret, "Self_Test Fail\n"); + } + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +/* +static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count) +{ + char buf_tmp[2]; + unsigned long result = 0; + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memcpy(buf_tmp, buf, 2); + if(!kstrtoul(buf_tmp, 16, &result)) + { + sel_type = (uint8_t)result; + } + I("sel_type = %x \r\n", sel_type); + return count; +} +*/ + +static const struct file_operations himax_proc_self_test_ops = +{ + .owner = THIS_MODULE, + .read = himax_self_test_read, +}; +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF +static ssize_t himax_sense_on_off_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if(buf[0] == '0') + { + himax_sense_off(private_ts->client); + I("Sense off \n"); + } + else if(buf[0] == '1') + { + if(buf[1] == '1'){ + himax_sense_on(private_ts->client, 0x01); + I("Sense on re-map off, run flash \n"); + }else if(buf[1] == '0'){ + himax_sense_on(private_ts->client, 0x00); + I("Sense on re-map on, run sram \n"); + }else{ + I("Do nothing \n"); + } + } + else + { + I("Do nothing \n"); + } + return len; +} + +static const struct file_operations himax_proc_sense_on_off_ops = +{ + .owner = THIS_MODULE, + .write = himax_sense_on_off_write, +}; +#endif + +#ifdef HX_HIGH_SENSE +static ssize_t himax_HSEN_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t count = 0; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return count; + } + count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable); + HX_PROC_SEND_FLAG=1; + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + } + else + HX_PROC_SEND_FLAG=0; + return count; +} + +static ssize_t himax_HSEN_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if (buf[0] == '0'){ + ts->HSEN_enable = 0; + } + else if (buf[0] == '1'){ + ts->HSEN_enable = 1; + } + else + return -EINVAL; + + himax_set_HSEN_func(ts->client, ts->HSEN_enable); + + I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable); + + return len; +} + +static const struct file_operations himax_proc_HSEN_ops = +{ + .owner = THIS_MODULE, + .read = himax_HSEN_read, + .write = himax_HSEN_write, +}; +#endif + +#ifdef HX_SMART_WAKEUP +static ssize_t himax_SMWP_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + struct himax_ts_data *ts = private_ts; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return count; + } + count = snprintf(temp_buf, len, "%d\n", ts->SMWP_enable); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return count; +} + +static ssize_t himax_SMWP_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + + if (buf[0] == '0') + { + ts->SMWP_enable = 0; + } + else if (buf[0] == '1') + { + ts->SMWP_enable = 1; + } + else + return -EINVAL; + + himax_set_SMWP_func(ts->client, ts->SMWP_enable); + HX_SMWP_EN = ts->SMWP_enable; + I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN); + + return len; +} + +static const struct file_operations himax_proc_SMWP_ops = +{ + .owner = THIS_MODULE, + .read = himax_SMWP_read, + .write = himax_SMWP_write, +}; + +static ssize_t himax_GESTURE_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i =0; + int ret = 0; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + for(i=0;i<16;i++) + ret += snprintf(temp_buf+ret, len-ret, "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); + HX_PROC_SEND_FLAG = 1; + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + { + HX_PROC_SEND_FLAG = 0; + ret = 0; + } + return ret; +} + +static ssize_t himax_GESTURE_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i =0; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + I("himax_GESTURE_store= %s \n",buf); + for (i=0;i<16;i++) + { + if (buf[i] == '0') + ts->gesture_cust_en[i]= 0; + else if (buf[i] == '1') + ts->gesture_cust_en[i]= 1; + else + ts->gesture_cust_en[i]= 0; + I("gesture en[%d]=%d \n", i, ts->gesture_cust_en[i]); + } + return len; +} + +static const struct file_operations himax_proc_Gesture_ops = +{ + .owner = THIS_MODULE, + .read = himax_GESTURE_read, + .write = himax_GESTURE_write, +}; +#endif + +int himax_touch_proc_init(void) +{ + himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL); + if (himax_touch_proc_dir == NULL) + { + E(" %s: himax_touch_proc_dir file create failed!\n", __func__); + return -ENOMEM; + } + + himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); + if (himax_proc_debug_level_file == NULL) + { + E(" %s: proc debug_level file create failed!\n", __func__); + goto fail_1; + } + + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_vendor_ops); + if(himax_proc_vendor_file == NULL) + { + E(" %s: proc vendor file create failed!\n", __func__); + goto fail_2; + } + + himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_attn_ops); + if(himax_proc_attn_file == NULL) + { + E(" %s: proc attn file create failed!\n", __func__); + goto fail_3; + } + + himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); + if(himax_proc_int_en_file == NULL) + { + E(" %s: proc int en file create failed!\n", __func__); + goto fail_4; + } + + himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); + if(himax_proc_layout_file == NULL) + { + E(" %s: proc layout file create failed!\n", __func__); + goto fail_5; + } + +#ifdef HX_TP_PROC_RESET + himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); + if(himax_proc_reset_file == NULL) + { + E(" %s: proc reset file create failed!\n", __func__); + goto fail_6; + } +#endif + +#ifdef HX_TP_PROC_DIAG + himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); + if(himax_proc_diag_file == NULL) + { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7; + } + himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_arrange_ops); + if(himax_proc_diag_arrange_file == NULL) + { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7_1; + } +#endif + +#ifdef HX_TP_PROC_REGISTER + himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); + if(himax_proc_register_file == NULL) + { + E(" %s: proc register file create failed!\n", __func__); + goto fail_8; + } +#endif + +#ifdef HX_TP_PROC_DEBUG + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); + if(himax_proc_debug_file == NULL) + { + E(" %s: proc debug file create failed!\n", __func__); + goto fail_9; + } +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); + if(himax_proc_flash_dump_file == NULL) + { + E(" %s: proc flash dump file create failed!\n", __func__); + goto fail_10; + } +#endif + +#ifdef HX_TP_PROC_SELF_TEST + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); + if(himax_proc_self_test_file == NULL) + { + E(" %s: proc self_test file create failed!\n", __func__); + goto fail_11; + } +#endif + +#ifdef HX_HIGH_SENSE + himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_HSEN_ops); + if(himax_proc_HSEN_file == NULL) + { + E(" %s: proc HSEN file create failed!\n", __func__); + goto fail_12; + } +#endif + +#ifdef HX_SMART_WAKEUP + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_SMWP_ops); + if(himax_proc_SMWP_file == NULL) + { + E(" %s: proc SMWP file create failed!\n", __func__); + goto fail_13; + } + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_Gesture_ops); + if(himax_proc_GESTURE_file == NULL) + { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_14; + } +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF + himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_sense_on_off_ops); + if(himax_proc_SENSE_ON_OFF_file == NULL) + { + E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__); + goto fail_15; + } +#endif + + return 0 ; + +#ifdef HX_TP_PROC_SENSE_ON_OFF + fail_15: +#endif +#ifdef HX_SMART_WAKEUP + remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); + fail_14: + remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); + fail_13: +#endif +#ifdef HX_HIGH_SENSE + remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); + fail_12: +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry( HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir ); + fail_11: +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry( HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir ); + fail_10: +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); + fail_9: +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry( HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir ); + fail_8: +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry( HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir ); + fail_7: + remove_proc_entry( HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir ); + fail_7_1: +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); + fail_6: +#endif + remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); + fail_5: remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); + fail_4: remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); + fail_3: remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); + fail_2: remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); + fail_1: remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); + return -ENOMEM; +} + +void himax_touch_proc_deinit(void) +{ +#ifdef HX_TP_PROC_SENSE_ON_OFF + remove_proc_entry( HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_SMART_WAKEUP + remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_DOT_VIEW + remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); +#endif + remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); +} +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h new file mode 100644 index 000000000000..91a7ae2eb7ab --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.h @@ -0,0 +1,181 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + #define HIMAX_PROC_TOUCH_FOLDER "android_touch" + #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" + #define HIMAX_PROC_VENDOR_FILE "vendor" + #define HIMAX_PROC_ATTN_FILE "attn" + #define HIMAX_PROC_INT_EN_FILE "int_en" + #define HIMAX_PROC_LAYOUT_FILE "layout" + + static struct proc_dir_entry *himax_touch_proc_dir; + static struct proc_dir_entry *himax_proc_debug_level_file; + static struct proc_dir_entry *himax_proc_vendor_file; + static struct proc_dir_entry *himax_proc_attn_file; + static struct proc_dir_entry *himax_proc_int_en_file; + static struct proc_dir_entry *himax_proc_layout_file; + + uint8_t HX_PROC_SEND_FLAG; + +extern int himax_touch_proc_init(void); +extern void himax_touch_proc_deinit(void); +bool getFlashDumpGoing(void); + +#ifdef HX_TP_PROC_REGISTER + #define HIMAX_PROC_REGISTER_FILE "register" + struct proc_dir_entry *himax_proc_register_file; + uint8_t register_command[4]; +#endif + +#ifdef HX_TP_PROC_DIAG + #define HIMAX_PROC_DIAG_FILE "diag" + struct proc_dir_entry *himax_proc_diag_file; + #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr" + struct proc_dir_entry *himax_proc_diag_arrange_file; + +#ifdef HX_TP_PROC_2T2R + static bool Is_2T2R; + static uint8_t x_channel_2; + static uint8_t y_channel_2; + static uint8_t *diag_mutual_2; + + int16_t *getMutualBuffer_2(void); + uint8_t getXChannel_2(void); + uint8_t getYChannel_2(void); + + void setMutualBuffer_2(void); + void setXChannel_2(uint8_t x); + void setYChannel_2(uint8_t y); +#endif + uint8_t x_channel; + uint8_t y_channel; + int16_t *diag_mutual; + int16_t *diag_mutual_new; + int16_t *diag_mutual_old; + uint8_t diag_max_cnt; + + int diag_command; + uint8_t diag_coor[128];// = {0xFF}; + int16_t diag_self[100] = {0}; + + int16_t *getMutualBuffer(void); + int16_t *getMutualNewBuffer(void); + int16_t *getMutualOldBuffer(void); + int16_t *getSelfBuffer(void); + uint8_t getDiagCommand(void); + uint8_t getXChannel(void); + uint8_t getYChannel(void); + + void setMutualBuffer(void); + void setMutualNewBuffer(void); + void setMutualOldBuffer(void); + void setXChannel(uint8_t x); + void setYChannel(uint8_t y); + uint8_t coordinate_dump_enable = 0; + struct file *coordinate_fn; +#endif + +#ifdef HX_TP_PROC_DEBUG + #define HIMAX_PROC_DEBUG_FILE "debug" + struct proc_dir_entry *himax_proc_debug_file = NULL; + + bool fw_update_complete = false; + int handshaking_result = 0; + unsigned char debug_level_cmd = 0; + unsigned char upgrade_fw[128*1024]; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + #define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" + struct proc_dir_entry *himax_proc_flash_dump_file = NULL; + + static int Flash_Size = 131072; + static uint8_t *flash_buffer = NULL; + static uint8_t flash_command = 0; + static uint8_t flash_read_step = 0; + static uint8_t flash_progress = 0; + static uint8_t flash_dump_complete = 0; + static uint8_t flash_dump_fail = 0; + static uint8_t sys_operation = 0; + static uint8_t flash_dump_sector = 0; + static uint8_t flash_dump_page = 0; + static bool flash_dump_going = false; + + static uint8_t getFlashCommand(void); + static uint8_t getFlashDumpComplete(void); + static uint8_t getFlashDumpFail(void); + static uint8_t getFlashDumpProgress(void); + static uint8_t getFlashReadStep(void); + //static uint8_t getFlashDumpSector(void); + //static uint8_t getFlashDumpPage(void); + + void setFlashBuffer(void); + uint8_t getSysOperation(void); + + static void setFlashCommand(uint8_t command); + static void setFlashReadStep(uint8_t step); + static void setFlashDumpComplete(uint8_t complete); + static void setFlashDumpFail(uint8_t fail); + static void setFlashDumpProgress(uint8_t progress); + void setSysOperation(uint8_t operation); + static void setFlashDumpSector(uint8_t sector); + static void setFlashDumpPage(uint8_t page); + static void setFlashDumpGoing(bool going); + +#endif + +#ifdef HX_TP_PROC_SELF_TEST + #define HIMAX_PROC_SELF_TEST_FILE "self_test" + struct proc_dir_entry *himax_proc_self_test_file = NULL; + uint32_t **raw_data_array; + uint8_t X_NUM = 0, Y_NUM = 0; + uint8_t sel_type = 0x0D; +#endif + +#ifdef HX_TP_PROC_RESET +#define HIMAX_PROC_RESET_FILE "reset" +extern void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); +struct proc_dir_entry *himax_proc_reset_file = NULL; +#endif + +#ifdef HX_HIGH_SENSE + #define HIMAX_PROC_HSEN_FILE "HSEN" + struct proc_dir_entry *himax_proc_HSEN_file = NULL; +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF + #define HIMAX_PROC_SENSE_ON_OFF_FILE "SenseOnOff" + struct proc_dir_entry *himax_proc_SENSE_ON_OFF_file = NULL; +#endif + +#ifdef HX_RST_PIN_FUNC + void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); +#endif + +#ifdef HX_SMART_WAKEUP +#define HIMAX_PROC_SMWP_FILE "SMWP" +struct proc_dir_entry *himax_proc_SMWP_file = NULL; +#define HIMAX_PROC_GESTURE_FILE "GESTURE" +struct proc_dir_entry *himax_proc_GESTURE_file = NULL; +uint8_t HX_SMWP_EN = 0; +//extern bool FAKE_POWER_KEY_SEND; +#endif + +#endif + diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c new file mode 100644 index 000000000000..6ad8dc03149b --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic.c @@ -0,0 +1,2118 @@ +/* Himax Android Driver Sample Code for HMX83100 chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_ic.h" + +static unsigned char i_TP_CRC_FW_128K[]= +{ + #include "HX_CRC_128.i" +}; +static unsigned char i_TP_CRC_FW_64K[]= +{ + #include "HX_CRC_64.i" +}; +static unsigned char i_TP_CRC_FW_124K[]= +{ + #include "HX_CRC_124.i" +}; +static unsigned char i_TP_CRC_FW_60K[]= +{ + #include "HX_CRC_60.i" +}; + + +unsigned long FW_VER_MAJ_FLASH_ADDR; +unsigned long FW_VER_MAJ_FLASH_LENG; +unsigned long FW_VER_MIN_FLASH_ADDR; +unsigned long FW_VER_MIN_FLASH_LENG; +unsigned long CFG_VER_MAJ_FLASH_ADDR; +unsigned long CFG_VER_MAJ_FLASH_LENG; +unsigned long CFG_VER_MIN_FLASH_ADDR; +unsigned long CFG_VER_MIN_FLASH_LENG; + +unsigned char IC_TYPE = 0; +unsigned char IC_CHECKSUM = 0; + +extern struct himax_ic_data* ic_data; + +int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C Fail +{ + int ret, result; + uint8_t hw_reset_check[1]; + uint8_t hw_reset_check_2[1]; + uint8_t buf0[2]; + uint8_t IC_STATUS_CHECK = 0xAA; + + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); + + buf0[0] = 0xF2; + if (IC_STATUS_CHECK == 0xAA) { + buf0[1] = 0xAA; + IC_STATUS_CHECK = 0x55; + } else { + buf0[1] = 0x55; + IC_STATUS_CHECK = 0xAA; + } + + ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:write 0xF2 failed line: %d \n",__LINE__); + goto work_func_send_i2c_msg_fail; + } + msleep(50); + + buf0[0] = 0xF2; + buf0[1] = 0x00; + ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:write 0x92 failed line: %d \n",__LINE__); + goto work_func_send_i2c_msg_fail; + } + usleep_range(2000, 4000); + + ret = i2c_himax_read(client, 0xD1, hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); + goto work_func_send_i2c_msg_fail; + } + + if ((IC_STATUS_CHECK != hw_reset_check[0])) { + usleep_range(2000, 4000); + ret = i2c_himax_read(client, 0xD1, hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); + goto work_func_send_i2c_msg_fail; + } + + if (hw_reset_check[0] == hw_reset_check_2[0]) { + result = 1; + } else { + result = 0; + } + } else { + result = 0; + } + + return result; + +work_func_send_i2c_msg_fail: + return 2; +} + +void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + if(diag_command != 0) + diag_command = diag_command + 5; + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = diag_command; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} + +void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) +{ + //struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work); + +// uint8_t sector = 0; +// uint8_t page = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t out_buffer[20]; + uint8_t in_buffer[260] = {0}; + int page_prog_start = 0; + int i = 0; + + himax_sense_off(client); + himax_burst_enable(client, 0); + /*=============Dump Flash Start=============*/ + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + for (page_prog_start = 0; page_prog_start < Flash_Size; page_prog_start = page_prog_start + 256) + { + //================================= + // SPI Transfer Control + // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + // Set read start address : 0x8000_0028 ==> 0x0000_0000 + // Set command : 0x8000_0024 ==> 0x0000_003B + //================================= + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) + { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //================================== + // AHB_I2C Burst Read + // Set SPI data register : 0x8000_002C ==> 0x00 + //================================== + out_buffer[0] = 0x2C; + out_buffer[1] = 0x00; + out_buffer[2] = 0x00; + out_buffer[3] = 0x80; + i2c_himax_write(client, 0x00 ,out_buffer, 4, 3); + + //================================== + // Read access : 0x0C ==> 0x00 + //================================== + out_buffer[0] = 0x00; + i2c_himax_write(client, 0x0C ,out_buffer, 1, 3); + + //================================== + // Read 128 bytes two times + //================================== + i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); + for (i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + + i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); + for (i = 0; i < 128; i++) + flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; + + I("%s:Verify Progress: %x\n", __func__, page_prog_start); + } + +/*=============Dump Flash End=============*/ + //msleep(100); + /* + for( i=0 ; i<8 ;i++) + { + for(j=0 ; j<64 ; j++) + { + setFlashDumpProgress(i*32 + j); + } + } + */ + himax_sense_on(client, 0x01); + + return; + +} + +int himax_chip_self_test(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + int pf_value=0x00; + uint8_t test_result_id = 0; + int j; + + memset(tmp_addr, 0x00, sizeof(tmp_addr)); + memset(tmp_data, 0x00, sizeof(tmp_data)); + + himax_interface_on(client); + himax_sense_off(client); + + //Set criteria + himax_burst_enable(client, 1); + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; + tmp_data[3] = 0x14; tmp_data[2] = 0xC8; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_data[7] = 0x13; tmp_data[6] = 0x60; tmp_data[5] = 0x0A; tmp_data[4] = 0x99; + + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 8); + + //start selftest + // 0x9008_805C ==> 0x0000_0001 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + himax_sense_on(client, 1); + + msleep(2000); + + himax_sense_off(client); + msleep(20); + + //===================================== + // Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF + //===================================== + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; + himax_register_read(client, tmp_addr, 1, tmp_data); + + test_result_id = tmp_data[0]; + + I("%s: check test result, test_result_id=%x, test_result=%x\n", __func__ + ,test_result_id,tmp_data[0]); + + if (test_result_id==0xF) { + I("[Himax]: self-test pass\n"); + pf_value = 0x1; + } else { + E("[Himax]: self-test fail\n"); + pf_value = 0x0; + } + himax_burst_enable(client, 1); + + for (j = 0;j < 10; j++){ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; + himax_register_read(client, tmp_addr, 1, tmp_data); + I("[Himax]: 9006000C = %d\n", tmp_data[0]); + if (tmp_data[0] != 0){ + tmp_data[3] = 0x90; tmp_data[2] = 0x06; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + tmp_data[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + i2c_himax_read(client, 0x08, tmp_data, 124,HIMAX_I2C_RETRY_TIMES); + }else{ + break; + } + } + + himax_sense_on(client, 1); + msleep(120); + + return pf_value; +} + +void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} +void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data) +{ + uint8_t tmp_addr[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + himax_register_read(client, tmp_addr, 1, tmp_data); +} + +void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} + +void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data) +{ + uint8_t tmp_addr[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + himax_register_read(client, tmp_addr, 1, tmp_data); +} + +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[4]; + + tmp_data[0] = 0x31; + if ( i2c_himax_write(client, 0x13 ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return -EBUSY; + } + + tmp_data[0] = (0x10 | auto_add_4_byte); + if ( i2c_himax_write(client, 0x0D ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return -EBUSY; + } + return 0; + +} + +void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data) +{ + uint8_t tmp_data[4]; + int i = 0; + int address = 0; + + if(read_length>256) + { + E("%s: read len over 256!\n", __func__); + return; + } + if (read_length > 1) + himax_burst_enable(client, 1); + else + himax_burst_enable(client, 0); + address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_addr[0]; + i = address; + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + tmp_data[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x08 ,read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + if (read_length > 1) + himax_burst_enable(client, 0); +} + +void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data) +{ + uint8_t tmpbyte[2]; + + if ( i2c_himax_write(client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + tmpbyte[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x08 ,&read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x09 ,&read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x0A ,&read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x0B ,&read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x18 ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + }// No bus request + + if ( i2c_himax_read(client, 0x0F ,&tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + }// idle state + +} + +void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data) +{ + uint8_t data_byte[8]; + int i = 0, j = 0; + + for (i = 0; i < 4; i++) + { + data_byte[i] = reg_byte[i]; + } + for (j = 4; j < 8; j++) + { + data_byte[j] = write_data[j-4]; + } + + if ( i2c_himax_write(client, 0x00 ,data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + +} + +int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length) +{ + uint8_t data_byte[256]; + int i = 0, j = 0; + + for (i = 0; i < 4; i++) + { + data_byte[i] = reg_byte[i]; + } + for (j = 4; j < length + 4; j++) + { + data_byte[j] = write_data[j - 4]; + } + + if ( i2c_himax_write(client, 0x00 ,data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return -EBUSY; + } + + return 0; +} + +int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data) +{ + int i =0, address = 0; + int ret = 0; + + address = (write_addr[3] << 24) + (write_addr[2] << 16) + (write_addr[1] << 8) + write_addr[0]; + + for (i = address; i < address + write_length * 4; i = i + 4) + { + if (write_length > 1) + { + ret = himax_burst_enable(client, 1); + if(ret) + return ret; + } + else + { + ret = himax_burst_enable(client, 0); + if(ret) + return ret; + } + ret = himax_flash_write_burst_lenth(client, write_addr, write_data, write_length * 4); + if(ret < 0) + return ret; + } + + return 0; +} + +void himax_sense_off(struct i2c_client *client) +{ + uint8_t wdt_off = 0x00; + uint8_t tmp_addr[4]; + uint8_t tmp_data[5]; + + himax_burst_enable(client, 0); + + while(wdt_off == 0x00) + { + // 0x9000_800C ==> 0x0000_AC53 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0xAC; tmp_data[0] = 0x53; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Read Watch Dog disable password : 0x9000_800C ==> 0x0000_AC53 + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + himax_register_read(client, tmp_addr, 1, tmp_data); + + //Check WDT + if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) + wdt_off = 0x01; + else + wdt_off = 0x00; + } + + // VCOM //0x9008_806C ==> 0x0000_0001 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(20); + + // 0x9000_0010 ==> 0x0000_00DA + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xDA; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA + //===================================== + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + himax_register_read(client, tmp_addr, 1, tmp_data); + I("%s: CPU clock off password data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + +} + +void himax_interface_on(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[5]; + + //=========================================== + // Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 + //=========================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + himax_flash_read(client, tmp_addr, tmp_data); //avoid RD/WR fail +} + +bool wait_wip(struct i2c_client *client, int Timing) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t in_buffer[10]; + //uint8_t out_buffer[20]; + int retry_cnt = 0; + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + in_buffer[0] = 0x01; + + do + { + //===================================== + // SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x42; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x03; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // SPI Command : 0x8000_0024 ==> 0x0000_0005 + // read 0x8000_002C for 0x01, means wait success + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x05; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + in_buffer[0] = in_buffer[1] = in_buffer[2] = in_buffer[3] = 0xFF; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(client, tmp_addr, 1, in_buffer); + + if ((in_buffer[0] & 0x01) == 0x00) + return true; + + retry_cnt++; + + if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 || in_buffer[2] != 0x00 || in_buffer[3] != 0x00) + I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, buffer[1]=%d, buffer[2]=%d, buffer[3]=%d \n", __func__, + retry_cnt,in_buffer[0],in_buffer[1],in_buffer[2],in_buffer[3]); + + if (retry_cnt > 100) + { + E("%s: Wait wip error!\n", __func__); + return false; + } + msleep(Timing); + }while ((in_buffer[0] & 0x01) == 0x01); + return true; +} + +void himax_sense_on(struct i2c_client *client, uint8_t FlashMode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + + himax_interface_on(client); + himax_burst_enable(client, 0); + //CPU reset + // 0x9000_0014 ==> 0x0000_00CA + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xCA; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA + //===================================== + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + + // 0x9000_0014 ==> 0x0000_0000 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 + //===================================== + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + + //===================================== + // Reset TCON + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + usleep_range(10000, 20000); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + if (FlashMode == 0x00) //SRAM + { + //===================================== + // Re-map + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xF1; + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + I("%s:83100_Chip_Re-map ON\n", __func__); + } + else + { + //===================================== + // Re-map off + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + I("%s:83100_Chip_Re-map OFF\n", __func__); + } + //===================================== + // CPU clock on + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + +} + +void himax_chip_erase(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Chip Erase + // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 + // 2. 0x8000_0024 ==> 0x0000_0006 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Chip Erase + // Erase Command : 0x8000_0024 ==> 0x0000_00C7 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xC7; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(2000); + + if (!wait_wip(client, 100)) + E("%s:83100_Chip_Erase Fail\n", __func__); + +} + +bool himax_block_erase(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Chip Erase + // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 + // 2. 0x8000_0024 ==> 0x0000_0006 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Block Erase + // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr + // 0x8000_0020 ==> 0x6700_0000 //control + // 0x8000_0024 ==> 0x0000_0052 //BE + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x52; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(1000); + + if (!wait_wip(client, 100)) + { + E("%s:83100_Erase Fail\n", __func__); + return false; + } + else + { + return true; + } + +} + +bool himax_sector_erase(struct i2c_client *client, int start_addr) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int page_prog_start = 0; + + himax_burst_enable(client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + for (page_prog_start = start_addr; page_prog_start < start_addr + 0x0F000; page_prog_start = page_prog_start + 0x1000) + { + //===================================== + // Chip Erase + // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 + // 2. 0x8000_0024 ==> 0x0000_0006 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Sector Erase + // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr + // 0x8000_0020 ==> 0x6700_0000 //control + // 0x8000_0024 ==> 0x0000_0020 //SE + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) + { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) + { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) + { + tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x20; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(200); + + if (!wait_wip(client, 100)) + { + E("%s:83100_Erase Fail\n", __func__); + return false; + } + } + return true; +} + +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) +{ + int i = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + int FW_length = 0x4000; // 0x4000 = 16K bin file + + //himax_sense_off(client); + + for (i = 0; i < FW_length; i = i + 128) + { + himax_burst_enable(client, 1); + + if (i < 0x100) + { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = i; + } + else if (i >= 0x100 && i < 0x10000) + { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = (i >> 8); + tmp_addr[0] = i; + } + + memcpy(&tmp_data[0], &FW_content[i], 128); + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 128); + + } + + if (!wait_wip(client, 100)) + E("%s:83100_Sram_Write Fail\n", __func__); +} + +bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size) +{ + int i = 0; + uint8_t out_buffer[20]; + uint8_t in_buffer[128]; + uint8_t *get_fw_content; + + get_fw_content = kzalloc(0x4000*sizeof(uint8_t), GFP_KERNEL); + if (!get_fw_content) + return false; + + for (i = 0; i < 0x4000; i = i + 128) + { + himax_burst_enable(client, 1); + + //================================== + // AHB_I2C Burst Read + //================================== + if (i < 0x100) + { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = 0x00; + out_buffer[0] = i; + } + else if (i >= 0x100 && i < 0x10000) + { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = (i >> 8); + out_buffer[0] = i; + } + + if ( i2c_himax_write(client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + out_buffer[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + if ( i2c_himax_read(client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + memcpy(&get_fw_content[i], &in_buffer[0], 128); + } + + for (i = 0; i < FW_Size; i++) + { + if (FW_File[i] != get_fw_content[i]) + { + E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", __func__,i,get_fw_content[i],FW_File[i]); + return false; + } + } + + kfree(get_fw_content); + + return true; +} + +void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size) +{ + int page_prog_start = 0; + int program_length = 48; + int i = 0, j = 0, k = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t buring_data[256]; // Read for flash data, 128K + // 4 bytes for 0x80002C padding + + //himax_interface_on(client); + himax_burst_enable(client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) + { + //msleep(5); + //===================================== + // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 + // 2. 0x8000_0024 ==> 0x0000_0006 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //================================= + // SPI Transfer Control + // Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 + // Set read start address : 0x8000_0028 ==> 0x0000_0000 + //================================= + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x61; tmp_data[2] = 0x0F; tmp_data[1] = 0xF0; tmp_data[0] = 0x00; + // data bytes should be 0x6100_0000 + ((word_number)*4-1)*4096 = 0x6100_0000 + 0xFF000 = 0x610F_F000 + // Programmable size = 1 page = 256 bytes, word_number = 256 byte / 4 = 64 + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + //tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; // Flash start address 1st : 0x0000_0000 + + if (page_prog_start < 0x100) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) + { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + + himax_flash_write_burst(client, tmp_addr, tmp_data); + + + //================================= + // Send 16 bytes data : 0x8000_002C ==> 16 bytes data + //================================= + buring_data[0] = 0x2C; + buring_data[1] = 0x00; + buring_data[2] = 0x00; + buring_data[3] = 0x80; + + for (i = /*0*/page_prog_start, j = 0; i < 16 + page_prog_start/**/; i++, j++) /// <------ bin file + { + buring_data[j + 4] = FW_content[i]; + } + + + if ( i2c_himax_write(client, 0x00 ,buring_data, 20, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + //================================= + // Write command : 0x8000_0024 ==> 0x0000_0002 + //================================= + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x02; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //================================= + // Send 240 bytes data : 0x8000_002C ==> 240 bytes data + //================================= + + for (j = 0; j < 5; j++) + { + for (i = (page_prog_start + 16 + (j * 48)), k = 0; i < (page_prog_start + 16 + (j * 48)) + program_length; i++, k++) /// <------ bin file + { + buring_data[k+4] = FW_content[i];//(byte)i; + } + + if ( i2c_himax_write(client, 0x00 ,buring_data, program_length+4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + } + + if (!wait_wip(client, 1)) + E("%s:83100_Flash_Programming Fail\n", __func__); + } +} + +bool himax_check_chip_version(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t ret_data = 0x00; + int i = 0; + int ret = 0; + himax_sense_off(client); + for (i = 0; i < 5; i++) + { + // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + ret = himax_register_write(client, tmp_addr, 1, tmp_data); + if(ret) + return false; + + // 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000) + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + ret = himax_register_write(client, tmp_addr, 1, tmp_data); + if(ret) + return false; + + // 3. Read driver ID register RF4H 1 byte (0x8001_F401) + // Driver register RF4H 1 byte value = 0x84H, read back value will become 0x84848484 + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; + himax_register_read(client, tmp_addr, 1, tmp_data); + ret_data = tmp_data[0]; + + I("%s:Read driver IC ID = %X\n", __func__, ret_data); + if (ret_data == 0x84) + { + IC_TYPE = HX_83100_SERIES_PWON; + //himax_sense_on(client, 0x01); + ret_data = true; + break; + } + else + { + ret_data = false; + E("%s:Read driver ID register Fail:\n", __func__); + } + } + // 4. After read finish, set DDREG_Req = 0 (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(client, tmp_addr, 1, tmp_data); + //himax_sense_on(client, 0x01); + return ret_data; +} + +#if 1 +int himax_check_CRC(struct i2c_client *client, int mode) +{ + bool burnFW_success = false; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int tmp_value; + int CRC_value = 0; + + memset(tmp_data, 0x00, sizeof(tmp_data)); + + if (1) + { + if(mode == fw_image_60k) + { + himax_sram_write(client, (i_TP_CRC_FW_60K)); + burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_60K, 0x4000); + } + else if(mode == fw_image_64k) + { + himax_sram_write(client, (i_TP_CRC_FW_64K)); + burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_64K, 0x4000); + } + else if(mode == fw_image_124k) + { + himax_sram_write(client, (i_TP_CRC_FW_124K)); + burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_124K, 0x4000); + } + else if(mode == fw_image_128k) + { + himax_sram_write(client, (i_TP_CRC_FW_128K)); + burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_128K, 0x4000); + } + if (burnFW_success) + { + I("%s: Start to do CRC FW mode=%d \n", __func__,mode); + himax_sense_on(client, 0x00); // run CRC firmware + + while(true) + { + msleep(100); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; + tmp_addr[0] = 0x94; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: CRC from firmware is %x, %x, %x, %x \n", __func__,tmp_data[3], + tmp_data[2],tmp_data[1],tmp_data[0]); + + if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) + { + } + else + break; + } + + CRC_value = tmp_data[3]; + + tmp_value = tmp_data[2] << 8; + CRC_value += tmp_value; + + tmp_value = tmp_data[1] << 16; + CRC_value += tmp_value; + + tmp_value = tmp_data[0] << 24; + CRC_value += tmp_value; + + I("%s: CRC Value is %x \n", __func__, CRC_value); + + //Close Remapping + //===================================== + // Re-map close + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + return CRC_value; + } + else + { + E("%s: SRAM write fail\n", __func__); + return 0; + } + } + else + I("%s: NO CRC Check File \n", __func__); + + return 0; +} + +bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode) +{ + uint8_t tmp_data[4]; + int i, j; + int fw_data; + int fw_data_2; + int CRC = 0xFFFFFFFF; + int PolyNomial = 0x82F63B78; + int length = 0; + + if (mode == fw_image_128k) + length = 0x8000; + else if (mode == fw_image_124k) + length = 0x7C00; + else if (mode == fw_image_64k) + length = 0x4000; + else //if (mode == fw_image_60k) + length = 0x3C00; + + for (i = 0; i < length; i++) + { + fw_data = FW_content[i * 4 ]; + + for (j = 1; j < 4; j++) + { + fw_data_2 = FW_content[i * 4 + j]; + fw_data += (fw_data_2) << (8 * j); + } + + CRC = fw_data ^ CRC; + + for (j = 0; j < 32; j++) + { + if ((CRC % 2) != 0) + { + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; + } + else + { + CRC = (((CRC >> 1) ^ 0x7FFFFFFF)& 0x7FFFFFFF); + } + } + } + + I("%s: CRC calculate from bin file is %x \n", __func__, CRC); + + tmp_data[0] = (uint8_t)(CRC >> 24); + tmp_data[1] = (uint8_t)(CRC >> 16); + tmp_data[2] = (uint8_t)(CRC >> 8); + tmp_data[3] = (uint8_t) CRC; + + CRC = tmp_data[0]; + CRC += tmp_data[1] << 8; + CRC += tmp_data[2] << 16; + CRC += tmp_data[3] << 24; + + I("%s: CRC calculate from bin file REVERSE %x \n", __func__, CRC); + I("%s: CRC calculate from FWis %x \n", __func__, CRC_from_FW); + if (CRC_from_FW == CRC) + return true; + else + return false; +} +#endif + +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x10000) //64k + { + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + if (!himax_sector_erase(client, 0x00000)) + { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } + himax_flash_programming(client, fw, 0x0F000); + + //burnFW_success = himax_83100_Verify(fw, len); + //if(burnFW_success==false) + // return burnFW_success; + + CRC_from_FW = himax_check_CRC(client,fw_image_60k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_60k); + //himax_sense_on(client, 0x01); + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x10000) //64k + { + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + himax_chip_erase(client); + himax_flash_programming(client, fw, len); + + //burnFW_success = himax_83100_Verify(fw, len); + //if(burnFW_success==false) + // return burnFW_success; + + CRC_from_FW = himax_check_CRC(client,fw_image_64k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_64k); + //himax_sense_on(client, 0x01); + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x20000) //128k + { + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + if (!himax_block_erase(client)) + { + E("%s:Block erase fail!Please restart the IC.\n", __func__); + return false; + } + + if (!himax_sector_erase(client, 0x10000)) + { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } + himax_flash_programming(client, fw, 0x1F000); + + + //burnFW_success = himax_83100_Verify(fw, len); + //if(burnFW_success==false) + // return burnFW_success; + + CRC_from_FW = himax_check_CRC(client,fw_image_124k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_124k); + //himax_sense_on(client, 0x01); + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x20000) //128k + { + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + himax_chip_erase(client); + + himax_flash_programming(client, fw, len); + + //burnFW_success = himax_83100_Verify(fw, len); + //if(burnFW_success==false) + // return burnFW_success; + + CRC_from_FW = himax_check_CRC(client,fw_image_128k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_128k); + //himax_sense_on(client, 0x01); + return burnFW_success; +} + +void himax_touch_information(struct i2c_client *client) +{ + uint8_t cmd[4]; + char data[12] = {0}; + + I("%s:IC_TYPE =%d\n", __func__,IC_TYPE); + + if(IC_TYPE == HX_83100_SERIES_PWON) + { + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8; + himax_register_read(client, cmd, 1, data); + + ic_data->HX_RX_NUM = data[1]; + ic_data->HX_TX_NUM = data[2]; + ic_data->HX_MAX_PT = data[3]; + + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC; + himax_register_read(client, cmd, 1, data); + + if((data[1] & 0x04) == 0x04) { + ic_data->HX_XY_REVERSE = true; + } else { + ic_data->HX_XY_REVERSE = false; + } + ic_data->HX_Y_RES = data[3]*256; + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00; + himax_register_read(client, cmd, 1, data); + ic_data->HX_Y_RES = ic_data->HX_Y_RES + data[0]; + ic_data->HX_X_RES = data[1]*256 + data[2]; + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C; + himax_register_read(client, cmd, 1, data); + if((data[0] & 0x01) == 1) { + ic_data->HX_INT_IS_EDGE = true; + } else { + ic_data->HX_INT_IS_EDGE = false; + } + if (ic_data->HX_RX_NUM > 40) + ic_data->HX_RX_NUM = 29; + if (ic_data->HX_TX_NUM > 20) + ic_data->HX_TX_NUM = 16; + if (ic_data->HX_MAX_PT > 10) + ic_data->HX_MAX_PT = 10; + if (ic_data->HX_Y_RES > 2000) + ic_data->HX_Y_RES = 1280; + if (ic_data->HX_X_RES > 2000) + ic_data->HX_X_RES = 720; +#ifdef HX_EN_MUT_BUTTON + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8; + himax_register_read(client, cmd, 1, data); + ic_data->HX_BT_NUM = data[3]; +#endif + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d \n", __func__,ic_data->HX_RX_NUM,ic_data->HX_TX_NUM,ic_data->HX_MAX_PT); + I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d \n", __func__,ic_data->HX_XY_REVERSE,ic_data->HX_Y_RES,ic_data->HX_X_RES); + I("%s:HX_INT_IS_EDGE =%d \n", __func__,ic_data->HX_INT_IS_EDGE); + } + else + { + ic_data->HX_RX_NUM = 0; + ic_data->HX_TX_NUM = 0; + ic_data->HX_BT_NUM = 0; + ic_data->HX_X_RES = 0; + ic_data->HX_Y_RES = 0; + ic_data->HX_MAX_PT = 0; + ic_data->HX_XY_REVERSE = false; + ic_data->HX_INT_IS_EDGE = false; + } +} + +void himax_read_FW_ver(struct i2c_client *client) +{ + uint8_t cmd[4]; + uint8_t data[64] = {0}; + + //===================================== + // Read FW version : 0x0000_E303 + //===================================== + cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_config_ver = data[3]<<8; + + cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver; + I("CFG_VER : %X \n",ic_data->vendor_config_ver); + + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_fw_ver = data[0]<<8 | data[1]; + I("FW_VER : %X \n",ic_data->vendor_fw_ver); + + + return; +} + +bool himax_ic_package_check(struct i2c_client *client) +{ +#if 0 + uint8_t cmd[3]; + uint8_t data[3]; + + memset(cmd, 0x00, sizeof(cmd)); + memset(data, 0x00, sizeof(data)); + + if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0) + return false ; + + if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0) + return false; + + if((data[0] == 0x85 && data[1] == 0x29)) + { + IC_TYPE = HX_85XX_F_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 64901; //0xFD85 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 64902; //0xFD86 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 64928; //0xFDA0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 64940; //0xFDAC + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x F\n"); + } + if((data[0] == 0x85 && data[1] == 0x30) || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) + { + IC_TYPE = HX_85XX_E_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; //0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x E\n"); + } + else if((data[0] == 0x85 && data[1] == 0x31)) + { + IC_TYPE = HX_85XX_ES_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; //0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x ES\n"); + } + else if ((data[0] == 0x85 && data[1] == 0x28) || (cmd[0] == 0x04 && cmd[1] == 0x85 && + (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28))) { + IC_TYPE = HX_85XX_D_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; // 0x00A0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; // 0x00AC + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x D\n"); + } else if ((data[0] == 0x85 && data[1] == 0x23) || (cmd[0] == 0x03 && cmd[1] == 0x85 && + (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28 || cmd[2] == 0x29))) { + IC_TYPE = HX_85XX_C_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 135; // 0x0087 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 147; // 0x0093 + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x C\n"); + } else if ((data[0] == 0x85 && data[1] == 0x26) || + (cmd[0] == 0x02 && cmd[1] == 0x85 && + (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { + IC_TYPE = HX_85XX_B_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 728; // 0x02D8 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 692; // 0x02B4 + CFG_VER_MAJ_FLASH_LENG = 3; + CFG_VER_MIN_FLASH_ADDR = 704; // 0x02C0 + CFG_VER_MIN_FLASH_LENG = 3; + I("Himax IC package 852x B\n"); + } else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 && + cmd[1] == 0x85 && cmd[2] == 0x19)) { + IC_TYPE = HX_85XX_A_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + I("Himax IC package 852x A\n"); + } else { + E("Himax IC package incorrect!!\n"); + }*/ +#else + IC_TYPE = HX_83100_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 57384; //0xE028 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 57385; //0xE029 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 58115; //0xE303 + CFG_VER_MAJ_FLASH_LENG = 1; + CFG_VER_MIN_FLASH_ADDR = 58116; //0xE304 + CFG_VER_MIN_FLASH_LENG = 1; + I("Himax IC package 83100_in\n"); + +#endif + return true; +} + +void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length) +{ + uint8_t cmd[4]; + + cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; + if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + + cmd[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + + i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); +} + +#if 0 +static void himax_83100_Flash_Write(uint8_t * reg_byte, uint8_t * write_data) +{ + uint8_t tmpbyte[2]; + + if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (isBusrtOn == false) + { + tmpbyte[0] = 0x01; + if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } +} +#endif +#if 0 +static void himax_83100_Flash_Burst_Write(uint8_t * reg_byte, uint8_t * write_data) +{ + //uint8_t tmpbyte[2]; + int i = 0; + + if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + // Write 256 bytes with continue burst mode + for (i = 0; i < 256; i = i + 4) + { + if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } + + //if (isBusrtOn == false) + //{ + // tmpbyte[0] = 0x01; + // if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, 3) < 0) { + // E("%s: i2c access fail!\n", __func__); + // return; + // } + //} + +} +#endif + +#if 0 +static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t out_buffer[20]; + uint8_t in_buffer[260]; + + int fail_addr=0, fail_cnt=0; + int page_prog_start = 0; + int i = 0; + + himax_interface_on(private_ts->client); + himax_burst_enable(private_ts->client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) + { + //================================= + // SPI Transfer Control + // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + // Set read start address : 0x8000_0028 ==> 0x0000_0000 + // Set command : 0x8000_0024 ==> 0x0000_003B + //================================= + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) + { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_83100_Flash_Write(tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + //================================== + // AHB_I2C Burst Read + // Set SPI data register : 0x8000_002C ==> 0x00 + //================================== + out_buffer[0] = 0x2C; + out_buffer[1] = 0x00; + out_buffer[2] = 0x00; + out_buffer[3] = 0x80; + i2c_himax_write(private_ts->client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES); + + //================================== + // Read access : 0x0C ==> 0x00 + //================================== + out_buffer[0] = 0x00; + i2c_himax_write(private_ts->client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES); + + //================================== + // Read 128 bytes two times + //================================== + i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + for (i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + + i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + for (i = 0; i < 128; i++) + flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; + + //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + //himax_register_read(tmp_addr, 32, out in_buffer); + //for (int i = 0; i < 128; i++) + // flash_buffer[i + page_prog_start] = in_buffer[i]; + //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + //himax_register_read(tmp_addr, 32, out in_buffer); + //for (int i = 0; i < 128; i++) + // flash_buffer[i + page_prog_start] = in_buffer[i]; + + I("%s:Verify Progress: %x\n", __func__, page_prog_start); + } + + fail_cnt = 0; + for (i = 0; i < FW_Size; i++) + { + if (FW_File[i] != flash_buffer[i]) + { + if (fail_cnt == 0) + fail_addr = i; + + fail_cnt++; + //E("%s Fail Block:%x\n", __func__, i); + //return false; + } + } + if (fail_cnt > 0) + { + E("%s:Start Fail Block:%x and fail block count=%x\n" , __func__,fail_addr,fail_cnt); + return false; + } + + I("%s:Byte read verify pass.\n", __func__); + return true; + +} +#endif + +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data) +{ + int i; + int cnt = 0; + unsigned char tmp_addr[4]; + unsigned char tmp_data[4]; + uint8_t max_i2c_size = 32; + int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; + int total_size_4bytes = total_size / 4; + int total_read_times = 0; + unsigned long address = 0x08000468; + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; + himax_flash_write_burst(client, tmp_addr, tmp_data); + do + { + cnt++; + himax_register_read(client, tmp_addr, 1, tmp_data); + usleep_range(10000, 20000); + } while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100); + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; + if (total_size_4bytes % max_i2c_size == 0) + { + total_read_times = total_size_4bytes / max_i2c_size; + } + else + { + total_read_times = total_size_4bytes / max_i2c_size + 1; + } + for (i = 0; i < (total_read_times); i++) + { + if ( total_size_4bytes >= max_i2c_size) + { + himax_register_read(client, tmp_addr, max_i2c_size, &info_data[i*max_i2c_size*4]); + total_size_4bytes = total_size_4bytes - max_i2c_size; + } + else + { + himax_register_read(client, tmp_addr, total_size_4bytes % max_i2c_size, &info_data[i*max_i2c_size*4]); + } + address += max_i2c_size*4; + tmp_addr[1] = (uint8_t)((address>>8)&0x00FF); + tmp_addr[0] = (uint8_t)((address)&0x00FF); + } + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x11; tmp_data[2] = 0x22; tmp_data[1] = 0x33; tmp_data[0] = 0x44; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} +//ts_work +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max){ + int RawDataLen; + if (raw_cnt_rmd != 0x00) { + RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+3)*4) - 1; + }else{ + RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+2)*4) - 1; + } + return RawDataLen; +} + +bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length) +{ + uint8_t cmd[4]; + + if(length > 56) + length = 124; + //===================== + //AHB I2C Burst Read + //===================== + cmd[0] = 0x31; + if ( i2c_himax_write(client, 0x13 ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + + cmd[0] = 0x10; + if ( i2c_himax_write(client, 0x0D ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + //===================== + //Read event stack + //===================== + cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; + if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + + cmd[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + i2c_himax_read(client, 0x08, buf, length,HIMAX_I2C_RETRY_TIMES); + return 1; + + err_workqueue_out: + return 0; +} + +bool post_read_event_stack(struct i2c_client *client) +{ + return 1; +} +bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf) //return checksum value +{ + uint16_t check_sum_cal = 0; + int i; + + //Check 124th byte CRC + for (i = hx_touch_info_size, check_sum_cal = 0; i < 124; i=i+2) + { + check_sum_cal += (buf[i+1]*256 + buf[i]); + } + if (check_sum_cal % 0x10000 != 0) + { + I("%s: diag check sum fail! check_sum_cal=%X, hx_touch_info_size=%d, \n",__func__,check_sum_cal, hx_touch_info_size); + return 0; + } + return 1; +} + + +void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) +{ + int RawDataLen_word; + int index = 0; + int temp1, temp2,i; + + if (buf[hx_touch_info_size] == 0x3A && buf[hx_touch_info_size+1] == 0xA3 && buf[hx_touch_info_size+2] > 0 && buf[hx_touch_info_size+3] == diag_cmd+5 ) + { + RawDataLen_word = RawDataLen/2; + index = (buf[hx_touch_info_size+2] - 1) * RawDataLen_word; + //I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + for (i = 0; i < RawDataLen_word; i++) + { + temp1 = index + i; + + if (temp1 < mul_num) + { //mutual + mutual_data[index + i] = buf[i*2 + hx_touch_info_size+4+1]*256 + buf[i*2 + hx_touch_info_size+4]; //4: RawData Header, 1:HSB + } + else + {//self + temp1 = i + index; + temp2 = self_num + mul_num; + + if (temp1 >= temp2) + { + break; + } + + self_data[i+index-mul_num] = buf[i*2 + hx_touch_info_size+4]; //4: RawData Header + self_data[i+index-mul_num+1] = buf[i*2 + hx_touch_info_size+4+1]; + } + } + } + else + { + I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); + I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + } +} diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h new file mode 100644 index 000000000000..18cd12b8b36f --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic.h @@ -0,0 +1,82 @@ +/* Himax Android Driver Sample Code for HMX83100 chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#include <linux/slab.h> + + +#define HX_85XX_A_SERIES_PWON 1 +#define HX_85XX_B_SERIES_PWON 2 +#define HX_85XX_C_SERIES_PWON 3 +#define HX_85XX_D_SERIES_PWON 4 +#define HX_85XX_E_SERIES_PWON 5 +#define HX_85XX_ES_SERIES_PWON 6 +#define HX_85XX_F_SERIES_PWON 7 +#define HX_83100_SERIES_PWON 8 + +#define HX_TP_BIN_CHECKSUM_SW 1 +#define HX_TP_BIN_CHECKSUM_HW 2 +#define HX_TP_BIN_CHECKSUM_CRC 3 + +enum fw_image_type { + fw_image_60k = 0x01, + fw_image_64k, + fw_image_124k, + fw_image_128k, +}; + +int himax_hand_shaking(struct i2c_client *client); +void himax_set_SMWP_enable(struct i2c_client *client,uint8_t SMWP_enable); +void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data); +void himax_set_HSEN_enable(struct i2c_client *client,uint8_t HSEN_enable); +void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data); +void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command); +void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); +int himax_chip_self_test(struct i2c_client *client); +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); ////himax_83100_BURST_INC0_EN +void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data); ////RegisterRead83100 +void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data); ////himax_83100_Flash_Read +void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data); ////himax_83100_Flash_Write_Burst +int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length); ////himax_83100_Flash_Write_Burst_lenth +int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data); ////RegisterWrite83100 +void himax_sense_off(struct i2c_client *client); ////himax_83100_SenseOff +void himax_interface_on(struct i2c_client *client); ////himax_83100_Interface_on +bool wait_wip(struct i2c_client *client, int Timing); +void himax_sense_on(struct i2c_client *client, uint8_t FlashMode); ////himax_83100_SenseOn +void himax_chip_erase(struct i2c_client *client); ////himax_83100_Chip_Erase +bool himax_block_erase(struct i2c_client *client); ////himax_83100_Block_Erase +bool himax_sector_erase(struct i2c_client *client, int start_addr); ////himax_83100_Sector_Erase +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); ////himax_83100_Sram_Write +bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size); ////himax_83100_Sram_Verify +void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size); ////himax_83100_Flash_Programming +bool himax_check_chip_version(struct i2c_client *client); ////himax_83100_CheckChipVersion +int himax_check_CRC(struct i2c_client *client, int mode); ////himax_83100_Check_CRC +bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode); +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); +void himax_touch_information(struct i2c_client *client); +void himax_read_FW_ver(struct i2c_client *client); +bool himax_ic_package_check(struct i2c_client *client); +void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length); +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); +bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length); +bool post_read_event_stack(struct i2c_client *client); +bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf_ts); //return checksum value +void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf_ts, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data);
\ No newline at end of file diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c new file mode 100644 index 000000000000..7e8a1d6572c5 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -0,0 +1,796 @@ +/* Himax Android Driver Sample Code for HIMAX chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +int irq_enable_count = 0; +#ifdef HX_SMART_WAKEUP +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) +#endif + +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" + +extern struct himax_ic_data* ic_data; +extern void himax_ts_work(struct himax_ts_data *ts); +extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); +extern int himax_ts_init(struct himax_ts_data *ts); + +extern int tp_rst_gpio; + +#ifdef HX_TP_PROC_DIAG +extern uint8_t getDiagCommand(void); +#endif + +void himax_vk_parser(struct device_node *dt, + struct himax_i2c_platform_data *pdata) +{ + u32 data = 0; + uint8_t cnt = 0, i = 0; + uint32_t coords[4] = {0}; + struct device_node *node, *pp = NULL; + struct himax_virtual_key *vk; + + node = of_parse_phandle(dt, "virtualkey", 0); + if (node == NULL) { + I(" DT-No vk info in DT"); + return; + } else { + while ((pp = of_get_next_child(node, pp))) + cnt++; + if (!cnt) + return; + + vk = kzalloc(cnt * (sizeof *vk), GFP_KERNEL); + if (!vk) + return; + pp = NULL; + while ((pp = of_get_next_child(node, pp))) { + if (of_property_read_u32(pp, "idx", &data) == 0) + vk[i].index = data; + if (of_property_read_u32_array(pp, "range", coords, 4) == 0) { + vk[i].x_range_min = coords[0], vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2], vk[i].y_range_max = coords[3]; + } else + I(" range faile"); + i++; + } + pdata->virtual_key = vk; + for (i = 0; i < cnt; i++) + I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, pdata->virtual_key[i].y_range_max); + } +} + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata) +{ + int rc, coords_size = 0; + uint32_t coords[4] = {0}; + struct property *prop; + struct device_node *dt = ts->client->dev.of_node; + u32 data = 0; + + prop = of_find_property(dt, "himax,panel-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid panel coords size %d", __func__, coords_size); + } + + if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) { + pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; + pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, + pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); + } + + prop = of_find_property(dt, "himax,display-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid display coords size %d", __func__, coords_size); + } + rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size); + if (rc && (rc != -EINVAL)) { + D(" %s:Fail to read display-coords %d\n", __func__, rc); + return rc; + } + pdata->screenWidth = coords[1]; + pdata->screenHeight = coords[3]; + I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth, + pdata->screenHeight); + + pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); + if (!gpio_is_valid(pdata->gpio_irq)) { + I(" DT:gpio_irq value is not valid\n"); + } + + pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); + if (!gpio_is_valid(pdata->gpio_reset)) { + I(" DT:gpio_rst value is not valid\n"); + } + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); + if (!gpio_is_valid(pdata->gpio_3v3_en)) { + I(" DT:gpio_3v3_en value is not valid\n"); + } + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); + + if (of_property_read_u32(dt, "report_type", &data) == 0) { + pdata->protocol_type = data; + I(" DT:protocol_type=%d", pdata->protocol_type); + } + + himax_vk_parser(dt, pdata); + + return 0; +} + +int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) + break; + msleep(20); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; + +} + +int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length + 1]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length + 1, + .buf = buf, + } + }; + + buf[0] = command; + memcpy(buf+1, data, length); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; + +} + +int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; +} + +int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry) +{ + return i2c_himax_write(client, command, NULL, 0, toRetry); +} + +int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length, + .buf = buf, + } + }; + + memcpy(buf, data, length); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; +} + +void himax_int_enable(int irqnum, int enable) +{ + if (enable == 1 && irq_enable_count == 0) { + enable_irq(irqnum); + irq_enable_count++; + } else if (enable == 0 && irq_enable_count == 1) { + disable_irq_nosync(irqnum); + irq_enable_count--; + } + I("irq_enable_count = %d", irq_enable_count); +} + +void himax_rst_gpio_set(int pinnum, uint8_t value) +{ + gpio_direction_output(pinnum, value); +} + +uint8_t himax_int_gpio_read(int pinnum) +{ + return gpio_get_value(pinnum); +} + +#if defined(CONFIG_HMX_DB) +static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +{ + int retval; + pdata->vcc_dig = regulator_get(&client->dev, + "vdd"); + if (IS_ERR(pdata->vcc_dig)) + { + E("%s: Failed to get regulator vdd\n", + __func__); + retval = PTR_ERR(pdata->vcc_dig); + return retval; + } + pdata->vcc_ana = regulator_get(&client->dev, + "avdd"); + if (IS_ERR(pdata->vcc_ana)) + { + E("%s: Failed to get regulator avdd\n", + __func__); + retval = PTR_ERR(pdata->vcc_ana); + regulator_put(pdata->vcc_ana); + return retval; + } + + return 0; +}; + +static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on) +{ + int retval; + + if (on) + { + retval = regulator_enable(pdata->vcc_dig); + if (retval) + { + E("%s: Failed to enable regulator vdd\n", + __func__); + return retval; + } + msleep(100); + retval = regulator_enable(pdata->vcc_ana); + if (retval) + { + E("%s: Failed to enable regulator avdd\n", + __func__); + regulator_disable(pdata->vcc_dig); + return retval; + } + } + else + { + regulator_disable(pdata->vcc_dig); + regulator_disable(pdata->vcc_ana); + } + + return 0; +} + +int himax_ts_pinctrl_init(struct himax_ts_data *ts) +{ + int retval; + + /* Get pinctrl if target uses pinctrl */ + ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); + if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { + retval = PTR_ERR(ts->ts_pinctrl); + dev_dbg(&ts->client->dev, + "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + ts->pinctrl_state_active + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { + retval = PTR_ERR(ts->pinctrl_state_active); + dev_err(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_suspend + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { + retval = PTR_ERR(ts->pinctrl_state_suspend); + dev_err(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_release + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_RELEASE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + retval = PTR_ERR(ts->pinctrl_state_release); + dev_dbg(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); + } + + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(ts->ts_pinctrl); +err_pinctrl_get: + ts->ts_pinctrl = NULL; + return retval; +} + +int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +{ + int error; + + error = himax_regulator_configure(client, pdata); + if (error) + { + E("Failed to intialize hardware\n"); + goto err_regulator_not_on; + } + +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + if (error) + { + E("unable to request gpio [%d]\n", + pdata->gpio_reset); + goto err_regulator_on; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_req; + } + } +#endif + + error = himax_power_on(pdata, true); + if (error) + { + E("Failed to power on hardware\n"); + goto err_gpio_reset_req; + } +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) + { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + if (error) + { + E("unable to request gpio [%d]\n", + pdata->gpio_irq); + goto err_power_on; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_req; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } + else + { + E("irq gpio not provided\n"); + goto err_power_on; + } +#endif + + msleep(20); + +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_irq_req; + } + } +#endif + return 0; +#ifdef HX_RST_PIN_FUNC + err_gpio_irq_req: +#endif +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); + err_power_on: +#endif + himax_power_on(pdata, false); + err_gpio_reset_req: +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); + err_regulator_on: +#endif + err_regulator_not_on: + + return error; +} + +#else +int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +{ + int error=0; + +#ifdef HX_RST_PIN_FUNC + if (pdata->gpio_reset >= 0) + { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + if (error < 0) + { + E("%s: request reset pin failed\n", __func__); + return error; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } +#endif + if (pdata->gpio_3v3_en >= 0) + { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + if (error < 0) + { + E("%s: request 3v3_en pin failed\n", __func__); + return error; + } + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + } + +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) + { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + if (error) + { + E("unable to request gpio [%d]\n",pdata->gpio_irq); + return error; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) + { + E("unable to set direction for gpio [%d]\n",pdata->gpio_irq); + return error; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } + else + { + E("irq gpio not provided\n"); + return error; + } +#endif + + msleep(20); + +#ifdef HX_RST_PIN_FUNC + if (pdata->gpio_reset >= 0) + { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } + msleep(20); +#endif + + return error; + } +#endif + +static void himax_ts_isr_func(struct himax_ts_data *ts) +{ + himax_ts_work(ts); +} + +irqreturn_t himax_ts_thread(int irq, void *ptr) +{ + uint8_t diag_cmd; + struct himax_ts_data *ts = ptr; + struct timespec timeStart, timeEnd, timeDelta; + + diag_cmd = getDiagCommand(); + + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeStart); + usleep_range(5000, 7000); + //I(" Irq start time = %ld.%06ld s\n", + // timeStart.tv_sec, timeStart.tv_nsec/1000); + } + +#ifdef HX_SMART_WAKEUP + if (atomic_read(&ts->suspend_mode)&&(!FAKE_POWER_KEY_SEND)&&(ts->SMWP_enable)&&(!diag_cmd)) { + wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + msleep(200); + himax_wake_check_func(); + return IRQ_HANDLED; + } +#endif + himax_ts_isr_func((struct himax_ts_data *)ptr); + if(ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeEnd); + timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec) + -(timeStart.tv_sec*1000000000+timeStart.tv_nsec); + //I("Irq finish time = %ld.%06ld s\n", + // timeEnd.tv_sec, timeEnd.tv_nsec/1000); + //I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000); + } + return IRQ_HANDLED; +} + +static void himax_ts_work_func(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work); + himax_ts_work(ts); +} + +int tp_irq = -1; + +int himax_ts_register_interrupt(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret = 0; + + ts->irq_enabled = 0; + //Work functon + if (client->irq) {/*INT mode*/ + ts->use_irq = 1; + if(ic_data->HX_INT_IS_EDGE) + { + I("%s edge triiger falling\n ",__func__); + ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); + } + else + { + I("%s level trigger low\n ",__func__); + ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + tp_irq = client->irq; + I("%s: irq enabled at qpio: %d\n", __func__, client->irq); +#ifdef HX_SMART_WAKEUP + irq_set_irq_wake(client->irq, 1); +#endif + } else { + ts->use_irq = 0; + E("%s: request_irq failed\n", __func__); + } + } else { + I("%s: client->irq is empty, use polling mode.\n", __func__); + } + + if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + ts->himax_wq = create_singlethread_workqueue("himax_touch"); + + INIT_WORK(&ts->work, himax_ts_work_func); + + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = himax_ts_timer_func; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + I("%s: polling mode enabled\n", __func__); + } + return ret; +} + +static int himax_common_suspend(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter \n", __func__); + + himax_chip_common_suspend(ts); + return 0; +} + +static int himax_common_resume(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter \n", __func__); + + himax_chip_common_resume(ts); + return 0; +} + +#if defined(CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct himax_ts_data *ts= + container_of(self, struct himax_ts_data, fb_notif); + + I(" %s\n", __func__); + if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && + ts->client) { + blank = evdata->data; + + mutex_lock(&ts->fb_mutex); + switch (*blank) { + case FB_BLANK_UNBLANK: + if (!ts->probe_done) { + himax_ts_init(ts); + ts->probe_done = true; + } else { + himax_common_resume(&ts->client->dev); + } + break; + + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + himax_common_suspend(&ts->client->dev); + break; + } + mutex_unlock(&ts->fb_mutex); + } + + return 0; +} +#endif + +static const struct i2c_device_id himax_common_ts_id[] = { + {HIMAX_common_NAME, 0 }, + {} +}; + +static const struct dev_pm_ops himax_common_pm_ops = { +#if (!defined(CONFIG_FB)) + .suspend = himax_common_suspend, + .resume = himax_common_resume, +#endif +}; + +#ifdef CONFIG_OF +static const struct of_device_id himax_match_table[] = { + {.compatible = "himax,hxcommon" }, + {}, +}; +#else +#define himax_match_table NULL +#endif + +static struct i2c_driver himax_common_driver = { + .id_table = himax_common_ts_id, + .probe = himax_chip_common_probe, + .remove = himax_chip_common_remove, + .driver = { + .name = HIMAX_common_NAME, + .owner = THIS_MODULE, + .of_match_table = himax_match_table, +#ifdef CONFIG_PM + .pm = &himax_common_pm_ops, +#endif + }, +}; + +static void __init himax_common_init_async(void *unused, async_cookie_t cookie) +{ + I("%s:Enter \n", __func__); + i2c_add_driver(&himax_common_driver); +} + +static int __init himax_common_init(void) +{ + I("Himax common touch panel driver init\n"); + async_schedule(himax_common_init_async, NULL); + return 0; +} + +static void __exit himax_common_exit(void) +{ + i2c_del_driver(&himax_common_driver); +} + +module_init(himax_common_init); +module_exit(himax_common_exit); + +MODULE_DESCRIPTION("Himax_common driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h new file mode 100644 index 000000000000..1223685683aa --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -0,0 +1,135 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_PLATFORM_H +#define HIMAX_PLATFORM_H + +#include <linux/delay.h> +#include <linux/fs.h> +#include <linux/gpio.h> +#include <linux/types.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#if defined(CONFIG_HMX_DB) +#include <linux/regulator/consumer.h> +#endif + +#define QCT + +#define HIMAX_I2C_RETRY_TIMES 10 + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_debug("[HXTP] " x) +#define I(x...) pr_info("[HXTP] " x) +#define W(x...) pr_warning("[HXTP][WARNING] " x) +#define E(x...) pr_err("[HXTP][ERROR] " x) +#define DIF(x...) \ +do {\ + if (debug_flag) \ + pr_debug("[HXTP][DEBUG] " x) \ +} while(0) +#else +#define D(x...) +#define I(x...) +#define W(x...) +#define E(x...) +#define DIF(x...) +#endif + +#if defined(CONFIG_HMX_DB) +/* Analog voltage @2.7 V */ +#define HX_VTG_MIN_UV 2700000 +#define HX_VTG_MAX_UV 3300000 +#define HX_ACTIVE_LOAD_UA 15000 +#define HX_LPM_LOAD_UA 10 +/* Digital voltage @1.8 V */ +#define HX_VTG_DIG_MIN_UV 1800000 +#define HX_VTG_DIG_MAX_UV 1800000 +#define HX_ACTIVE_LOAD_DIG_UA 10000 +#define HX_LPM_LOAD_DIG_UA 10 + +#define HX_I2C_VTG_MIN_UV 1800000 +#define HX_I2C_VTG_MAX_UV 1800000 +#define HX_I2C_LOAD_UA 10000 +#define HX_I2C_LPM_LOAD_UA 10 +#endif + +#define HIMAX_common_NAME "himax_tp" +#define HIMAX_I2C_ADDR 0x48 +#define INPUT_DEV_NAME "himax-touchscreen" + +struct himax_i2c_platform_data { + int abs_x_min; + int abs_x_max; + int abs_x_fuzz; + int abs_y_min; + int abs_y_max; + int abs_y_fuzz; + int abs_pressure_min; + int abs_pressure_max; + int abs_pressure_fuzz; + int abs_width_min; + int abs_width_max; + int screenWidth; + int screenHeight; + uint8_t fw_version; + uint8_t tw_id; + uint8_t powerOff3V3; + uint8_t cable_config[2]; + uint8_t protocol_type; + int gpio_irq; + int gpio_reset; + int gpio_3v3_en; + int (*power)(int on); + void (*reset)(void); + struct himax_virtual_key *virtual_key; + struct kobject *vk_obj; + struct kobj_attribute *vk2Use; + + struct himax_config *hx_config; + int hx_config_size; +#if defined(CONFIG_HMX_DB) + bool i2c_pull_up; + bool digital_pwr_regulator; + int reset_gpio; + u32 reset_gpio_flags; + int irq_gpio; + u32 irq_gpio_flags; + + struct regulator *vcc_ana; //For Dragon Board + struct regulator *vcc_dig; //For Dragon Board + struct regulator *vcc_i2c; //For Dragon Board +#endif +}; + + +extern int irq_enable_count; +extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry); +extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); +extern void himax_int_enable(int irqnum, int enable); +extern int himax_ts_register_interrupt(struct i2c_client *client); +extern void himax_rst_gpio_set(int pinnum, uint8_t value); +extern uint8_t himax_int_gpio_read(int pinnum); + +extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata); + +#if defined(CONFIG_FB) +extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +#endif + +#endif diff --git a/drivers/media/platform/msm/ais/isp/msm_isp_util.c b/drivers/media/platform/msm/ais/isp/msm_isp_util.c index 2c670eea1852..60f0983ad519 100644 --- a/drivers/media/platform/msm/ais/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/ais/isp/msm_isp_util.c @@ -918,9 +918,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_CFG_STREAM: mutex_lock(&vfe_dev->core_mutex); - mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_cfg_axi_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->buf_mgr->lock); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_CFG_HW_STATE: @@ -1021,9 +1019,7 @@ static long msm_isp_ioctl_unlocked(struct v4l2_subdev *sd, break; case VIDIOC_MSM_ISP_CFG_STATS_STREAM: mutex_lock(&vfe_dev->core_mutex); - mutex_lock(&vfe_dev->buf_mgr->lock); rc = msm_isp_cfg_stats_stream(vfe_dev, arg); - mutex_unlock(&vfe_dev->buf_mgr->lock); mutex_unlock(&vfe_dev->core_mutex); break; case VIDIOC_MSM_ISP_UPDATE_STATS_STREAM: diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c index aec7faa65bad..40c343014501 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -652,6 +652,8 @@ int vfe_hw_probe(struct platform_device *pdev) spin_lock_init(&vfe_dev->shared_data_lock); spin_lock_init(&vfe_dev->reg_update_lock); spin_lock_init(&req_history_lock); + spin_lock_init(&vfe_dev->reset_completion_lock); + spin_lock_init(&vfe_dev->halt_completion_lock); media_entity_init(&vfe_dev->subdev.sd.entity, 0, NULL, 0); vfe_dev->subdev.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; vfe_dev->subdev.sd.entity.group_id = MSM_CAMERA_SUBDEV_VFE; diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index d223401d8688..f1cf72e53b6d 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -740,6 +740,8 @@ struct vfe_device { struct mutex core_mutex; spinlock_t shared_data_lock; spinlock_t reg_update_lock; + spinlock_t reset_completion_lock; + spinlock_t halt_completion_lock; spinlock_t tasklet_lock; /* Tasklet info */ diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c index c216defef880..d494328e82cc 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp40.c @@ -358,15 +358,24 @@ static void msm_vfe40_clear_status_reg(struct vfe_device *vfe_dev) static void msm_vfe40_process_reset_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1) { - if (irq_status0 & (1 << 31)) + unsigned long flags; + + if (irq_status0 & (1 << 31)) { + spin_lock_irqsave(&vfe_dev->reset_completion_lock, flags); complete(&vfe_dev->reset_complete); + spin_unlock_irqrestore(&vfe_dev->reset_completion_lock, flags); + } } static void msm_vfe40_process_halt_irq(struct vfe_device *vfe_dev, uint32_t irq_status0, uint32_t irq_status1) { + unsigned long flags; + if (irq_status1 & (1 << 8)) { + spin_lock_irqsave(&vfe_dev->halt_completion_lock, flags); complete(&vfe_dev->halt_complete); + spin_unlock_irqrestore(&vfe_dev->halt_completion_lock, flags); msm_camera_io_w(0x0, vfe_dev->vfe_base + 0x2C0); } } @@ -756,7 +765,11 @@ static long msm_vfe40_reset_hardware(struct vfe_device *vfe_dev, uint32_t first_start, uint32_t blocking_call) { long rc = 0; + unsigned long flags; + + spin_lock_irqsave(&vfe_dev->reset_completion_lock, flags); init_completion(&vfe_dev->reset_complete); + spin_unlock_irqrestore(&vfe_dev->reset_completion_lock, flags); if (first_start) { msm_camera_io_w_mb(0x1FF, vfe_dev->vfe_base + 0xC); @@ -1720,6 +1733,7 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, { int rc = 0; enum msm_vfe_input_src i; + unsigned long flags; /* Keep only halt and restart mask */ msm_vfe40_set_halt_restart_mask(vfe_dev); @@ -1754,7 +1768,9 @@ static int msm_vfe40_axi_halt(struct vfe_device *vfe_dev, } if (blocking) { + spin_lock_irqsave(&vfe_dev->halt_completion_lock, flags); init_completion(&vfe_dev->halt_complete); + spin_unlock_irqrestore(&vfe_dev->halt_completion_lock, flags); /* Halt AXI Bus Bridge */ msm_camera_io_w_mb(0x1, vfe_dev->vfe_base + 0x2C0); rc = wait_for_completion_interruptible_timeout( diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 14f95e15b45b..b008bbf10eed 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -1635,12 +1635,38 @@ void msm_isp_halt_send_error(struct vfe_device *vfe_dev, uint32_t event) struct msm_isp_event_data error_event; struct msm_vfe_axi_halt_cmd halt_cmd; uint32_t irq_status0, irq_status1; + struct vfe_device *vfe_dev_other = NULL; + uint32_t vfe_id_other = 0; + unsigned long flags; if (atomic_read(&vfe_dev->error_info.overflow_state) != NO_OVERFLOW) /* Recovery is already in Progress */ return; + /* if there are no active streams - do not start recovery */ + if (vfe_dev->is_split) { + if (vfe_dev->pdev->id == ISP_VFE0) + vfe_id_other = ISP_VFE1; + else + vfe_id_other = ISP_VFE0; + spin_lock_irqsave( + &vfe_dev->common_data->common_dev_data_lock, flags); + vfe_dev_other = vfe_dev->common_data->dual_vfe_res-> + vfe_dev[vfe_id_other]; + if (!vfe_dev->axi_data.num_active_stream || + !vfe_dev_other->axi_data.num_active_stream) { + spin_unlock_irqrestore( + &vfe_dev->common_data->common_dev_data_lock, + flags); + pr_err("%s:skip the recovery as no active streams\n", + __func__); + return; + } + spin_unlock_irqrestore( + &vfe_dev->common_data->common_dev_data_lock, flags); + } else if (!vfe_dev->axi_data.num_active_stream) + return; if (ISP_EVENT_PING_PONG_MISMATCH == event && vfe_dev->axi_data.recovery_count < MAX_RECOVERY_THRESHOLD) { vfe_dev->hw_info->vfe_ops.irq_ops. diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c index c77944a0a047..0a4b80e5cbe2 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_stats_util.c @@ -689,8 +689,10 @@ static int msm_isp_start_stats_stream(struct vfe_device *vfe_dev, vfe_dev->hw_info->stats_hw_info->num_stats_comp_mask; rc = vfe_dev->hw_info->vfe_ops.stats_ops.check_streams( stats_data->stream_info); - if (rc < 0) + if (rc < 0) { + mutex_unlock(&vfe_dev->buf_mgr->lock); return rc; + } for (i = 0; i < stream_cfg_cmd->num_streams; i++) { idx = STATS_IDX(stream_cfg_cmd->stream_handle[i]); diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.c index 7c12fb9af6c4..9d6c0a9da277 100644 --- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.c +++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif_32.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -43,6 +43,8 @@ #define ISPIF_TIMEOUT_SLEEP_US 1000 #define ISPIF_TIMEOUT_ALL_US 1000000 +#define CSID_VERSION_V37 0x30070000 + #undef CDBG #ifdef CONFIG_MSMB_CAMERA_DEBUG #define CDBG(fmt, args...) pr_debug(fmt, ##args) @@ -123,6 +125,11 @@ static int msm_ispif_reset_hw(struct ispif_device *ispif) ispif->clk_idx = 0; + if (ispif->csid_version != CSID_VERSION_V37) { + pr_err("%s:%d error returning\n", __func__, __LINE__); + return -EINVAL; + } + rc = msm_cam_clk_enable(&ispif->pdev->dev, ispif_8974_reset_clk_info, reset_clk, ARRAY_SIZE(ispif_8974_reset_clk_info), 1); @@ -1255,8 +1262,12 @@ static int msm_ispif_init(struct ispif_device *ispif, goto error_ahb; } - msm_ispif_reset_hw(ispif); - + rc = msm_ispif_reset_hw(ispif); + if (rc < 0) { + pr_err("%s:%d msm_ispif_reset_hw failed\n", __func__, + __LINE__); + goto error_ahb; + } rc = msm_ispif_reset(ispif); if (rc == 0) { ispif->ispif_state = ISPIF_POWER_UP; diff --git a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c index 4e03a7eac022..994d9de0e643 100644 --- a/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c +++ b/drivers/media/platform/msm/camera_v2/msm_buf_mgr/msm_generic_buf_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -74,9 +74,6 @@ static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev, new_entry->session_id = buf_info->session_id; new_entry->stream_id = buf_info->stream_id; new_entry->index = new_entry->vb2_buf->v4l2_buf.index; - spin_lock_irqsave(&dev->buf_q_spinlock, flags); - list_add_tail(&new_entry->entry, &dev->buf_qhead); - spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); buf_info->index = new_entry->vb2_buf->v4l2_buf.index; if (buf_info->type == MSM_CAMERA_BUF_MNGR_BUF_USER) { mutex_lock(&dev->cont_mutex); @@ -89,6 +86,16 @@ static int32_t msm_buf_mngr_get_buf(struct msm_buf_mngr_device *dev, } mutex_unlock(&dev->cont_mutex); } + if (!rc) { + spin_lock_irqsave(&dev->buf_q_spinlock, flags); + list_add_tail(&new_entry->entry, &dev->buf_qhead); + spin_unlock_irqrestore(&dev->buf_q_spinlock, flags); + } else { + pr_err("List not empty or msm_buf_mngr_hdl_cont_get_buf failed %pK\n", + new_entry->vb2_buf); + kfree(new_entry); + } + return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 30ef850da4a3..026b4e308123 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -3032,7 +3032,7 @@ static int set_output_buffers(struct msm_vidc_inst *inst, { int rc = 0; struct msm_smem *handle; - struct internal_buf *binfo; + struct internal_buf *binfo = NULL; u32 smem_flags = 0, buffer_size; struct hal_buffer_requirements *output_buf, *extradata_buf; int i; @@ -3138,10 +3138,10 @@ static int set_output_buffers(struct msm_vidc_inst *inst, } return rc; fail_set_buffers: - kfree(binfo); -fail_kzalloc: msm_comm_smem_free(inst, handle); err_no_mem: + kfree(binfo); +fail_kzalloc: return rc; } diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 84a0a9bbd125..f2955be61899 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1,6 +1,6 @@ /*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver * - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -109,6 +109,9 @@ #define DEFAULT_CE_INFO_UNIT 0 #define DEFAULT_NUM_CE_INFO_UNIT 1 +#define FDE_FLAG_POS 4 +#define ENABLE_KEY_WRAP_IN_KS (1 << FDE_FLAG_POS) + enum qseecom_clk_definitions { CLK_DFAB = 0, CLK_SFPB, @@ -273,6 +276,7 @@ struct qseecom_control { unsigned int ce_opp_freq_hz; bool appsbl_qseecom_support; uint32_t qsee_reentrancy_support; + bool enable_key_wrap_in_ks; uint32_t app_block_ref_cnt; wait_queue_head_t app_block_wq; @@ -5779,6 +5783,9 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, else flags |= QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE; + if (qseecom.enable_key_wrap_in_ks == true) + flags |= ENABLE_KEY_WRAP_IN_KS; + generate_key_ireq.flags = flags; generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY; memset((void *)generate_key_ireq.key_id, @@ -8467,6 +8474,14 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.qsee_reentrancy_support); } + qseecom.enable_key_wrap_in_ks = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,enable-key-wrap-in-ks"); + if (qseecom.enable_key_wrap_in_ks) { + pr_warn("qseecom.enable_key_wrap_in_ks = %d\n", + qseecom.enable_key_wrap_in_ks); + } + /* * The qseecom bus scaling flag can not be enabled when * crypto clock is not handled by HLOS. diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index b4ad723b4e36..7cceec44d2d8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -3002,6 +3002,13 @@ static void _mmc_detect_change(struct mmc_host *host, unsigned long delay, pm_wakeup_event(mmc_dev(host), 5000); host->detect_change = 1; + /* + * Change in cd_gpio state, so make sure detection part is + * not overided because of manual resume. + */ + if (cd_irq && mmc_bus_manual_resume(host)) + host->ignore_bus_resume_flags = true; + mmc_schedule_delayed_work(&host->detect, delay); } @@ -3923,6 +3930,8 @@ void mmc_rescan(struct work_struct *work) host->bus_ops->detect(host); host->detect_change = 0; + if (host->ignore_bus_resume_flags) + host->ignore_bus_resume_flags = false; /* * Let mmc_bus_put() free the bus/bus_ops if we've found that @@ -4184,7 +4193,8 @@ int mmc_pm_notify(struct notifier_block *notify_block, spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 0; - if (mmc_bus_manual_resume(host)) { + if (mmc_bus_manual_resume(host) && + !host->ignore_bus_resume_flags) { spin_unlock_irqrestore(&host->lock, flags); break; } diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c index 071adc101158..1b4e40c0aff6 100644 --- a/drivers/mmc/core/quirks.c +++ b/drivers/mmc/core/quirks.c @@ -79,6 +79,13 @@ #define SDIO_DEVICE_ID_QCA9377 0x701 #endif +#ifndef SDIO_VENDOR_ID_QCA9379 +#define SDIO_VENDOR_ID_QCA9379 0x271 +#endif + +#ifndef SDIO_DEVICE_ID_QCA9379 +#define SDIO_DEVICE_ID_QCA9379 0x801 +#endif /* * This hook just adds a quirk for all sdio devices @@ -131,6 +138,9 @@ static const struct mmc_fixup mmc_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_QCA9377, SDIO_DEVICE_ID_QCA9377, add_quirk, MMC_QUIRK_QCA9377_SETTINGS), + + SDIO_FIXUP(SDIO_VENDOR_ID_QCA9379, SDIO_DEVICE_ID_QCA9379, + add_quirk, MMC_QUIRK_QCA9379_SETTINGS), END_FIXUP }; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index a29c4b2c8e97..b58bf6d1f505 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1234,7 +1234,10 @@ static int mmc_sd_suspend(struct mmc_host *host) if (!err) { pm_runtime_disable(&host->card->dev); pm_runtime_set_suspended(&host->card->dev); - } + /* if suspend fails, force mmc_detect_change during resume */ + } else if (mmc_bus_manual_resume(host)) + host->ignore_bus_resume_flags = true; + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 5651cf63f8bd..65425a41a84f 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -228,7 +228,8 @@ static void sdio_enable_vendor_specific_settings(struct mmc_card *card) u8 settings; if (mmc_enable_qca6574_settings(card) || - mmc_enable_qca9377_settings(card)) { + mmc_enable_qca9377_settings(card) || + mmc_enable_qca9379_settings(card)) { ret = mmc_io_rw_direct(card, 1, 0, 0xF2, 0x0F, NULL); if (ret) { pr_crit("%s: failed to write to fn 0xf2 %d\n", diff --git a/drivers/net/can/spi/qti-can.c b/drivers/net/can/spi/qti-can.c index 69a3159d34b1..253e341dbb58 100644 --- a/drivers/net/can/spi/qti-can.c +++ b/drivers/net/can/spi/qti-can.c @@ -445,8 +445,8 @@ static int qti_can_process_rx(struct qti_can *priv_data, char *rx_buf) } else { data = rx_buf + length_processed; resp = (struct spi_miso *)data; - if (resp->cmd == 0) { - /* special case. ignore cmd==0 */ + if (resp->cmd == 0x00 || resp->cmd == 0xFF) { + /* special case. ignore cmd==0x00, 0xFF */ length_processed += 1; continue; } diff --git a/drivers/net/wireless/cnss/cnss_sdio.c b/drivers/net/wireless/cnss/cnss_sdio.c index fafab6910570..a2ca99f77aa3 100644 --- a/drivers/net/wireless/cnss/cnss_sdio.c +++ b/drivers/net/wireless/cnss/cnss_sdio.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -127,6 +127,7 @@ static struct cnss_sdio_data { /* SDIO manufacturer ID and Codes */ #define MANUFACTURER_ID_AR6320_BASE 0x500 #define MANUFACTURER_ID_QCA9377_BASE 0x700 +#define MANUFACTURER_ID_QCA9379_BASE 0x800 #define MANUFACTURER_CODE 0x271 static const struct sdio_device_id ar6k_id_table[] = { @@ -162,6 +163,22 @@ static const struct sdio_device_id ar6k_id_table[] = { {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))}, {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))}, {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xF))}, {}, }; MODULE_DEVICE_TABLE(sdio, ar6k_id_table); @@ -261,11 +278,6 @@ static int cnss_put_hw_resources(struct device *dev) return ret; } - if (!cnss_pdata->regulator.wlan_vreg) { - pr_debug("wlan_vreg regulator is invalid\n"); - return 0; - } - ret = mmc_power_save_host(host); if (ret) { pr_err("Failed to Power Save Host err:%d\n", @@ -273,7 +285,11 @@ static int cnss_put_hw_resources(struct device *dev) return ret; } - regulator_disable(cnss_pdata->regulator.wlan_vreg); + if (cnss_pdata->regulator.wlan_vreg) + regulator_disable(cnss_pdata->regulator.wlan_vreg); + else + pr_debug("wlan_vreg regulator is invalid\n"); + info->cnss_hw_state = CNSS_HW_SLEEP; return ret; @@ -307,22 +323,23 @@ static int cnss_get_hw_resources(struct device *dev) return ret; } - if (!cnss_pdata->regulator.wlan_vreg) { + if (cnss_pdata->regulator.wlan_vreg) { + ret = regulator_enable(cnss_pdata->regulator.wlan_vreg); + if (ret) { + pr_err("Failed to enable wlan vreg\n"); + return ret; + } + } else { pr_debug("wlan_vreg regulator is invalid\n"); - return 0; } - ret = regulator_enable(cnss_pdata->regulator.wlan_vreg); - if (ret) { - pr_err("Failed to enable wlan vreg\n"); - return ret; - } ret = mmc_power_restore_host(host); if (ret) { pr_err("Failed to restore host power ret:%d\n", ret); - regulator_disable(cnss_pdata->regulator.wlan_vreg); + if (cnss_pdata->regulator.wlan_vreg) + regulator_disable(cnss_pdata->regulator.wlan_vreg); return ret; } diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index 16bff82a116d..0261e857298a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -432,6 +432,8 @@ static ssize_t ipa_read_hdr(struct file *file, char __user *ubuf, size_t count, list_for_each_entry(entry, &ipa_ctx->hdr_tbl.head_hdr_entry_list, link) { + if (entry->cookie != IPA_HDR_COOKIE) + continue; nbytes = scnprintf( dbg_buff, IPA_MAX_MSG_LEN - 1, @@ -597,6 +599,14 @@ static int ipa_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) if (attrib->protocol_eq_present) pr_err("protocol:%d ", attrib->protocol_eq); + if (attrib->num_ihl_offset_range_16 > + IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) { + IPAERR_RL("num_ihl_offset_range_16 Max %d passed value %d\n", + IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS, + attrib->num_ihl_offset_range_16); + return -EPERM; + } + for (i = 0; i < attrib->num_ihl_offset_range_16; i++) { pr_err( "(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ", @@ -605,6 +615,12 @@ static int ipa_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_range_16[i].range_high); } + if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) { + IPAERR_RL("num_offset_meq_32 Max %d passed value %d\n", + IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32); + return -EPERM; + } + for (i = 0; i < attrib->num_offset_meq_32; i++) { pr_err( "(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ", @@ -626,6 +642,12 @@ static int ipa_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_eq_16.value); } + if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) { + IPAERR_RL("num_ihl_offset_meq_32 Max %d passed value %d\n", + IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32); + return -EPERM; + } + for (i = 0; i < attrib->num_ihl_offset_meq_32; i++) { pr_err( "(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ", @@ -634,6 +656,12 @@ static int ipa_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_meq_32[i].value); } + if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) { + IPAERR_RL("num_offset_meq_128 Max %d passed value %d\n", + IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128); + return -EPERM; + } + for (i = 0; i < attrib->num_offset_meq_128; i++) { for (j = 0; j < 16; j++) { addr[j] = attrib->offset_meq_128[i].value[j]; @@ -803,11 +831,14 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, u32 rt_tbl_idx; u32 bitmap; bool eq; + int res = 0; tbl = &ipa_ctx->glob_flt_tbl[ip]; mutex_lock(&ipa_ctx->lock); i = 0; list_for_each_entry(entry, &tbl->head_flt_rule_list, link) { + if (entry->cookie != IPA_FLT_COOKIE) + continue; if (entry->rule.eq_attrib_type) { rt_tbl_idx = entry->rule.rt_tbl_idx; bitmap = entry->rule.eq_attrib.rule_eq_bitmap; @@ -826,10 +857,14 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, i, entry->rule.action, rt_tbl_idx); pr_err("attrib_mask:%08x retain_hdr:%d eq:%d ", bitmap, entry->rule.retain_hdr, eq); - if (eq) - ipa_attrib_dump_eq( + if (eq) { + res = ipa_attrib_dump_eq( &entry->rule.eq_attrib); - else + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } + } else ipa_attrib_dump( &entry->rule.attrib, ip); i++; @@ -839,6 +874,8 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, tbl = &ipa_ctx->flt_tbl[j][ip]; i = 0; list_for_each_entry(entry, &tbl->head_flt_rule_list, link) { + if (entry->cookie != IPA_FLT_COOKIE) + continue; if (entry->rule.eq_attrib_type) { rt_tbl_idx = entry->rule.rt_tbl_idx; bitmap = entry->rule.eq_attrib.rule_eq_bitmap; @@ -858,18 +895,23 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, pr_err("attrib_mask:%08x retain_hdr:%d ", bitmap, entry->rule.retain_hdr); pr_err("eq:%d ", eq); - if (eq) - ipa_attrib_dump_eq( - &entry->rule.eq_attrib); - else + if (eq) { + res = ipa_attrib_dump_eq( + &entry->rule.eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } + } else ipa_attrib_dump( &entry->rule.attrib, ip); i++; } } +bail: mutex_unlock(&ipa_ctx->lock); - return 0; + return res; } static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 33b0e2187bc2..be6b1a49ddcf 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -531,6 +531,14 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) if (attrib->protocol_eq_present) pr_err("protocol:%d ", attrib->protocol_eq); + if (attrib->num_ihl_offset_range_16 > + IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) { + IPAERR_RL("num_ihl_offset_range_16 Max %d passed value %d\n", + IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS, + attrib->num_ihl_offset_range_16); + return -EPERM; + } + for (i = 0; i < attrib->num_ihl_offset_range_16; i++) { pr_err( "(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ", @@ -539,6 +547,12 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_range_16[i].range_high); } + if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) { + IPAERR_RL("num_offset_meq_32 Max %d passed value %d\n", + IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32); + return -EPERM; + } + for (i = 0; i < attrib->num_offset_meq_32; i++) { pr_err( "(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ", @@ -560,6 +574,13 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_eq_16.value); } + if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) { + IPAERR_RL("num_ihl_offset_meq_32 Max %d passed value %d\n", + IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, + attrib->num_ihl_offset_meq_32); + return -EPERM; + } + for (i = 0; i < attrib->num_ihl_offset_meq_32; i++) { pr_err( "(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ", @@ -568,6 +589,12 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_meq_32[i].value); } + if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) { + IPAERR_RL("num_offset_meq_128 Max %d passed value %d\n", + IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128); + return -EPERM; + } + for (i = 0; i < attrib->num_offset_meq_128; i++) { for (j = 0; j < 16; j++) { addr[j] = attrib->offset_meq_128[i].value[j]; @@ -704,6 +731,7 @@ static ssize_t ipa3_read_rt_hw(struct file *file, char __user *ubuf, struct ipa3_debugfs_rt_entry *entry; enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data; int num_tbls; + int res = 0; if (ip == IPA_IP_v4) num_tbls = IPA_MEM_PART(v4_rt_num_index); @@ -736,7 +764,11 @@ static ssize_t ipa3_read_rt_hw(struct file *file, char __user *ubuf, pr_err("rule_id:%u prio:%u retain_hdr:%u ", entry[i].rule_id, entry[i].prio, entry[i].retain_hdr); - ipa3_attrib_dump_eq(&entry[i].eq_attrib); + res = ipa3_attrib_dump_eq(&entry[i].eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } } pr_err("== HASHABLE TABLE tbl:%d ==\n", j); @@ -758,14 +790,19 @@ static ssize_t ipa3_read_rt_hw(struct file *file, char __user *ubuf, pr_err("rule_id:%u prio:%u retain_hdr:%u ", entry[i].rule_id, entry[i].prio, entry[i].retain_hdr); - ipa3_attrib_dump_eq(&entry[i].eq_attrib); + res = ipa3_attrib_dump_eq(&entry[i].eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } } } +bail: mutex_unlock(&ipa3_ctx->lock); kfree(entry); IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); - return 0; + return res; } static ssize_t ipa3_read_proc_ctx(struct file *file, char __user *ubuf, @@ -830,6 +867,7 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count, u32 rt_tbl_idx; u32 bitmap; bool eq; + int res = 0; mutex_lock(&ipa3_ctx->lock); @@ -860,18 +898,23 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count, pr_err("hashable:%u rule_id:%u max_prio:%u prio:%u ", entry->rule.hashable, entry->rule_id, entry->rule.max_prio, entry->prio); - if (eq) - ipa3_attrib_dump_eq( - &entry->rule.eq_attrib); - else + if (eq) { + res = ipa3_attrib_dump_eq( + &entry->rule.eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } + } else ipa3_attrib_dump( &entry->rule.attrib, ip); i++; } } +bail: mutex_unlock(&ipa3_ctx->lock); - return 0; + return res; } static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf, @@ -884,6 +927,7 @@ static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf, enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data; u32 rt_tbl_idx; u32 bitmap; + int res = 0; entry = kzalloc(sizeof(*entry) * IPA_DBG_MAX_RULE_IN_TBL, GFP_KERNEL); if (!entry) @@ -906,7 +950,11 @@ static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf, bitmap, entry[i].rule.retain_hdr); pr_err("rule_id:%u prio:%u ", entry[i].rule_id, entry[i].prio); - ipa3_attrib_dump_eq(&entry[i].rule.eq_attrib); + res = ipa3_attrib_dump_eq(&entry[i].rule.eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } } pr_err("== HASHABLE TABLE ep:%d ==\n", j); @@ -922,14 +970,19 @@ static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf, pr_err("rule_id:%u max_prio:%u prio:%u ", entry[i].rule_id, entry[i].rule.max_prio, entry[i].prio); - ipa3_attrib_dump_eq(&entry[i].rule.eq_attrib); + res = ipa3_attrib_dump_eq(&entry[i].rule.eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } } } +bail: mutex_unlock(&ipa3_ctx->lock); kfree(entry); IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); - return 0; + return res; } static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf, diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 0f6a0d255db6..48edff5a60f6 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -122,22 +122,18 @@ void mhi_dev_read_from_host(struct mhi_dev *mhi, struct mhi_addr *transfer) host_addr_pa = transfer->host_pa | bit_40; } - if (mhi->use_ipa) { - mhi_log(MHI_MSG_VERBOSE, - "device 0x%x <<-- host 0x%llx, size %d\n", - transfer->phy_addr, host_addr_pa, - (int) transfer->size); - rc = ipa_dma_async_memcpy((u64)transfer->phy_addr, host_addr_pa, - (int)transfer->size, - mhi_dev_ring_cache_completion_cb, &ring_req); - if (rc) - pr_err("error while reading from host:%d\n", rc); + mhi_log(MHI_MSG_VERBOSE, + "device 0x%x <<-- host 0x%llx, size %d\n", + transfer->phy_addr, host_addr_pa, + (int) transfer->size); + rc = ipa_dma_async_memcpy((u64)transfer->phy_addr, host_addr_pa, + (int)transfer->size, + mhi_dev_ring_cache_completion_cb, &ring_req); + if (rc) + pr_err("error while reading from host:%d\n", rc); + + wait_for_completion(&done); - wait_for_completion(&done); - } else { - memcpy(transfer->virt_addr, (void *) &transfer->device_va, - (int) transfer->size); - } } EXPORT_SYMBOL(mhi_dev_read_from_host); @@ -160,42 +156,35 @@ void mhi_dev_write_to_host(struct mhi_dev *mhi, struct mhi_addr *transfer, host_addr_pa = transfer->host_pa | bit_40; } - if (mhi->use_ipa) { - mhi_log(MHI_MSG_VERBOSE, - "device 0x%llx --> host 0x%llx, size %d\n", - (uint64_t) mhi->cache_dma_handle, host_addr_pa, - (int) transfer->size); - if (tr_type == MHI_DEV_DMA_ASYNC) { - dma = dma_map_single(&mhi->pdev->dev, - transfer->virt_addr, transfer->size, - DMA_TO_DEVICE); - if (ereq->event_type == SEND_EVENT_BUFFER) { - ereq->dma = dma; - ereq->dma_len = transfer->size; - } else if (ereq->event_type == SEND_EVENT_RD_OFFSET) { - ereq->event_rd_dma = dma; - } - rc = ipa_dma_async_memcpy(host_addr_pa, (uint64_t) dma, - (int)transfer->size, - ereq->client_cb, ereq); - if (rc) - pr_err("error while writing to host:%d\n", rc); - } else if (tr_type == MHI_DEV_DMA_SYNC) { - /* Copy the device content to a local device - * physical address */ - memcpy(mhi->dma_cache, transfer->virt_addr, - transfer->size); - rc = ipa_dma_sync_memcpy(host_addr_pa, - (u64) mhi->cache_dma_handle, - (int) transfer->size); - if (rc) - pr_err("error while writing to host:%d\n", rc); - } - } else { - memcpy((void *) &transfer->device_va, transfer->virt_addr, + mhi_log(MHI_MSG_VERBOSE, + "device 0x%llx --> host 0x%llx, size %d\n", + (uint64_t) mhi->cache_dma_handle, host_addr_pa, + (int) transfer->size); + if (tr_type == MHI_DEV_DMA_ASYNC) { + dma = dma_map_single(&mhi->pdev->dev, + transfer->virt_addr, transfer->size, + DMA_TO_DEVICE); + if (ereq->event_type == SEND_EVENT_BUFFER) { + ereq->dma = dma; + ereq->dma_len = transfer->size; + } else if (ereq->event_type == SEND_EVENT_RD_OFFSET) { + ereq->event_rd_dma = dma; + } + rc = ipa_dma_async_memcpy(host_addr_pa, (uint64_t) dma, + (int)transfer->size, + ereq->client_cb, ereq); + if (rc) + pr_err("error while writing to host:%d\n", rc); + } else if (tr_type == MHI_DEV_DMA_SYNC) { + /* Copy the device content to a local device + * physical address */ + memcpy(mhi->dma_cache, transfer->virt_addr, transfer->size); - /* Update state before sending events */ - wmb(); + rc = ipa_dma_sync_memcpy(host_addr_pa, + (u64) mhi->cache_dma_handle, + (int) transfer->size); + if (rc) + pr_err("error while writing to host:%d\n", rc); } } EXPORT_SYMBOL(mhi_dev_write_to_host); diff --git a/drivers/power/qcom/lpm-stats.c b/drivers/power/qcom/lpm-stats.c index 7f1967d432b7..bfd897a4323b 100644 --- a/drivers/power/qcom/lpm-stats.c +++ b/drivers/power/qcom/lpm-stats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -682,11 +682,14 @@ static void cleanup_stats(struct lpm_stats *stats) { struct list_head *centry = NULL; struct lpm_stats *pos = NULL; + struct lpm_stats *n = NULL; centry = &stats->child; - list_for_each_entry_reverse(pos, centry, sibling) { - if (!list_empty(&pos->child)) + list_for_each_entry_safe_reverse(pos, n, centry, sibling) { + if (!list_empty(&pos->child)) { cleanup_stats(pos); + continue; + } list_del_init(&pos->child); diff --git a/drivers/soc/qcom/rpm_stats.c b/drivers/soc/qcom/rpm_stats.c index 30b92657b6bc..f56cddfa7208 100644 --- a/drivers/soc/qcom/rpm_stats.c +++ b/drivers/soc/qcom/rpm_stats.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -430,7 +431,7 @@ static ssize_t rpmstats_show(struct kobject *kobj, prvdata); } - ret = snprintf(buf, prvdata->len, prvdata->buf); + ret = snprintf(buf, prvdata->len, "%s", prvdata->buf); iounmap(prvdata->reg_base); ioremap_fail: kfree(prvdata); diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c index c18d9b2ba642..776ba2aa3f92 100644 --- a/drivers/video/msm/mdss/mdp3_ctrl.c +++ b/drivers/video/msm/mdss/mdp3_ctrl.c @@ -651,8 +651,11 @@ int mdp3_ctrl_get_source_format(u32 imgType) case MDP_RGB_888: format = MDP3_DMA_IBUF_FORMAT_RGB888; break; + case MDP_XRGB_8888: case MDP_ARGB_8888: case MDP_RGBA_8888: + case MDP_BGRA_8888: + case MDP_RGBX_8888: format = MDP3_DMA_IBUF_FORMAT_XRGB8888; break; default: diff --git a/include/linux/ipc_router_xprt.h b/include/linux/ipc_router_xprt.h index 276c79ff1591..5baddb80c66e 100644 --- a/include/linux/ipc_router_xprt.h +++ b/include/linux/ipc_router_xprt.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -100,6 +100,7 @@ struct rr_opt_hdr { * @pkt_fragment_q: Queue of SKBs containing payload. * @length: Length of data in the chain of SKBs * @ref: Reference count for the packet. + * @ws_need: Flag to check wakeup soruce need */ struct rr_packet { struct list_head list; @@ -108,6 +109,7 @@ struct rr_packet { struct sk_buff_head *pkt_fragment_q; uint32_t length; struct kref ref; + bool ws_need; }; /** diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index f6cec9c43d98..9f7cbb375a37 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -393,6 +393,8 @@ struct mmc_card { /* Make sure CMDQ is empty before queuing DCMD */ #define MMC_QUIRK_CMDQ_EMPTY_BEFORE_DCMD (1 << 17) +#define MMC_QUIRK_QCA9379_SETTINGS (1 << 18) /* QCA9379 card settings*/ + unsigned int erase_size; /* erase size in sectors */ unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int pref_erase; /* in sectors */ @@ -693,6 +695,11 @@ static inline bool mmc_enable_qca9377_settings(const struct mmc_card *c) return c->quirks & MMC_QUIRK_QCA9377_SETTINGS; } +static inline bool mmc_enable_qca9379_settings(const struct mmc_card *c) +{ + return c->quirks & MMC_QUIRK_QCA9379_SETTINGS; +} + #define mmc_card_name(c) ((c)->cid.prod_name) #define mmc_card_id(c) (dev_name(&(c)->dev)) diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 3c354aeb69bc..7de48a57f68f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -551,6 +551,7 @@ struct mmc_host { unsigned int bus_resume_flags; #define MMC_BUSRESUME_MANUAL_RESUME (1 << 0) #define MMC_BUSRESUME_NEEDS_RESUME (1 << 1) + bool ignore_bus_resume_flags; unsigned int sdio_irqs; struct task_struct *sdio_irq_thread; diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index c7f1639f350e..b2a73fe82b7d 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -216,6 +216,25 @@ enum { UP, }; +/** + * is_sensor_port() - Check if the remote port is sensor service or not + * @rport: Pointer to the remote port. + * + * Return: true if the remote port is sensor service else false. + */ +static int is_sensor_port(struct msm_ipc_router_remote_port *rport) +{ + u32 svcid = 0; + + if (rport && rport->server) { + svcid = rport->server->name.service; + if (svcid == 400 || (svcid >= 256 && svcid <= 320)) + return true; + } + + return false; +} + static void init_routing_table(void) { int i; @@ -1165,7 +1184,8 @@ static int post_pkt_to_port(struct msm_ipc_port *port_ptr, } mutex_lock(&port_ptr->port_rx_q_lock_lhc3); - __pm_stay_awake(port_ptr->port_rx_ws); + if (pkt->ws_need) + __pm_stay_awake(port_ptr->port_rx_ws); list_add_tail(&temp_pkt->list, &port_ptr->port_rx_q); wake_up(&port_ptr->port_rx_wait_q); notify = port_ptr->notify; @@ -2740,7 +2760,6 @@ static void do_read_data(struct work_struct *work) struct rr_packet *pkt = NULL; struct msm_ipc_port *port_ptr; struct msm_ipc_router_remote_port *rport_ptr; - int ret; struct msm_ipc_router_xprt_info *xprt_info = container_of(work, @@ -2748,16 +2767,7 @@ static void do_read_data(struct work_struct *work) read_data); while ((pkt = rr_read(xprt_info)) != NULL) { - if (pkt->length < calc_rx_header_size(xprt_info) || - pkt->length > MAX_IPC_PKT_SIZE) { - IPC_RTR_ERR("%s: Invalid pkt length %d\n", - __func__, pkt->length); - goto read_next_pkt1; - } - ret = extract_header(pkt); - if (ret < 0) - goto read_next_pkt1; hdr = &(pkt->hdr); if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) && @@ -4199,6 +4209,7 @@ void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt, { struct msm_ipc_router_xprt_info *xprt_info = xprt->priv; struct msm_ipc_router_xprt_work *xprt_work; + struct msm_ipc_router_remote_port *rport_ptr = NULL; struct rr_packet *pkt; int ret; @@ -4251,9 +4262,34 @@ void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt, if (!pkt) return; + if (pkt->length < calc_rx_header_size(xprt_info) || + pkt->length > MAX_IPC_PKT_SIZE) { + IPC_RTR_ERR("%s: Invalid pkt length %d\n", + __func__, pkt->length); + release_pkt(pkt); + return; + } + + ret = extract_header(pkt); + if (ret < 0) { + release_pkt(pkt); + return; + } + + pkt->ws_need = true; + + if (pkt->hdr.type == IPC_ROUTER_CTRL_CMD_DATA) + rport_ptr = ipc_router_get_rport_ref(pkt->hdr.src_node_id, + pkt->hdr.src_port_id); + mutex_lock(&xprt_info->rx_lock_lhb2); list_add_tail(&pkt->list, &xprt_info->pkt_list); - __pm_stay_awake(&xprt_info->ws); + /* check every pkt is from SENSOR services or not*/ + if (is_sensor_port(rport_ptr)) + pkt->ws_need = false; + else + __pm_stay_awake(&xprt_info->ws); + mutex_unlock(&xprt_info->rx_lock_lhb2); queue_work(xprt_info->workqueue, &xprt_info->read_data); } diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 9b1452e8e868..72ebc3f300e5 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2759,7 +2759,7 @@ static struct genl_family ip_vs_genl_family = { .hdrsize = 0, .name = IPVS_GENL_NAME, .version = IPVS_GENL_VERSION, - .maxattr = IPVS_CMD_MAX, + .maxattr = IPVS_CMD_ATTR_MAX, .netnsok = true, /* Make ipvsadm to work on netns */ }; |
