diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile index 9d7be7dd1d0f6..b33c63ac6b526 100644 --- a/arch/arm64/boot/dts/rockchip/Makefile +++ b/arch/arm64/boot/dts/rockchip/Makefile @@ -119,6 +119,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-rock-2a.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-rock-2f.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3528-nanopi-rev01.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-dictpen-test3-v20.dtb +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-kickpi-k3b.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-evb1-lp4x-v10.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-evb1-lp4x-v10-linux.dtb dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3562-evb1-lp4x-v10-linux-amp.dtb diff --git a/arch/arm64/boot/dts/rockchip/overlay/Makefile b/arch/arm64/boot/dts/rockchip/overlay/Makefile index d4b3f58d7e704..cbfbeeb58e61f 100644 --- a/arch/arm64/boot/dts/rockchip/overlay/Makefile +++ b/arch/arm64/boot/dts/rockchip/overlay/Makefile @@ -140,6 +140,7 @@ dtbo-$(CONFIG_ARCH_ROCKCHIP) += \ rockchip-rk3588-panthor-gpu.dtbo \ rk3528-rock-2-enable-pcie.dtbo \ rk3566-roc-pc-sata2.dtbo \ + rk3562-kickpi-k3b-sq101p-x4ei451-84h501.dtbo \ rk3576-can1-m1.dtbo \ rk3576-i2c0-m1.dtbo \ rk3576-i2c1-m0.dtbo \ diff --git a/arch/arm64/boot/dts/rockchip/overlay/rk3562-kickpi-k3b-sq101p-x4ei451-84h501.dts b/arch/arm64/boot/dts/rockchip/overlay/rk3562-kickpi-k3b-sq101p-x4ei451-84h501.dts new file mode 100644 index 0000000000000..88683bbe30e97 --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/overlay/rk3562-kickpi-k3b-sq101p-x4ei451-84h501.dts @@ -0,0 +1,288 @@ +/dts-v1/; +/plugin/; + +/* + * Compatible with: + * SQ101P-X4EI451-84H501 + * YDP1010BT003-V1 + */ + +#include +#include +#include +#include + +/ { + fragment@0 { + target-path = "/"; + + __overlay__ { + lcd_3v3: regulator-lcd-3v3 { + compatible = "regulator-fixed"; + enable-active-high; + gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_3v3_pin>; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "lcd_3v3"; + vin-supply = <&vcc_3v3>; + }; + + backlight_dsi: backlight-dsi { + compatible = "gpio-backlight"; + gpios = <&gpio0 RK_PC2 GPIO_ACTIVE_HIGH>; /* This enabled fixed 24v VLED */ + default-on; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_vled_pin>; + }; + }; + }; + + fragment@1 { + target = <&dsi>; + + __overlay__ { + status = "okay"; + + panel@0 { + reg = <0>; + compatible = "simple-panel-dsi"; + pinctrl-names = "default"; + pinctrl-0 = <&lcd_reset_pin>; + backlight = <&backlight_dsi>; + power-supply = <&lcd_3v3>; + reset-gpios = <&gpio0 RK_PA7 GPIO_ACTIVE_LOW>; + + reset-delay-ms = <120>; + enable-delay-ms = <120>; + prepare-delay-ms = <120>; + init-delay-ms = <120>; + unprepare-delay-ms = <60>; + disable-delay-ms = <60>; + + dsi,flags = <(MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET)>; + dsi,format = ; + dsi,lanes = <4>; + + panel-init-sequence = [ + 23 00 02 30 01 + 39 00 05 78 49 61 02 00 + 23 00 02 30 02 + 23 00 02 31 12 + 23 00 02 32 08 + 23 00 02 33 3f + 23 00 02 3c 04 + 23 00 02 3d 78 + 23 00 02 3e 43 + 23 00 02 3f 30 + 23 00 02 42 a2 + 23 00 02 43 f0 + 23 00 02 44 01 + 23 00 02 46 17 + 23 00 02 49 c0 + 23 00 02 6d 30 + 23 00 02 6e 21 + 39 00 0d 41 5b 5b 03 03 5b 5b 02 02 03 03 03 03 + 39 00 0c 5a 00 00 34 34 31 31 23 23 24 24 23 + 39 00 0c 5b 23 0b 0b 09 09 0f 0f 0d 0d 06 06 + 39 00 0c 5c 00 00 34 34 31 31 23 23 24 24 23 + 39 00 0c 5d 23 0a 0a 08 08 0e 0e 0c 0c 05 05 + 39 00 0c 5e 00 00 31 31 34 34 23 23 24 24 23 + 39 00 0c 5f 23 0c 0c 0e 0e 08 08 0a 0a 05 05 + 39 00 0c 60 00 00 31 31 34 34 23 23 24 24 23 + 39 00 0c 61 23 0d 0d 0f 0f 09 09 0b 0b 06 06 + 39 00 04 64 ff ff 3f + 39 00 04 65 ff ff 3f + 39 00 04 6f 03 00 00 + 39 00 04 70 03 00 00 + 39 00 04 71 00 00 80 + 39 00 04 72 00 00 00 + 39 00 03 4c 22 22 + 23 00 02 73 2a + 39 00 03 4e 00 00 + 39 00 03 50 00 00 + 39 00 03 55 ff ff + 39 00 03 56 ff ff + 39 00 03 57 00 00 + 39 00 03 58 ff ff + 39 00 03 66 ff ff + 39 00 03 67 ff ff + 23 00 02 4a 3f + 23 00 02 30 08 + 23 00 02 31 65 + 23 00 02 33 05 + 23 00 02 40 50 + 23 00 02 41 80 + 23 00 02 42 1a + 23 00 02 47 0a + 23 00 02 48 0d + 23 00 02 50 17 + 23 00 02 5a 20 + 23 00 02 5b 00 + 23 00 02 5c 53 + 23 00 02 62 04 + 23 00 02 65 5f + 23 00 02 73 01 + 23 00 02 30 0a + 23 00 02 32 ff + 23 00 02 33 28 + 23 00 02 3f 53 + 23 00 02 40 15 + 23 00 02 47 20 + 23 00 02 48 80 + 23 00 02 49 03 + 23 00 02 30 0b + 39 00 03 33 00 3d + 39 00 03 3c 00 bf + 23 00 02 43 b1 + 23 00 02 44 31 + 39 00 06 3e 00 10 1e 27 2f + 39 00 0f 3f 54 6f 73 7c 77 91 90 99 a8 a5 ae b5 c5 b8 + 39 00 0a 40 52 52 53 7f 00 10 1e 27 2f + 39 00 0f 41 54 6f 73 7c 77 91 98 99 a8 a5 ae b5 c5 b8 + 39 00 05 42 52 52 53 7f + 23 00 02 45 70 + 23 00 02 46 3b + 23 00 02 48 7c + 23 00 02 49 1e + 23 00 02 4a 3a + 23 00 02 30 0c + 23 00 02 32 62 + 23 00 02 71 77 + 23 00 02 30 0d + 23 00 02 4c 74 + 23 00 02 30 00 + 05 78 01 11 + 05 0a 01 29 + 23 00 02 35 00 + ]; + + panel-exit-sequence = [ + 05 00 01 28 + 05 00 01 10 + ]; + + display-timings { + native-mode = <&dsi0_timing0>; + dsi0_timing0: timing0 { + clock-frequency = <76106880>; + hactive = <800>; + vactive = <1280>; + hback-porch = <28>; + hfront-porch = <40>; + vback-porch = <20>; + vfront-porch = <140>; + hsync-len = <8>; + vsync-len = <8>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + panel_in_dsi: endpoint { + remote-endpoint = <&dsi_out_panel>; + }; + }; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + dsi_out_panel: endpoint { + remote-endpoint = <&panel_in_dsi>; + }; + }; + }; + }; + }; + + fragment@2 { + target = <&dsi_in_vp0>; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@3 { + target = <&video_phy>; + + __overlay__ { + status = "okay"; + }; + }; + + fragment@4 { + target = <&route_dsi>; + + __overlay__ { + status = "okay"; + connect = <&vp0_out_dsi>; + }; + }; + + fragment@5 { + target = <&i2c2>; + + __overlay__ { + status = "okay"; + + jd9366: touchscreen@68 { + compatible = "jadard,jdcommon"; + reg = <0x68>; + interrupt-parent = <&gpio0>; + interrupts = ; + jadard,panel-sense-nums = <22 36>; + jadard,panel-coords = <0 800 0 1280>; + jadard,panel-max-points = <10>; + jadard,int-is-edge = <1>; + jadard,irq-gpio = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>; + jadard,rst-gpio = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&touchscreen_int_pin &touchscreen_rst_pin>; + }; + }; + }; + + fragment@6 { + target = <&pinctrl>; + + __overlay__ { + display { + lcd_3v3_pin: lcd-3v3-pin { + rockchip,pins = <0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + lcd_vled_pin: lcd-vled-pin { + rockchip,pins = <0 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + lcd_reset_pin: lcd-reset-pin { + rockchip,pins = <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + touchscreen_int_pin: touchscreen-int-pin { + rockchip,pins = <0 RK_PC3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + touchscreen_rst_pin: touchscreen-rst-pin { + rockchip,pins = <0 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3562-kickpi-k3b.dts b/arch/arm64/boot/dts/rockchip/rk3562-kickpi-k3b.dts new file mode 100644 index 0000000000000..48e2cc919a71a --- /dev/null +++ b/arch/arm64/boot/dts/rockchip/rk3562-kickpi-k3b.dts @@ -0,0 +1,793 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (c) 2022 Fuzhou Rockchip Electronics Co., Ltd. + * Copyright (c) 2026 retro98boy + */ + +/dts-v1/; + +#include +#include +#include +#include +#include "rk3562.dtsi" +/* + * Include configurations for the Linux system. + * Replace this with rk3562-android.dtsi to + * adapt this DTS for the Android system. + */ +#include "rk3562-linux.dtsi" + +#define USE_PANFROST + +/ { + model = "KICKPI K3B"; + compatible = "kickpi,k3b", "rockchip,rk3562"; + + gpio-leds { + compatible = "gpio-leds"; + + work-led { + color = ; + linux,default-trigger = "heartbeat"; + function = LED_FUNCTION_HEARTBEAT; + gpios = <&gpio1 RK_PC7 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&work_led_pin>; + }; + + /* + * The KICKPI K3B has a hardware quirk: + * if the battery functionality is enabled in software + * but no physical battery is connected, + * powering the device via Type-C will cause it to hang + * during the boot process. + * To workaround this issue, KICKPI introduces a 10-second + * delay before enabling the USB Type-A power supply. + * Note that the initial-on-delay-ms property requires + * a specific kernel patch to be supported. + */ + vcc5v0-usb { + label = "vcc5v0-usb"; + default-state = "on"; + initial-on-delay-ms = <10000>; + gpios = <&gpio3 RK_PC6 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc5v0_usb_pin>; + }; + }; + + sdio_pwrseq: sdio-pwrseq { + compatible = "mmc-pwrseq-simple"; + clocks = <&rk817 1>; + clock-names = "ext_clock"; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_enable_h>; + post-power-on-delay-ms = <200>; + reset-gpios = <&gpio0 RK_PB3 GPIO_ACTIVE_LOW>; + }; + + test-power { + status = "okay"; + }; + + analog-sound { + compatible = "rockchip,multicodecs-card"; + rockchip,card-name = "kickpi-k3b"; + hp-det-gpio = <&gpio3 RK_PD0 GPIO_ACTIVE_HIGH>; + rockchip,format = "i2s"; + rockchip,mclk-fs = <256>; + rockchip,cpu = <&sai0>; + rockchip,codec = <&rk817_codec>; + pinctrl-names = "default"; + pinctrl-0 = <&hp_det_pin>; + io-channels = <&saradc0 0>; + io-channel-names = "adc-detect"; + keyup-threshold-microvolt = <1800000>; + + play-pause-key { + label = "playpause"; + linux,code = ; + press-threshold-microvolt = <2000>; + }; + }; + + vcc_sys: vcc-sys { + compatible = "regulator-fixed"; + regulator-name = "vcc_sys"; + regulator-always-on; + regulator-boot-on; + }; + + vcc5v0_usb_otg: vcc5v0-usb-otg { + compatible = "regulator-fixed"; + regulator-name = "vcc5v0_usb_otg"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + }; + + vcc3v3_sd: regulator-vcc3v3-sd { + compatible = "regulator-fixed"; + regulator-name = "vcc3v3_sd"; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + enable-active-low; + gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&vcc3v3_sd_pin>; + vin-supply = <&vcc_3v3>; + }; + + vdd_gpu: vdd-gpu { + compatible = "pwm-regulator"; + pwms = <&pwm7 0 5000 1>; + regulator-name = "vdd_gpu"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1100000>; + regulator-init-microvolt = <900000>; + regulator-always-on; + regulator-boot-on; + regulator-settling-time-up-us = <250>; + pwm-supply = <&vcc_sys>; + }; + + vdd_npu: vdd-npu { + compatible = "pwm-regulator"; + pwms = <&pwm6 0 5000 1>; + regulator-name = "vdd_npu"; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <1100000>; + regulator-init-microvolt = <900000>; + regulator-always-on; + regulator-boot-on; + regulator-settling-time-up-us = <250>; + pwm-supply = <&vcc_sys>; + }; + + wireless-wlan { + compatible = "wlan-platdata"; + rockchip,grf = <&sys_grf>; + wifi_chip_type = "rtl8822cs"; /* Not care */ + /* WIFI,poweren_gpio = <&gpio0 RK_PB3 GPIO_ACTIVE_HIGH>; */ + WIFI,host_wake_irq = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&wifi_host_wake_irq>; + }; + + wireless-bluetooth { + compatible = "bluetooth-platdata"; + clocks = <&rk817 1>; + clock-names = "ext_clock"; + uart_rts_gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>; + pinctrl-names = "default", "rts_gpio"; + pinctrl-0 = <&uart1m0_rtsn>; + pinctrl-1 = <&uart1_gpios>; + BT,power_gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>; + BT,wake_gpio = <&gpio0 RK_PC6 GPIO_ACTIVE_HIGH>; + BT,wake_host_irq = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>; + }; + + bt_sco: bt-sco { + compatible = "delta,dfbmcs320"; + #sound-dai-cells = <1>; + }; + + bt-sound { + compatible = "simple-audio-card"; + simple-audio-card,format = "dsp_a"; + simple-audio-card,bitclock-inversion = <0>; + simple-audio-card,mclk-fs = <256>; + simple-audio-card,name = "rockchip,bt"; + + simple-audio-card,cpu { + sound-dai = <&sai2>; + }; + + simple-audio-card,codec { + sound-dai = <&bt_sco 1>; + }; + }; +}; + +&chosen { + /* Override incompatible settings from rk3562-linux.dtsi */ + bootargs = "earlycon=uart8250,mmio32,0xff210000 console=ttyFIQ0"; +}; + +&combphy_pu { + status = "okay"; +}; + +&cpu0 { + cpu-supply = <&vdd_cpu>; +}; + +&dfi { + status = "okay"; +}; + +&display_subsystem { + status = "okay"; +}; + +&dmc { + center-supply = <&vdd_logic>; + status = "okay"; +}; + +&gmac0 { + phy-handle = <&mae0621a>; + phy-mode = "rgmii"; + clock_in_out = "output"; + tx_delay = <0x47>; + rx_delay = <0x3f>; + + snps,reset-gpio = <&gpio3 RK_PA0 GPIO_ACTIVE_LOW>; + snps,reset-active-low; + snps,reset-delays-us = <0 20000 100000>; + + pinctrl-names = "default"; + pinctrl-0 = <&rgmiim0_miim + &rgmiim0_tx_bus2 + &rgmiim0_rx_bus2 + &rgmiim0_rgmii_clk + &rgmiim0_rgmii_bus>; + + status = "okay"; +}; + +&gpu { +#ifdef USE_PANFROST + interrupt-names = "gpu", "mmu", "job"; +#endif + mali-supply = <&vdd_gpu>; + status = "okay"; +}; + +#ifdef USE_PANFROST +&gpu_opp_table { + opp-300000000 { + /delete-property/ opp-supported-hw; + }; + + opp-400000000 { + /delete-property/ opp-supported-hw; + }; + + opp-500000000 { + /delete-property/ opp-supported-hw; + }; + + opp-600000000 { + /delete-property/ opp-supported-hw; + }; + + opp-700000000 { + /delete-property/ opp-supported-hw; + }; + + opp-800000000 { + /delete-property/ opp-supported-hw; + }; + + opp-900000000 { + /delete-property/ opp-supported-hw; + }; +}; +#endif + +&i2c0 { + status = "okay"; + + rk817: pmic@20 { + compatible = "rockchip,rk817"; + reg = <0x20>; + interrupt-parent = <&gpio0>; + interrupts = <3 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default", "pmic-sleep", + "pmic-power-off", "pmic-reset"; + pinctrl-0 = <&pmic_int>; + pinctrl-1 = <&soc_slppin_slp>, <&rk817_slppin_slp>; + pinctrl-2 = <&soc_slppin_gpio>, <&rk817_slppin_pwrdn>; + pinctrl-3 = <&soc_slppin_gpio>, <&rk817_slppin_rst>; + rockchip,system-power-controller; + wakeup-source; + #clock-cells = <1>; + clock-output-names = "rk808-clkout1", "rk808-clkout2"; + pmic-reset-func = <0>; + vcc1-supply = <&vcc_sys>; + vcc2-supply = <&vcc_sys>; + vcc3-supply = <&vcc_sys>; + vcc4-supply = <&vcc_sys>; + vcc5-supply = <&vcc_sys>; + vcc6-supply = <&vcc_sys>; + vcc7-supply = <&vcc_sys>; + vcc8-supply = <&vcc_sys>; + vcc9-supply = <&dcdc_boost>; + + pwrkey { + status = "okay"; + }; + + pinctrl_rk8xx: pinctrl_rk8xx { + gpio-controller; + #gpio-cells = <2>; + + rk817_slppin_null: rk817_slppin_null { + pins = "gpio_slp"; + function = "pin_fun0"; + }; + + rk817_slppin_slp: rk817_slppin_slp { + pins = "gpio_slp"; + function = "pin_fun1"; + }; + + rk817_slppin_pwrdn: rk817_slppin_pwrdn { + pins = "gpio_slp"; + function = "pin_fun2"; + }; + + rk817_slppin_rst: rk817_slppin_rst { + pins = "gpio_slp"; + function = "pin_fun3"; + }; + }; + + regulators { + vdd_logic: DCDC_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-init-microvolt = <900000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_logic"; + + regulator-state-mem { + regulator-off-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vdd_cpu: DCDC_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <500000>; + regulator-max-microvolt = <1350000>; + regulator-init-microvolt = <900000>; + regulator-ramp-delay = <6001>; + regulator-initial-mode = <0x2>; + regulator-name = "vdd_cpu"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc_ddr: DCDC_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_ddr"; + + regulator-state-mem { + regulator-on-in-suspend; + }; + }; + + vcc_3v3: DCDC_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-initial-mode = <0x2>; + regulator-name = "vcc_3v3"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3300000>; + }; + }; + + vcca1v8_pmu: LDO_REG1 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcca1v8_pmu"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <1800000>; + }; + }; + + vdda_0v9: LDO_REG2 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda_0v9"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vdda0v9_pmu: LDO_REG3 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <900000>; + regulator-name = "vdda0v9_pmu"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <900000>; + }; + }; + + vccio_acodec: LDO_REG4 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_acodec"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vccio_sd: LDO_REG5 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vccio_sd"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc3v3_pmu: LDO_REG6 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-name = "vcc3v3_pmu"; + + regulator-state-mem { + regulator-on-in-suspend; + regulator-suspend-microvolt = <3000000>; + }; + }; + + vcc_1v8: LDO_REG7 { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc_1v8"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc1v8_dvp: LDO_REG8 { + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-name = "vcc1v8_dvp"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + vcc2v8_dvp: LDO_REG9 { + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-name = "vcc2v8_dvp"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + dcdc_boost: BOOST { + regulator-always-on; + regulator-boot-on; + regulator-min-microvolt = <4700000>; + regulator-max-microvolt = <5400000>; + regulator-name = "boost"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + + otg_switch: OTG_SWITCH { + regulator-name = "otg_switch"; + + regulator-state-mem { + regulator-off-in-suspend; + }; + }; + }; + + rk817_codec: codec { + #sound-dai-cells = <0>; + compatible = "rockchip,rk817-codec"; + clocks = <&mclkout_sai0>; + clock-names = "mclk"; + assigned-clocks = <&mclkout_sai0>; + assigned-clock-rates = <12288000>; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0m0_mclk>; + hp-volume = <3>; + spk-volume = <3>; + mic-in-differential; + }; + + battery { + compatible = "rk817,battery"; + ocv_table = <3400 3573 3620 3662 3691 3713 3735 + 3760 3791 3830 3878 3923 3958 3986 + 4014 4051 4094 4126 4153 4191 4204>; + design_capacity = <5000>; + design_qmax = <5000>; + bat_res = <100>; + sleep_enter_current = <300>; + sleep_exit_current = <300>; + sleep_filter_current = <100>; + power_off_thresd = <3400>; + zero_algorithm_vol = <3850>; + max_soc_offset = <60>; + monitor_sec = <5>; + sample_res = <10>; + virtual_power = <1>; + }; + + charger { + compatible = "rk817,charger"; + min_input_voltage = <4000>; + max_input_current = <3000>; + max_chrg_current = <3500>; + max_chrg_voltage = <4350>; + chrg_term_mode = <0>; + chrg_finish_cur = <300>; + virtual_power = <0>; + dc_det_adc = <0>; + extcon = <&u2phy>; + gate_function_disable = <1>; + }; + }; +}; + +&jpegd { + status = "okay"; +}; + +&jpegd_mmu { + status = "okay"; +}; + +&mdio0 { + mae0621a: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0x0>; + clocks = <&cru CLK_GMAC_ETH_OUT2IO>; + assigned-clocks = <&cru CLK_GMAC_ETH_OUT2IO>; + assigned-clock-rates = <25000000>; + }; +}; + +&mpp_srv { + status = "okay"; +}; + +&pinctrl { + led { + work_led_pin: work-led-pin { + rockchip,pins = <1 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>; + }; + + vcc5v0_usb_pin: vcc5v0-usb-pin { + rockchip,pins = <3 RK_PC6 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sdmmc { + vcc3v3_sd_pin: vcc3v3-sd-pin { + rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + sound { + hp_det_pin: hp-det-pin { + rockchip,pins = <3 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; + + wireless-wlan { + wifi_enable_h: wifi-enable-h { + rockchip,pins = <0 RK_PB3 RK_FUNC_GPIO &pcfg_pull_up>; + }; + + wifi_host_wake_irq: wifi-host-wake-irq { + rockchip,pins = <0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + + wireless-bluetooth { + uart1_gpios: uart1-gpios { + rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_none>; + }; + }; +}; + +&pwm6 { + status = "okay"; +}; + +&pwm7 { + status = "okay"; +}; + +&rga2 { + status = "okay"; +}; + +&rga2_mmu { + status = "okay"; +}; + +&rknpu { + rknpu-supply = <&vdd_npu>; + status = "okay"; +}; + +&rknpu_mmu { + status = "okay"; +}; + +&rkvdec { + status = "okay"; +}; + +&rkvdec_mmu { + status = "okay"; +}; + +&rkvenc { + status = "okay"; +}; + +&rkvenc_mmu { + status = "okay"; +}; + +&sai0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s0m0_lrck + &i2s0m0_sclk + &i2s0m0_sdi0 + &i2s0m0_sdo0>; +}; + +&sai2 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&i2s2m0_lrck + &i2s2m0_sclk + &i2s2m0_sdi + &i2s2m0_sdo>; +}; + +&saradc0 { + status = "okay"; + vref-supply = <&vcc_1v8>; +}; + +&sdhci { + bus-width = <8>; + no-sdio; + no-sd; + non-removable; + mmc-hs400-1_8v; + mmc-hs400-enhanced-strobe; + full-pwr-cycle-in-suspend; + status = "okay"; +}; + +&sdmmc0 { + no-sdio; + no-mmc; + bus-width = <4>; + cap-mmc-highspeed; + cap-sd-highspeed; + supports-sd; + disable-wp; + sd-uhs-sdr104; + vmmc-supply = <&vcc3v3_sd>; + vqmmc-supply = <&vccio_sd>; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>; + status = "okay"; +}; + +&sdmmc1 { + no-sd; + no-mmc; + bus-width = <4>; + disable-wp; + cap-sd-highspeed; + cap-sdio-irq; + keep-power-in-suspend; + mmc-pwrseq = <&sdio_pwrseq>; + non-removable; + pinctrl-names = "default"; + pinctrl-0 = <&sdmmc1_bus4 &sdmmc1_cmd &sdmmc1_clk>; + sd-uhs-sdr104; + status = "okay"; +}; + +&tsadc { + status = "okay"; +}; + +&uart1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&uart1m0_xfer &uart1m0_ctsn>; +}; + +&u2phy { + status = "okay"; +}; + +&u2phy_host { + status = "okay"; +}; + +&u2phy_otg { + status = "okay"; + vbus-supply = <&vcc5v0_usb_otg>; +}; + +&usb_host0_ehci { + status = "okay"; +}; + +&usb_host0_ohci { + status = "okay"; +}; + +&usbdrd30 { + status = "okay"; +}; + +&usbdrd_dwc3 { + status = "okay"; + dr_mode = "otg"; + extcon = <&u2phy>; + maximum-speed = "high-speed"; + phys = <&u2phy_otg>; + phy-names = "usb2-phy"; + snps,dis_u2_susphy_quirk; + snps,usb2-lpm-disable; +}; + +&vop { + status = "okay"; +}; + +&vop_mmu { + status = "okay"; +}; diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c index ee612303f0765..4c0b0e83b6774 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.c +++ b/drivers/gpu/drm/panfrost/panfrost_device.c @@ -17,6 +17,12 @@ #include "panfrost_mmu.h" #include "panfrost_perfcnt.h" +static const char * const panfrost_extra_clock_names[] = { + "clk_gpu", + "clk_gpu_brg", + "aclk_gpu", +}; + static int panfrost_reset_init(struct panfrost_device *pfdev) { pfdev->rstc = devm_reset_control_array_get_optional_exclusive(pfdev->dev); @@ -36,6 +42,7 @@ static void panfrost_reset_fini(struct panfrost_device *pfdev) static int panfrost_clk_init(struct panfrost_device *pfdev) { int err; + int i; unsigned long rate; pfdev->clock = devm_clk_get(pfdev->dev, NULL); @@ -68,8 +75,43 @@ static int panfrost_clk_init(struct panfrost_device *pfdev) goto disable_clock; } + for (i = 0; i < ARRAY_SIZE(panfrost_extra_clock_names); i++) { + struct clk *clk; + + clk = devm_clk_get_optional(pfdev->dev, + panfrost_extra_clock_names[i]); + if (IS_ERR(clk)) { + dev_err(pfdev->dev, "get %s failed %ld\n", + panfrost_extra_clock_names[i], PTR_ERR(clk)); + err = PTR_ERR(clk); + goto disable_bus_clock; + } + + if (!clk) + continue; + + pfdev->extra_clocks[pfdev->num_extra_clocks].id = + panfrost_extra_clock_names[i]; + pfdev->extra_clocks[pfdev->num_extra_clocks].clk = clk; + pfdev->num_extra_clocks++; + } + + for (i = 0; i < pfdev->num_extra_clocks; i++) { + rate = clk_get_rate(pfdev->extra_clocks[i].clk); + dev_info(pfdev->dev, "%s rate = %lu\n", + pfdev->extra_clocks[i].id, + rate); + } + + err = clk_bulk_prepare_enable(pfdev->num_extra_clocks, + pfdev->extra_clocks); + if (err) + goto disable_bus_clock; + return 0; +disable_bus_clock: + clk_disable_unprepare(pfdev->bus_clock); disable_clock: clk_disable_unprepare(pfdev->clock); @@ -78,6 +120,7 @@ static int panfrost_clk_init(struct panfrost_device *pfdev) static void panfrost_clk_fini(struct panfrost_device *pfdev) { + clk_bulk_disable_unprepare(pfdev->num_extra_clocks, pfdev->extra_clocks); clk_disable_unprepare(pfdev->bus_clock); clk_disable_unprepare(pfdev->clock); } diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h index 8b25278f34c8f..15ff73b611898 100644 --- a/drivers/gpu/drm/panfrost/panfrost_device.h +++ b/drivers/gpu/drm/panfrost/panfrost_device.h @@ -6,6 +6,7 @@ #define __PANFROST_DEVICE_H__ #include +#include #include #include #include @@ -84,6 +85,8 @@ struct panfrost_device { void __iomem *iomem; struct clk *clock; struct clk *bus_clock; + struct clk_bulk_data extra_clocks[3]; + int num_extra_clocks; struct regulator_bulk_data *regulators; struct reset_control *rstc; /* pm_domains for devices with more than one. */ diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 428a4c2e21d00..b48a71ed794d6 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -511,6 +511,19 @@ config TOUCHSCREEN_IPROC To compile this driver as a module, choose M here: the module will be called bcm_iproc_tsc. +config TOUCHSCREEN_JADARD_CHIPSET + tristate "JADARD touch panel driver support" + help + Say Y here if you want to add support for the JADARD touch + controller to your system. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called jadard_touch. + +source "drivers/input/touchscreen/jdchipset/Kconfig" + config TOUCHSCREEN_S3C2410 tristate "Samsung S3C2410/generic touchscreen input driver" depends on ARCH_S3C24XX || SAMSUNG_DEV_TS diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 339b262973fb7..39f864d483c0c 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_IMAGIS) += imagis.o obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o +obj-$(CONFIG_TOUCHSCREEN_JADARD_CHIPSET) += jdchipset/ obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o diff --git a/drivers/input/touchscreen/jdchipset/Kconfig b/drivers/input/touchscreen/jdchipset/Kconfig new file mode 100644 index 0000000000000..6ee784768b413 --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/Kconfig @@ -0,0 +1,111 @@ +# +# Jadard Touchscreen driver configuration +# + +config TOUCHSCREEN_JADARD_MODULE + tristate "Jadard chipset module fuction" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This switch whether to compile into a kernel module. + +config TOUCHSCREEN_JADARD_IC_JD9365TD + tristate "Jadard chipset of JD9365TD" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9365TD. + +config TOUCHSCREEN_JADARD_IC_JD9532TD + tristate "Jadard chipset of JD9532TD" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9532TD. + +config TOUCHSCREEN_JADARD_IC_JD9532P + tristate "Jadard chipset of JD9532P" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9532P. + +config TOUCHSCREEN_JADARD_IC_JD9365T + tristate "Jadard chipset of JD9365T" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9365T. + +config TOUCHSCREEN_JADARD_IC_JD9365TR + tristate "Jadard chipset of JD9365TR" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9365TR. + +config TOUCHSCREEN_JADARD_IC_JD9365TF + tristate "Jadard chipset of JD9365TF" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9365TF. + +config TOUCHSCREEN_JADARD_IC_JD9365TG + tristate "Jadard chipset of JD9365TG" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9365TG. + +config TOUCHSCREEN_JADARD_IC_JD9365TH + tristate "Jadard chipset of JD9365TH" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9365TH. + +config TOUCHSCREEN_JADARD_IC_JD9261T + tristate "Jadard chipset of JD9261T" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9261T. + +config TOUCHSCREEN_JADARD_IC_JD9366T + tristate "Jadard chipset of JD9366T" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9366T. + +config TOUCHSCREEN_JADARD_IC_JD9366TP + tristate "Jadard chipset of JD9366TP" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9366TP. + +config TOUCHSCREEN_JADARD_IC_JD9522T + tristate "Jadard chipset of JD9522T" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9522T. + +config TOUCHSCREEN_JADARD_IC_JD9522TS + tristate "Jadard chipset of JD9522TS" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9522TS. + +config TOUCHSCREEN_JADARD_IC_JD9532Q + tristate "Jadard chipset of JD9532Q" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard chipset of JD9532Q. + +config JD_DB + tristate "Jadard driver test over Dragon Board" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard driver test over Dragon Board. + +config JD_FB + tristate "Jadard driver suspend/resume event by system FB" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard driver suspend/resume event by system FB. + +config JD_HID + tristate "Jadard HID over I2C/SPI function" + depends on TOUCHSCREEN_JADARD_CHIPSET + help + This enables support for Jadard HID over I2C/SPI. \ No newline at end of file diff --git a/drivers/input/touchscreen/jdchipset/Makefile b/drivers/input/touchscreen/jdchipset/Makefile new file mode 100644 index 0000000000000..9264f283a025d --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/Makefile @@ -0,0 +1,27 @@ +ccflags-y += -DCONFIG_TOUCHSCREEN_JADARD_DEBUG=y +ccflags-y += -DCONFIG_TOUCHSCREEN_JADARD_SORTING=y + +ifeq ($(TARGET_BUILD_VARIANT), user) + ccflags-y += -D__JADARD_GKI__ +endif + +# Makefile for the Jadard touchscreen drivers. +ifeq ($(CONFIG_TOUCHSCREEN_JADARD_MODULE), y) + obj-y += jadard_module.o + obj-$(CONFIG_TOUCHSCREEN_JADARD_IC_JD9366T) += jadard_ic_JD9366T.o + obj-y += jadard_common.o jadard_platform.o + obj-y += jadard_debug.o + obj-y += jadard_sorting.o + obj-$(CONFIG_JD_HID) += jadard_hid.o + +else ifeq ($(CONFIG_TOUCHSCREEN_JADARD_MODULE), m) + ccflags-y += -D__JADARD_KMODULE__ + + jadard_touch-objs := jadard_module.o + jadard_touch-objs += jadard_ic_JD9366T.o + jadard_touch-objs += jadard_common.o jadard_platform.o + jadard_touch-objs += jadard_debug.o + jadard_touch-objs += jadard_sorting.o + obj-m += jadard_touch.o + +endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_common.c b/drivers/input/touchscreen/jdchipset/jadard_common.c new file mode 100644 index 0000000000000..631d3186a1354 --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_common.c @@ -0,0 +1,3593 @@ +#include "jadard_platform.h" +#include "jadard_common.h" +#include "jadard_module.h" + +struct jadard_module_fp g_module_fp; +struct jadard_ts_data *pjadard_ts_data = NULL; +struct jadard_ic_data *pjadard_ic_data = NULL; +struct jadard_report_data *pjadard_report_data = NULL; +struct jadard_host_data *pjadard_host_data = NULL; +struct jadard_debug *pjadard_debug = NULL; +struct proc_dir_entry *pjadard_touch_proc_dir = NULL; +bool jd_g_esd_check_enable = false; + +#ifdef CONFIG_TOUCHSCREEN_JADARD_DEBUG +extern int DataType; +extern int *jd_diag_mutual; +extern int jd_diag_mutual_cnt; +#endif + +#ifdef CONFIG_JD_HID +extern uint8_t hid_touch_data[JD_TOUCH_DATA_SIZE]; +#endif + +#if defined(JD_OPPO_FUNC) +#define JADARD_PROC_TOUCHPANLE_FOLDER "touchpanel" +#define JADARD_PROC_BASELINE_TEST_FILE "baseline_test" +#define JADARD_PROC_BLACK_SCREEN_TEST_FILE "black_screen_test" + +struct proc_dir_entry *pjadard_touchpanel_proc_dir = NULL; +struct proc_dir_entry *pjadard_baseline_test_file = NULL; +struct proc_dir_entry *pjadard_blackscreen_baseline_file = NULL; +#endif + +char *jd_panel_maker_list[JD_PANEL_MAKER_LIST_SIZE] = { + "AUO", /* 友達 */ + "BOE", /* 京東方 */ + "CPT", /* 華映 */ + "CSOT", /* 華星 */ + "CTC", /* 深超 */ + "CTO", /* 華銳 */ + "HSD", /* 瀚宇彩晶 */ + "INX", /* 群創 */ + "IVO", /* 龍騰 */ + "JDI", /* 日本顯示 */ + "LGD", /* 樂金顯示 */ + "MDT", /* 華佳彩 */ + "PANDA", /* 中電熊貓 */ + "SDC", /* 三星顯示 */ + "SHARP", /* 夏普 */ + "TM", /* 天馬 */ + "TRULY", /* 信利 */ + "HKC", /* 惠科 */ + "N/A" +}; + +#ifdef JD_UPGRADE_FW_ARRAY +char *jd_i_CTPM_firmware_name = "Jadard_firmware.i"; +const uint8_t jd_i_firmware[] = { +#include "Jadard_firmware.i" +}; +const uint32_t jd_fw_size = sizeof(jd_i_firmware); +#endif + +#if defined(JD_AUTO_UPGRADE_FW) || defined(JD_ZERO_FLASH) +#ifndef JD_UPGRADE_FW_ARRAY +char *jd_i_CTPM_firmware_name = "Jadard_firmware.bin"; +#endif +#if defined(JD_AUTO_UPGRADE_FW) +uint8_t *g_jadard_fw = NULL; +uint32_t g_jadard_fw_len; +uint32_t g_jadard_fw_ver = 0; +uint32_t g_jadard_fw_cid_ver = 0; +#endif +#endif + +#ifdef JD_USB_DETECT_GLOBAL +/* Get usb status from system */ +bool jd_usb_detect_flag; +#if defined(__JADARD_KMODULE__) +EXPORT_SYMBOL(jd_usb_detect_flag); +#endif +#endif + +#ifdef JD_SMART_WAKEUP +/* {Double-Click, Up, Down, Left, Rright, C, Z, M, + * O, S, V, DV, LV, RV, W, e, + * AT, RF, LF, Two fingers Up, Two fingers Down, Two fingers Left, Two fingers Right} + */ +uint8_t jd_gest_event[JD_GEST_SUP_NUM] = { + 0x80, 0x01, 0x02, 0x03, 0x04, 0x20, 0x21, 0x22, + 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, + 0x2B, 0x2C, 0x2D, 0x51, 0x52, 0x53, 0x54 +}; + +uint16_t jd_gest_key_def[JD_GEST_SUP_NUM] = { + KEY_WAKEUP/*KEY_POWER*/, 251, 252, 253, 254, 255, 256, 257, + 258, 259, 260, 261, 262, 263, 264, 265, + 266, 267, 268, 269, 270, 271, 272 +}; + +bool proc_smwp_send_flag = false; +#define JADARD_PROC_SMWP_FILE "SMWP" +struct proc_dir_entry *jadard_proc_SMWP_file = NULL; +#define JADARD_PROC_GESTURE_FILE "GESTURE" +struct proc_dir_entry *jadard_proc_GESTURE_file = NULL; +#endif + +#ifdef JD_HIGH_SENSITIVITY +bool proc_Hsens_send_flag = false; +#define JADARD_PROC_HIGH_SENSITIVITY_FILE "SENSITIVITY" +struct proc_dir_entry *jadard_proc_high_sensitivity_file = NULL; +#endif + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING +#define JADARD_PROC_SORTING_TEST_FILE "sorting_test" +struct proc_dir_entry *jadard_proc_sorting_test_file; +#endif + +#ifdef JD_ROTATE_BORDER +bool proc_rotate_border_flag = false; +#define JADARD_PROC_ROTATE_BORDER_FILE "BORDER" +struct proc_dir_entry *jadard_proc_rotate_border_file = NULL; +#endif + +#ifdef JD_EARPHONE_DETECT +bool proc_earphone_detect_flag = false; +#define JADARD_PROC_EARPHONE_FILE "EARPHONE" +struct proc_dir_entry *jadard_proc_earphone_file = NULL; +#endif + +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_DISABLE) +bool proc_proximity_detect_flag = false; +#define JADARD_PROC_PROXIMITY_FILE "PROXIMITY" +struct proc_dir_entry *jadard_proc_proximity_file = NULL; +#endif + +static bool jadard_DbicWaitBusReady(uint8_t cmd) +{ + uint8_t status = 0; + uint8_t int_clr_busy = JD_DBIC_INT_CLR_BUSY_MSK; + uint32_t retry_time = 0x30; + + /* Get ready flag of bus status */ + g_module_fp.fp_register_read((uint32_t)JD_DBIC_STATUS, &status, 1); + + /* Wait bus ready & timeout */ + while ((status & (uint8_t)JD_DBIC_STATUS_RDY_BUSY_MSK) != (uint8_t)JD_DBIC_STATUS_RDY_MSK) { + /* Add delay time to avoid bus busy error */ + if (cmd == 0x29) { + msleep(10); + } + + if ((retry_time--) <= 0) { + /* Clear bus error flag */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_INT_CLR, &int_clr_busy, 1); + return true; + } + + /* Get ready flag of bus status */ + g_module_fp.fp_register_read((uint32_t)JD_DBIC_STATUS, &status, 1); + } + + return false; +} + +static bool jadard_DbicWaitBusTransferDone(bool int_clr_en) +{ + uint8_t status; + uint8_t irq_valid_msk = JD_DBIC_IRQ_VALID_MSK; + uint8_t int_clr_busy = JD_DBIC_INT_CLR_BUSY_MSK; + uint32_t retry_time = 0x30; + + /* Get transfer status of bus */ + g_module_fp.fp_register_read((uint32_t)JD_DBIC_STATUS, &status, 1); + + while ((status & (uint8_t)JD_DBIC_IRQ_VALID_MSK) == 0x00) { + if (((retry_time--) <= 0) || (status & (uint8_t)JD_DBIC_STATUS_BUSY_MSK)) { + /* Clear bus error flag */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_INT_CLR, &int_clr_busy, 1); + return true; + } + + /* Get transfer status of bus */ + g_module_fp.fp_register_read((uint32_t)JD_DBIC_STATUS, &status, 1); + } + + /* Clear transfer flag */ + if (int_clr_en) { + g_module_fp.fp_register_write((uint32_t)JD_DBIC_INT_CLR, &irq_valid_msk, 1); + } + + /* Return error when spi_done_int = 1 & dbic_busy_err = 1 */ + if (status & (uint8_t)JD_DBIC_STATUS_BUSY_MSK) { + /* Clear bus error flag */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_INT_CLR, &int_clr_busy, 1); + return true; + } + + return false; +} + +uint8_t jadard_DbicWriteDDReg(uint8_t cmd, uint8_t *par, uint8_t par_len) +{ + uint8_t i; + bool dbi_c_status; + uint8_t write_run = JD_DBIC_WRITE_RUN; + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_Off(); + mdelay(100); +#endif + + /* Re-send command when dbic busy error */ + DBIC_CMD_RESEND: + + /* End condition of payload */ + /* 1st condition: cmd and len equal 0x00 */ + /* 2nd condition: timeout of dbi c bus */ + if (jadard_DbicWaitBusReady(cmd)) { + goto DBIC_CMD_RESEND; + } else { + if ((cmd == 0x10) || (cmd == 0x11) || (cmd == 0x28) || + (cmd == 0x29) || (cmd == 0x34) || (cmd == 0x35)) { + par_len = 0; + } + + /* Setup cmd & length */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_CMD, &cmd, 1); + g_module_fp.fp_register_write((uint32_t)JD_DBIC_CMD_LEN, &par_len, 1); + + /* Enable transfer */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_SPI_RUN, &write_run, 1); + + /* Polling transfer one byte done or task done */ + dbi_c_status = jadard_DbicWaitBusTransferDone(true); + + if (dbi_c_status) { + goto DBIC_CMD_RESEND; + } + + /* Write parameter */ + for (i = 0; i < par_len; i++) { + if (jadard_DbicWaitBusReady(cmd)) { + goto DBIC_CMD_RESEND; + } + + /* Write */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_WRITE_DATA, par+i, 1); + + /* Polling transfer one byte done or task done */ + dbi_c_status = jadard_DbicWaitBusTransferDone(true); + + if (dbi_c_status) { + goto DBIC_CMD_RESEND; + } + } + } + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + + return JD_DBIC_READ_WRITE_SUCCESS; +} + +uint8_t jadard_DbicReadDDReg(uint8_t cmd, uint8_t *rpar, uint8_t rpar_len) +{ + uint8_t i; + uint8_t read_data_cmd = JD_DBIC_READ_DATA_CMD; + uint8_t read_run = JD_DBIC_READ_RUN; + uint8_t irq_valid_msk = JD_DBIC_IRQ_VALID_MSK; + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_Off(); + mdelay(100); +#endif + + /* Set read cmd */ + if (jadard_DbicWriteDDReg(JD_DBIC_READ_SET_CMD, &cmd, 1) == JD_DBIC_READ_WRITE_FAIL) { +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + return JD_DBIC_READ_WRITE_FAIL; + } else { + /* Setup cmd & length */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_CMD, &read_data_cmd, 1); + g_module_fp.fp_register_write((uint32_t)JD_DBIC_CMD_LEN, &rpar_len, 1); + + /* Enable transfer */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_SPI_RUN, &read_run, 1); + + /* Read parameter */ + for (i = 0; i < rpar_len; i++) { + /* Polling transfer one byte done or task done */ + if (jadard_DbicWaitBusTransferDone(false)) { +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + return JD_DBIC_READ_WRITE_FAIL; + } + + g_module_fp.fp_register_read((uint32_t)JD_DBIC_READ_DATA, rpar+i, 1); + g_module_fp.fp_register_write((uint32_t)JD_DBIC_INT_CLR, &irq_valid_msk, 1); + } + } +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + + return JD_DBIC_READ_WRITE_SUCCESS; +} + +static int jadard_Dbi_DDReg_Write_StdCmd(uint8_t WriteCmd, uint8_t *WriteData, uint8_t WriteLen, uint32_t offset) +{ + uint32_t WriteAddr; + + WriteData[0] = WriteCmd; + WriteAddr = JD_DBI_DDREG_STD_CMD_BASE_ADDR + (WriteCmd << 8); + + return g_module_fp.fp_register_write(WriteAddr + offset, WriteData, WriteLen); +} + +static int jadard_Dbi_DDReg_Write(uint8_t WritePage, uint8_t WriteCmd, uint8_t *WriteData, uint8_t WriteLen, uint32_t offset) +{ + uint32_t WriteAddr; + + WriteAddr = JD_DBI_DDREG_BASE_ADDR + ((WritePage & 0x0F) << 16) + (WriteCmd << 8) + 1; + + return g_module_fp.fp_register_write(WriteAddr + offset, WriteData, WriteLen); +} + +static int jadard_Dbi_DDReg_Read_StdCmd(uint8_t ReadCmd, uint8_t *ReadBuffer, uint8_t ReadLen, uint32_t offset) +{ + int ReCode; + uint32_t ReadAddr; + + ReadAddr = JD_DBI_DDREG_STD_CMD_BASE_ADDR + (ReadCmd << 8) + 1; + ReCode = g_module_fp.fp_register_read(ReadAddr + offset, ReadBuffer, ReadLen); + + return ReCode; +} + +static int jadard_Dbi_DDReg_Read(uint8_t ReadPage, uint8_t ReadCmd, uint8_t *ReadBuffer, uint8_t ReadLen, uint32_t offset) +{ + int ReCode; + uint32_t ReadAddr; + + ReadAddr = JD_DBI_DDREG_BASE_ADDR + ((ReadPage & 0x0F) << 16) + (ReadCmd << 8) + 1; + ReCode = g_module_fp.fp_register_read(ReadAddr + offset, ReadBuffer, ReadLen); + + return ReCode; +} + +uint8_t jadard_DbiWriteDDReg(uint8_t page, uint8_t cmd, uint8_t *par, uint8_t par_len) +{ + uint8_t *WriteData; + uint32_t AddrOffset; + + AddrOffset = (pjadard_ic_data->JD_MODULE_CASCADE_MODE == JD_CASCADE_MODE_ENABLE) + ? pjadard_ic_data->JD_BOTH_ADDR_OFFSET : pjadard_ic_data->JD_MASTER_ADDR_OFFSET; + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_Off(); + mdelay(100); +#endif + if ((cmd == 0x10) || (cmd == 0x11) || (cmd == 0x28) || + (cmd == 0x29) || (cmd == 0x34) || (cmd == 0x35) || + (pjadard_ts_data->dbi_std_mode_enable == true)) { + WriteData = kzalloc((par_len + 1) * sizeof(uint8_t), GFP_KERNEL); + if (WriteData == NULL) { +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + JD_E("%s: Memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + if (par_len == 0x00) { + WriteData[0] = cmd; + jadard_Dbi_DDReg_Write_StdCmd(cmd, WriteData, 0x01, AddrOffset); + } else { + WriteData[0] = cmd; + memcpy(WriteData + 1, par, par_len); + jadard_Dbi_DDReg_Write_StdCmd(cmd, WriteData, par_len + 1, AddrOffset); + } + + kfree(WriteData); + } else { + jadard_Dbi_DDReg_Write(page, cmd, par, par_len, AddrOffset); + } + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + + return JD_DBIC_READ_WRITE_SUCCESS; +} + +uint8_t jadard_DbiReadDDReg(uint8_t page, uint8_t cmd, uint8_t *rpar, uint8_t rpar_len, uint32_t offset) +{ +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_Off(); + mdelay(100); +#endif + + if ((cmd == 0x0A) || (cmd == 0x09) || (pjadard_ts_data->dbi_std_mode_enable == true)) { + jadard_Dbi_DDReg_Read_StdCmd(cmd, rpar, rpar_len, offset); + } else { + jadard_Dbi_DDReg_Read(page, cmd, rpar, rpar_len, offset); + } + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + + return JD_DBIC_READ_WRITE_SUCCESS; +} + +static void jadard_report_all_leave_event(struct jadard_ts_data *ts) +{ +#ifndef JD_PROTOCOL_A + int i; + + for (i = 0; i < pjadard_ic_data->JD_MAX_PT; i++) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); +#ifdef JD_SANSUMG_PALM_EN + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, 0); + input_report_abs(ts->input_dev, ABS_MT_CUSTOM, 0); +#endif +#ifdef JD_PALM_EN + input_report_key(ts->input_dev, JD_BTN_PALM, 0); +#endif + } +#endif + + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_sync(ts->input_dev); +} + +int jadard_report_data_init(void) +{ + int i; + + if (pjadard_report_data->touch_coord_info != NULL) { + kfree(pjadard_report_data->touch_coord_info); + pjadard_report_data->touch_coord_info = NULL; + } + + pjadard_report_data->touch_coord_size = pjadard_ic_data->JD_MAX_PT * JD_FINGER_DATA_SIZE; + pjadard_report_data->touch_coord_info = + kzalloc(sizeof(uint8_t) * (pjadard_report_data->touch_coord_size), GFP_KERNEL); + + if (pjadard_report_data->touch_coord_info == NULL) { + goto mem_alloc_fail; + } + +#ifdef JD_SANSUMG_PALM_EN + if (pjadard_report_data->touch_palm_info != NULL) { + kfree(pjadard_report_data->touch_palm_info); + pjadard_report_data->touch_palm_info = NULL; + } + + pjadard_report_data->touch_palm_size = pjadard_ic_data->JD_MAX_PT * JD_PALM_DATA_SIZE; + pjadard_report_data->touch_palm_info = + kzalloc(sizeof(uint8_t) * (pjadard_report_data->touch_palm_size), GFP_KERNEL); + + if (pjadard_report_data->touch_palm_info == NULL) { + goto mem_alloc_fail; + } +#endif + + if (pjadard_host_data == NULL) { + pjadard_host_data = kzalloc(sizeof(struct jadard_host_data), GFP_KERNEL); + if (pjadard_host_data == NULL) + goto mem_alloc_fail; + + pjadard_host_data->id = kzalloc(sizeof(uint8_t)*(pjadard_ic_data->JD_MAX_PT), GFP_KERNEL); + if (pjadard_host_data->id == NULL) + goto mem_alloc_fail; + + pjadard_host_data->x = kzalloc(sizeof(int)*(pjadard_ic_data->JD_MAX_PT), GFP_KERNEL); + if (pjadard_host_data->x == NULL) { + goto mem_alloc_fail; + } else { + /* For setting touch event */ + for (i = 0; i < pjadard_ic_data->JD_MAX_PT; i++) { + pjadard_host_data->x[i] = 0xFFFF; + } + pjadard_host_data->stylus.x = 0xFFFF; + } + + pjadard_host_data->y = kzalloc(sizeof(int)*(pjadard_ic_data->JD_MAX_PT), GFP_KERNEL); + if (pjadard_host_data->y == NULL) + goto mem_alloc_fail; + + pjadard_host_data->w = kzalloc(sizeof(int)*(pjadard_ic_data->JD_MAX_PT), GFP_KERNEL); + if (pjadard_host_data->w == NULL) + goto mem_alloc_fail; + +#ifdef JD_SANSUMG_PALM_EN + pjadard_host_data->maj = kzalloc(sizeof(int)*(pjadard_ic_data->JD_MAX_PT), GFP_KERNEL); + if (pjadard_host_data->maj == NULL) + goto mem_alloc_fail; + + pjadard_host_data->min = kzalloc(sizeof(int)*(pjadard_ic_data->JD_MAX_PT), GFP_KERNEL); + if (pjadard_host_data->min == NULL) + goto mem_alloc_fail; +#endif + + pjadard_host_data->event = kzalloc(sizeof(int)*(pjadard_ic_data->JD_MAX_PT), GFP_KERNEL); + if (pjadard_host_data->event == NULL) + goto mem_alloc_fail; + } + +#ifdef JD_SMART_WAKEUP + pjadard_host_data->SMWP_event_chk = 0; +#endif + + return JD_NO_ERR; + +mem_alloc_fail: + if (pjadard_host_data->id != NULL) { + kfree(pjadard_host_data->id); + pjadard_host_data->id = NULL; + } + + if (pjadard_host_data->x != NULL) { + kfree(pjadard_host_data->x); + pjadard_host_data->x = NULL; + } + + if (pjadard_host_data->y != NULL) { + kfree(pjadard_host_data->y); + pjadard_host_data->y = NULL; + } + + if (pjadard_host_data->w != NULL) { + kfree(pjadard_host_data->w); + pjadard_host_data->w = NULL; + } + +#ifdef JD_SANSUMG_PALM_EN + if (pjadard_host_data->maj != NULL) { + kfree(pjadard_host_data->maj); + pjadard_host_data->maj = NULL; + } + + if (pjadard_host_data->min != NULL) { + kfree(pjadard_host_data->min); + pjadard_host_data->min = NULL; + } +#endif + + if (pjadard_host_data->event != NULL) { + kfree(pjadard_host_data->event); + pjadard_host_data->event = NULL; + } + + if (pjadard_host_data != NULL) { + kfree(pjadard_host_data); + pjadard_host_data = NULL; + } + + if (pjadard_report_data->touch_coord_info != NULL) { + kfree(pjadard_report_data->touch_coord_info); + pjadard_report_data->touch_coord_info = NULL; + } + +#ifdef JD_SANSUMG_PALM_EN + if (pjadard_report_data->touch_palm_info != NULL) { + kfree(pjadard_report_data->touch_palm_info); + pjadard_report_data->touch_palm_info = NULL; + } +#endif + JD_E("%s: Memory allocate fail!\n", __func__); + + return JD_MEM_ALLOC_FAIL; +} + +#ifdef JD_SMART_WAKEUP +static void jadard_wake_event_report(void) +{ + int event_chk = pjadard_host_data->SMWP_event_chk; + + JD_I("%s: Entering\n", __func__); + + if (event_chk > 0) { + JD_I("%s SMART WAKEUP KEY event %d press\n", __func__, event_chk); + input_report_key(pjadard_ts_data->input_dev, event_chk, 1); + input_sync(pjadard_ts_data->input_dev); + + JD_I("%s SMART WAKEUP KEY event %d release\n", __func__, event_chk); + input_report_key(pjadard_ts_data->input_dev, event_chk, 0); + input_sync(pjadard_ts_data->input_dev); + pjadard_host_data->SMWP_event_chk = 0; + } + + JD_I("%s: End\n", __func__); +} + +static void jadard_wake_event_parse(struct jadard_ts_data *ts, int ts_status) +{ + uint8_t wake_event = pjadard_report_data->touch_event_info; + int i; + + JD_I("%s: Entering, ts_status=%d, wake_event=0x%02x\n", __func__, ts_status, wake_event); + + for (i = 0; i < JD_GEST_SUP_NUM; i++) { + if (wake_event == jd_gest_event[i]) { + if (ts->gesture_cust_en[i]) { + pjadard_host_data->SMWP_event_chk = jd_gest_key_def[i]; + } else { + pjadard_host_data->SMWP_event_chk = 0; + } + break; + } + } + + JD_I("%s:end, SMWP_event_chk=%d\n", __func__, pjadard_host_data->SMWP_event_chk); +} +#endif + +void jadard_stylus_report_points(struct jadard_ts_data *ts) +{ + JD_D("%s: Entering\n", __func__); + + if (pjadard_host_data->stylus.event == JD_UP_EVENT) { + JD_D("stylus.x=%d, stylus.y=%d\n", pjadard_host_data->stylus.x, + pjadard_host_data->stylus.y); + + pjadard_host_data->stylus.pre_btn = 0; + pjadard_host_data->stylus.pre_btn2 = 0; + input_report_key(ts->stylus_dev, BTN_STYLUS, 0); + input_report_key(ts->stylus_dev, BTN_STYLUS2, 0); + input_report_key(ts->stylus_dev, BTN_TOUCH, 0); + input_report_abs(ts->stylus_dev, ABS_PRESSURE, 0); + input_report_abs(ts->stylus_dev, ABS_DISTANCE, 0); + input_report_abs(ts->stylus_dev, ABS_TILT_X, 0); + input_report_abs(ts->stylus_dev, ABS_TILT_Y, 0); + input_report_key(ts->stylus_dev, BTN_TOOL_RUBBER, 0); + input_report_key(ts->stylus_dev, BTN_TOOL_PEN, 0); + } else if ((pjadard_host_data->stylus.event == JD_DOWN_EVENT) || + (pjadard_host_data->stylus.event == JD_CONTACT_EVENT)) { + JD_D("stylus.x=%d, stylus.y=%d, stylus.w=%d\n", pjadard_host_data->stylus.x, + pjadard_host_data->stylus.y, pjadard_host_data->stylus.w); + + if (pjadard_ic_data->JD_X_RES <= pjadard_ic_data->JD_Y_RES) { + input_report_abs(ts->stylus_dev, ABS_X, pjadard_host_data->stylus.x); + input_report_abs(ts->stylus_dev, ABS_Y, pjadard_host_data->stylus.y); + } else { + input_report_abs(ts->stylus_dev, ABS_X, pjadard_host_data->stylus.y); + input_report_abs(ts->stylus_dev, ABS_Y, pjadard_host_data->stylus.x); + } + + if (pjadard_host_data->stylus.btn != pjadard_host_data->stylus.pre_btn) { + JD_I("BTN: %d\n", pjadard_host_data->stylus.btn); + input_report_key(ts->stylus_dev, BTN_STYLUS, pjadard_host_data->stylus.btn); + pjadard_host_data->stylus.pre_btn = pjadard_host_data->stylus.btn; + } + + if (pjadard_host_data->stylus.btn2 != pjadard_host_data->stylus.pre_btn2) { + JD_I("BTN2: %d\n", pjadard_host_data->stylus.btn2); + input_report_key(ts->stylus_dev, BTN_STYLUS2, pjadard_host_data->stylus.btn2); + pjadard_host_data->stylus.pre_btn2 = pjadard_host_data->stylus.btn2; + } + + input_report_abs(ts->stylus_dev, ABS_TILT_X, pjadard_host_data->stylus.tilt_x); + input_report_abs(ts->stylus_dev, ABS_TILT_Y, pjadard_host_data->stylus.tilt_y); + input_report_key(ts->stylus_dev, BTN_TOOL_PEN, 1); + + /* Disable stylus.hover flag */ + input_report_key(ts->stylus_dev, BTN_TOUCH, 1); + input_report_abs(ts->stylus_dev, ABS_DISTANCE, 0); + input_report_abs(ts->stylus_dev, ABS_PRESSURE, pjadard_host_data->stylus.w); + } + + input_sync(ts->stylus_dev); + + JD_D("%s:end\n", __func__); +} + +void jadard_report_points(struct jadard_ts_data *ts) +{ + int i; + + JD_D("%s: Entering\n", __func__); + +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_DISABLE) + /* Report p-sensor event */ + ts->proximity_detect = (pjadard_report_data->touch_state_info[3] >> 6) & 0x01; + if (ts->proximity_detect == 1) { + /* Proximity detect from 0 to 1 */ + if ((ts->proximity_enable) && (ts->pre_proximity_detect == 0)) { + JD_I("%s: Proximity On(Near)\n", __func__); +#if (JD_PROXIMITY_MODE == JD_PROXIMITY_SUSPEND_RESUME) + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); +#elif (JD_PROXIMITY_MODE == JD_PROXIMITY_BACKLIGHT) + /* Add report proximity near event to system */ +#endif + } + } else { + /* Proximity detect from 1 to 0 */ + if (ts->pre_proximity_detect) { + JD_I("%s: Proximity Off(Far)\n", __func__); +#if (JD_PROXIMITY_MODE == JD_PROXIMITY_SUSPEND_RESUME) + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); +#elif (JD_PROXIMITY_MODE == JD_PROXIMITY_BACKLIGHT) + /* Add report proximity far event to system */ +#endif + } + } + ts->pre_proximity_detect = ts->proximity_detect; +#endif + +#ifdef JD_PALM_EN + /* Report palm event key */ + ts->palm_detect = pjadard_report_data->touch_state_info[0] & 0x01; + if (ts->palm_detect == 1) { + /* Palm detect from 0 to 1 */ + if (ts->pre_palm_detect == 0) { + JD_I("%s: Palm On\n", __func__); + input_report_key(ts->input_dev, JD_BTN_PALM, 1); + } + } else { + /* Palm detect from 1 to 0 */ + if (ts->pre_palm_detect) { + JD_I("%s: Palm Off\n", __func__); + input_report_key(ts->input_dev, JD_BTN_PALM, 0); + } + } + ts->pre_palm_detect = ts->palm_detect; +#endif + + for (i = 0; i < pjadard_ic_data->JD_MAX_PT; i++) { + if (pjadard_host_data->event[i] == JD_UP_EVENT) { +#ifdef JD_SANSUMG_PALM_EN + JD_D("ID=%d, x=%d, y=%d, maj=%d, min=%d, palm=%d\n", pjadard_host_data->id[i], + pjadard_host_data->x[i], pjadard_host_data->y[i], + pjadard_host_data->maj[i], pjadard_host_data->min[i], ts->palm_detect); +#else + JD_D("ID=%d, x=%d, y=%d\n", pjadard_host_data->id[i], + pjadard_host_data->x[i], pjadard_host_data->y[i]); +#endif + input_mt_slot(ts->input_dev, pjadard_host_data->id[i]); +#ifdef JD_SANSUMG_PALM_EN + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, 0); + input_report_abs(ts->input_dev, ABS_MT_CUSTOM, 0); +#endif + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + + if (pjadard_host_data->finger_num == 0) { + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); + } + } else if ((pjadard_host_data->event[i] == JD_DOWN_EVENT) || + (pjadard_host_data->event[i] == JD_CONTACT_EVENT)) { +#ifdef JD_SANSUMG_PALM_EN + JD_D("ID=%d, x=%d, y=%d, w=%d, maj=%d, min=%d, palm=%d\n", pjadard_host_data->id[i], + pjadard_host_data->x[i], pjadard_host_data->y[i], pjadard_host_data->w[i], + pjadard_host_data->maj[i], pjadard_host_data->min[i], ts->palm_detect); +#else + JD_D("ID=%d, x=%d, y=%d, w=%d\n", pjadard_host_data->id[i], + pjadard_host_data->x[i], pjadard_host_data->y[i], pjadard_host_data->w[i]); +#endif + +#ifndef JD_PROTOCOL_A + input_mt_slot(ts->input_dev, pjadard_host_data->id[i]); +#endif + input_report_key(ts->input_dev, BTN_TOUCH, 1); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 1); +#ifdef JD_SANSUMG_PALM_EN + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, pjadard_host_data->maj[i]); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, pjadard_host_data->min[i]); +#else + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, pjadard_host_data->w[i]); +#endif + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, pjadard_host_data->id[i]); +#ifndef JD_PROTOCOL_A +#if JD_REPORT_PRESSURE + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, pjadard_host_data->w[i]); +#endif + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, pjadard_host_data->w[i]); +#endif + if (pjadard_ic_data->JD_X_RES <= pjadard_ic_data->JD_Y_RES) { + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pjadard_host_data->x[i]); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pjadard_host_data->y[i]); + } else { + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, pjadard_host_data->y[i]); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, pjadard_host_data->x[i]); + } +#ifndef JD_PROTOCOL_A + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); +#else + input_mt_sync(ts->input_dev); +#endif + } + } + + input_sync(ts->input_dev); + + JD_D("%s:end\n", __func__); +} + +static int jadard_report_data(struct jadard_ts_data *ts, int ts_path, int ts_status) +{ + JD_D("%s: Entering, ts_status=%d\n", __func__, ts_status); + + if (ts_path == JD_REPORT_COORD) { +#ifdef JD_REPORT_FRAME_CHECK + if (pjadard_host_data->pre_finger_frame != pjadard_host_data->finger_frame) { +#endif + g_module_fp.fp_report_points(ts); +#ifdef JD_REPORT_FRAME_CHECK + } + pjadard_host_data->pre_finger_frame = pjadard_host_data->finger_frame; +#endif + + if (pjadard_ic_data->JD_STYLUS_EN) { +#ifdef JD_REPORT_FRAME_CHECK + if (pjadard_host_data->stylus.pre_pen_frame != pjadard_host_data->stylus.pen_frame) { +#endif + jadard_stylus_report_points(ts); +#ifdef JD_REPORT_FRAME_CHECK + } + pjadard_host_data->stylus.pre_pen_frame = pjadard_host_data->stylus.pen_frame; +#endif + } +#ifdef JD_SMART_WAKEUP + } else if (ts_path == JD_REPORT_SMWP_EVENT) { + jadard_wake_event_report(); +#endif + } else { + JD_E("%s: Not support event\n", __func__); + ts_status = JD_IRQ_EVENT_FAIL; + } + + JD_D("%s: end, ts_status=%d\n", __func__, ts_status); + + return ts_status; +} + +#define READ_VAR_BIT(var, nb) (((var) >> (nb)) & 0x1) +static bool jadard_wgp_pen_id_crc(uint8_t *p_id) +{ + uint64_t pen_id, input; + uint8_t hash_id, devidend; + uint8_t pol = 0x43; + int i; + + for (i = 0; i < 8; i++) + JD_I("%s: pen id[%d] = %x\n", __func__, i, p_id[i]); + + pen_id = (uint64_t)p_id[0] | ((uint64_t)p_id[1] << 8) | + ((uint64_t)p_id[2] << 16) | ((uint64_t)p_id[3] << 24) | + ((uint64_t)p_id[4] << 32) | ((uint64_t)p_id[5] << 40) | + ((uint64_t)p_id[6] << 48); + hash_id = p_id[7]; + + JD_I("%s: pen id = %llx, hash id = %x\n", __func__, pen_id, hash_id); + + input = pen_id << 6; + devidend = input >> (44 + 6); + + for (i = (44 + 6 - 1); i >= 0; i--) { + if (READ_VAR_BIT(devidend, 6)) + devidend = devidend ^ pol; + devidend = devidend << 1 | READ_VAR_BIT(input, i); + } + + if (READ_VAR_BIT(devidend, 6)) + devidend = devidend ^ pol; + + JD_I("%s: devidend = %x\n", __func__, devidend); + + if (devidend == hash_id) { + pjadard_host_data->stylus.pen_id = pen_id; + return true; + } else { + pjadard_host_data->stylus.pen_id = 0; + return false; + } +} + +static int jadard_parse_report_points(struct jadard_ts_data *ts, int ts_status) +{ + uint8_t *pCoord_info = NULL; + int x, y, w, i; + int p_x, p_y, p_w; + int8_t p_tilt_x, p_tilt_y; + uint8_t p_hover, p_btn, p_btn2, p_id_sel; + uint8_t p_id[8]; + uint8_t ratio = pjadard_ic_data->JD_STYLUS_RATIO; +#ifdef JD_SANSUMG_PALM_EN + uint8_t *pPalm_info = NULL; + int maj, min; +#endif + + JD_D("%s: Entering, ts_status=%d finger_num = %d\n", __func__, + ts_status, pjadard_host_data->finger_num); + +#ifdef JD_REPORT_FRAME_CHECK + if (pjadard_host_data->pre_finger_frame != pjadard_host_data->finger_frame) { +#endif + if (pjadard_ic_data->JD_X_RES > pjadard_ic_data->JD_Y_RES) { + ts->pdata->abs_x_max = pjadard_ic_data->JD_Y_RES; + ts->pdata->abs_y_max = pjadard_ic_data->JD_X_RES; + } + + for (i = 0; i < pjadard_ic_data->JD_MAX_PT; i++) { + #if defined(JD_REPORT_FORMAT_V2) + x = 0xFFFF; + if ((pjadard_host_data->id[i] & 0x10) == 0x10) { + #endif + pCoord_info = pjadard_report_data->touch_coord_info + (JD_FINGER_DATA_SIZE * i); + x = (uint16_t)(pCoord_info[0] << 8 | pCoord_info[1]); + y = (uint16_t)(pCoord_info[2] << 8 | pCoord_info[3]); + w = pCoord_info[4]; /* Max:255 Min:0 */ + #ifdef JD_SANSUMG_PALM_EN + pPalm_info = pjadard_report_data->touch_palm_info + (JD_PALM_DATA_SIZE * i); + maj = pPalm_info[1]; + min = pPalm_info[0]; + #endif + #if defined(JD_REPORT_FORMAT_V2) + } + #endif + pjadard_host_data->id[i] = i; + if ((x >= 0 && x <= ts->pdata->abs_x_max) && + (y >= 0 && y <= ts->pdata->abs_y_max)) { + /* Set touch event */ + if (pjadard_host_data->x[i] == 0xFFFF) { + pjadard_host_data->event[i] = JD_DOWN_EVENT; + } else { + pjadard_host_data->event[i] = JD_CONTACT_EVENT; + } + + /* Set coordinate */ + pjadard_host_data->x[i] = x; + pjadard_host_data->y[i] = y; + pjadard_host_data->w[i] = w; + #ifdef JD_SANSUMG_PALM_EN + pjadard_host_data->maj[i] = maj; + pjadard_host_data->min[i] = min; + #endif + } else { + /* Set touch event */ + if (pjadard_host_data->x[i] == 0xFFFF) { + pjadard_host_data->event[i] = JD_NO_EVENT; + } else { + pjadard_host_data->event[i] = JD_UP_EVENT; + } + + /* Set coordinate to default */ + pjadard_host_data->x[i] = 0xFFFF; + pjadard_host_data->y[i] = 0xFFFF; + pjadard_host_data->w[i] = 0xFFFF; + #ifdef JD_SANSUMG_PALM_EN + pjadard_host_data->maj[i] = 0xFFFF; + pjadard_host_data->min[i] = 0xFFFF; + #endif + } + + #ifdef JD_SANSUMG_PALM_EN + JD_D("ID=%d, x=%d, y=%d, w=%d, maj=%d, min=%d, event=%d\n", pjadard_host_data->id[i], + pjadard_host_data->x[i], pjadard_host_data->y[i], pjadard_host_data->w[i], + pjadard_host_data->maj[i], pjadard_host_data->min[i], pjadard_host_data->event[i]); + #else + JD_D("ID=%d, x=%d, y=%d, w=%d, event=%d\n", pjadard_host_data->id[i], pjadard_host_data->x[i], + pjadard_host_data->y[i], pjadard_host_data->w[i], pjadard_host_data->event[i]); + #endif + } +#ifdef JD_REPORT_FRAME_CHECK + } +#endif + + /* Copy touch stylus info. */ + if (pjadard_ic_data->JD_STYLUS_EN) { +#ifdef JD_REPORT_FRAME_CHECK + if (pjadard_host_data->stylus.pre_pen_frame != pjadard_host_data->stylus.pen_frame) { +#endif + pCoord_info = &(pjadard_report_data->touch_stylus_info[0]); + p_x = (uint16_t)(pCoord_info[0] << 8 | pCoord_info[1]); + p_y = (uint16_t)(pCoord_info[2] << 8 | pCoord_info[3]); + p_w = (uint16_t)(pCoord_info[4] << 8 | pCoord_info[5]); + p_tilt_x = (int8_t)pCoord_info[6]; + p_tilt_y = (uint16_t)(pCoord_info[7] << 8 | pCoord_info[8]); + p_hover = pCoord_info[9] & 0x01; + p_btn = pCoord_info[9] & 0x02; + p_btn2 = pCoord_info[9] & 0x04; + + if (pjadard_ic_data->JD_STYLUS_ID_EN) { + if (pCoord_info[9] & 0x08) { + p_id_sel = (pCoord_info[9] & 0xF0) >> 4; + if (p_id_sel < 4) { + p_id[p_id_sel * 2] = pCoord_info[12]; + p_id[p_id_sel * 2 + 1] = pCoord_info[11]; + + if (p_id_sel == 3) { + if (!jadard_wgp_pen_id_crc(p_id)) + JD_E("Pen_ID CRC not match\n"); + } + } else { + JD_E("Pen_ID_Select %d overflow\n", p_id_sel); + } + } else { + pjadard_host_data->stylus.battery_info = pCoord_info[10]; + JD_D("%s: battery info = %x\n", __func__, pjadard_host_data->stylus.battery_info); + } + } + + JD_D("%s: p_x=%d, p_y=%d, p_w=%d, p_tilt_x=%d, p_tilt_y=%d, p_hover=%d, p_btn=%d, p_btn2=%d\n", + __func__, p_x, p_y, p_w, p_tilt_x, p_tilt_y, p_hover, p_btn, p_btn2); + + if ((p_x >= 0 && p_x <= ((ts->pdata->abs_x_max + 1)*ratio - 1)) && + (p_y >= 0 && p_y <= ((ts->pdata->abs_y_max + 1)*ratio - 1))) { + /* Set pen event */ + if (pjadard_host_data->stylus.x == 0xFFFF) { + pjadard_host_data->stylus.event = JD_DOWN_EVENT; + } else { + pjadard_host_data->stylus.event = JD_CONTACT_EVENT; + } + + /* Set pen coordinate */ + pjadard_host_data->stylus.x = p_x; + pjadard_host_data->stylus.y = p_y; + pjadard_host_data->stylus.w = p_w; + pjadard_host_data->stylus.tilt_x = p_tilt_x; + pjadard_host_data->stylus.tilt_y = p_tilt_y; + pjadard_host_data->stylus.hover = p_hover; + pjadard_host_data->stylus.btn = p_btn; + pjadard_host_data->stylus.btn2 = p_btn2; + } else { + /* Set pen event */ + if (pjadard_host_data->stylus.x == 0xFFFF) { + pjadard_host_data->stylus.event = JD_NO_EVENT; + } else { + pjadard_host_data->stylus.event = JD_UP_EVENT; + } + + /* Set pen coordinate to default */ + pjadard_host_data->stylus.x = 0xFFFF; + pjadard_host_data->stylus.y = 0xFFFF; + pjadard_host_data->stylus.w = 0xFFFF; + pjadard_host_data->stylus.tilt_x = 0; + pjadard_host_data->stylus.tilt_y = 0; + pjadard_host_data->stylus.hover = 0; + pjadard_host_data->stylus.btn = 0; + pjadard_host_data->stylus.btn2 = 0; + } + + JD_D("%s: p_x=%d, p_y=%d, p_w=%d, p_tilt_x=%d, p_tilt_y=%d, p_hover=%d, p_btn=%d, p_btn2=%d\n", + __func__, pjadard_host_data->stylus.x, pjadard_host_data->stylus.y, pjadard_host_data->stylus.w, + pjadard_host_data->stylus.tilt_x, pjadard_host_data->stylus.tilt_y, + pjadard_host_data->stylus.hover, pjadard_host_data->stylus.btn, pjadard_host_data->stylus.btn2); +#ifdef JD_REPORT_FRAME_CHECK + } +#endif + } + + JD_D("%s: end\n", __func__); + + return ts_status; +} + +int jadard_parse_report_data(struct jadard_ts_data *ts, int irq_event, int ts_status) +{ + JD_D("%s: start now_status=%d\n", __func__, ts_status); + + switch (irq_event) { + case JD_REPORT_COORD: + ts_status = jadard_parse_report_points(ts, ts_status); + break; +#if defined(JD_SMART_WAKEUP) + case JD_REPORT_SMWP_EVENT: + jadard_wake_event_parse(ts, ts_status); + break; +#endif + default: + JD_E("%s: Not support event(%d)\n", __func__, irq_event); + ts_status = JD_IRQ_EVENT_FAIL; + break; + } + + JD_D("%s: end now_status=%d\n", __func__, ts_status); + + return ts_status; +} + +int jadard_distribute_touch_data(struct jadard_ts_data *ts, uint8_t *buf, int irq_event, int ts_status) +{ + struct jadard_report_data *pReport_data = pjadard_report_data; +#if defined(JD_REPORT_FORMAT_V2) + uint32_t buf_offset; +#endif + + JD_D("%s: Entering, ts_status=%d\n", __func__, ts_status); + + switch (irq_event) { + case JD_REPORT_COORD: +#if defined(JD_REPORT_FORMAT_V2) + buf_offset = JD_TOUCH_HEADER_SIZE; + #ifdef JD_REPORT_FRAME_CHECK + pjadard_host_data->finger_frame = buf[JD_FINGER_FRAME_ADDR] >> 2; + #endif + + if (pjadard_ic_data->JD_STYLUS_EN) { + /* Copy touch stylus info. */ + #ifdef JD_REPORT_FRAME_CHECK + pjadard_host_data->stylus.pen_frame = buf[JD_TOUCH_STYLUS_INFO_ADDR]; + #endif + memcpy(pReport_data->touch_stylus_info, buf + JD_TOUCH_STYLUS_INFO_ADDR + 1, + sizeof(pReport_data->touch_stylus_info) - 1); + + /* Set buf offset */ + buf_offset += JD_TOUCH_STYLUS_SIZE; + } + /* Copy finger info. */ + memcpy(pReport_data->touch_coord_info, buf + buf_offset, + pjadard_host_data->finger_num * JD_FINGER_DATA_SIZE); + /* Copy touch state info. */ + buf_offset += pjadard_host_data->finger_num * JD_FINGER_DATA_SIZE; + memcpy(pReport_data->touch_state_info, buf + buf_offset, + sizeof(pReport_data->touch_state_info)); + #ifdef JD_SANSUMG_PALM_EN + buf_offset += JD_TOUCH_STATE_ALL_SIZE; + memcpy(pReport_data->touch_palm_info, buf + buf_offset, + pjadard_host_data->finger_num * JD_PALM_DATA_SIZE); + #endif +#else + /* Set finger number & Coordinate Info. */ + pjadard_host_data->finger_num = buf[JD_FINGER_NUM_ADDR]; + #ifdef JD_REPORT_FRAME_CHECK + pjadard_host_data->finger_frame = buf[JD_FINGER_FRAME_ADDR]; + #endif + memcpy(pReport_data->touch_coord_info, buf + JD_TOUCH_COORD_INFO_ADDR, + pReport_data->touch_coord_size); + #ifdef JD_SANSUMG_PALM_EN + memcpy(pReport_data->touch_palm_info, buf + JD_TOUCH_PALM_INFO_ADDR, + pReport_data->touch_palm_size); + #endif + /* Copy touch state info. */ + memcpy(pReport_data->touch_state_info, buf + JD_TOUCH_STATE_INFO_ADDR, + sizeof(pReport_data->touch_state_info)); + + /* Copy touch stylus info. */ + if (pjadard_ic_data->JD_STYLUS_EN) { + #ifdef JD_REPORT_FRAME_CHECK + pjadard_host_data->stylus.pen_frame = buf[JD_TOUCH_STYLUS_INFO_ADDR]; + #endif + memcpy(pReport_data->touch_stylus_info, buf + JD_TOUCH_STYLUS_INFO_ADDR + 1, + sizeof(pReport_data->touch_stylus_info)); + } +#endif + break; +#if defined(JD_SMART_WAKEUP) + case JD_REPORT_SMWP_EVENT: + pReport_data->touch_event_info = buf[JD_TOUCH_EVENT_INFO_ADDR]; + break; +#endif + default: + JD_E("%s: Not support event(%d)\n", __func__, irq_event); + ts_status = JD_IRQ_EVENT_FAIL; + break; + } + + JD_D("%s: End, ts_status=%d\n", __func__, ts_status); + + return ts_status; +} + +void jadard_log_touch_state(const char **bit_map) +{ + JD_I("Touch state1 = %s %s\n", bit_map[pjadard_report_data->touch_state_info[0] >> 4], + bit_map[pjadard_report_data->touch_state_info[0] & 0x0F]); + JD_I("Touch state2 = %s %s\n", bit_map[pjadard_report_data->touch_state_info[1] >> 4], + bit_map[pjadard_report_data->touch_state_info[1] & 0x0F]); + JD_I("Touch state3 = %s %s\n", bit_map[pjadard_report_data->touch_state_info[2] >> 4], + bit_map[pjadard_report_data->touch_state_info[2] & 0x0F]); + JD_I("Touch state4 = %s %s\n", bit_map[pjadard_report_data->touch_state_info[3] >> 4], + bit_map[pjadard_report_data->touch_state_info[3] & 0x0F]); + JD_I("Touch application = %s %s\n", bit_map[pjadard_report_data->touch_state_info[4] >> 4], + bit_map[pjadard_report_data->touch_state_info[4] & 0x0F]); +} + +#ifndef CONFIG_JD_HID +static int jadard_err_ctrl(uint8_t *buf, int buf_len, int ts_status) +{ + int i; +#ifdef JD_REPORT_CHECKSUM + uint16_t checksum = 0; +#endif + + if (pjadard_ts_data->rst_active) { + /* drop 1st interrupts after chip reset */ + pjadard_ts_data->rst_active = false; + JD_I("[rst_active]:%s: Back from reset, ready to serve.\n", __func__); + ts_status = JD_RST_OK; + goto GOTO_END; + } + + for (i = 0; i < buf_len; i++) { + if (buf[i] == 0x00) { + if (i == buf_len - 1) { + ts_status = JD_TS_UNUSUAL_DATA_FAIL; + JD_D("Bypass all zero\n"); + goto GOTO_END; + } + } else { + break; + } + } + + for (i = 0; i < buf_len; i++) { + if (buf[i] == 0xFF) { + if (i == buf_len - 1) { + ts_status = JD_TS_UNUSUAL_DATA_FAIL; + JD_D("Bypass all 0xFF\n"); + goto GOTO_END; + } + } else { + break; + } + } + +#ifdef JD_REPORT_CHECKSUM +#ifndef JD_REPORT_FORMAT_V2 + if (buf_len >= 59) { + for (i = 0; i < 59; i++) { + checksum += buf[i]; + } + + if ((checksum & 0x00FF) != 0) { + JD_E("checksum fail: 0x%04x\n", checksum); + ts_status = JD_TS_CHECKSUM_FAIL; + } + } +#endif +#endif + +GOTO_END: + JD_D("%s: end, ts_status=%d\n", __func__, ts_status); + + return ts_status; +} + +static int jadard_touch_get(uint8_t *buf, int buf_len, int ts_status) +{ + JD_D("%s: Entering, ts_status=%d\n", __func__, ts_status); + + if (!g_module_fp.fp_get_touch_data(buf, buf_len)) { + JD_E("%s: can't read data from chip!\n", __func__); + ts_status = JD_TS_GET_DATA_FAIL; + } + + return ts_status; +} +#endif + +static int jadard_touch_raw_get(uint8_t *buf, int buf_len, int ts_status) +{ + uint32_t index = 0; + int i, j, new_data, ReCode; + uint8_t *rdata = NULL; + int x_num = pjadard_ic_data->JD_X_NUM; + int y_num = pjadard_ic_data->JD_Y_NUM; + uint16_t rdata_size = x_num * y_num * sizeof(uint16_t) + JD_TOUCH_MAX_DATA_SIZE; + + JD_D("%s: Entering, ts_status=%d\n", __func__, ts_status); + + rdata = kzalloc(rdata_size * sizeof(uint8_t), GFP_KERNEL); + if (rdata == NULL) { + JD_E("%s, rdata memory allocate fail: %d\n", __func__, __LINE__); + return JD_TS_GET_DATA_FAIL; + } + + ReCode = g_module_fp.fp_read_mutual_data(rdata, rdata_size); + if (ReCode < 0) { + for (i = 0; i < x_num * y_num; i++) { + jd_diag_mutual[i] = -23131; + } + kfree(rdata); + jd_diag_mutual_cnt++; + return JD_TS_GET_DATA_FAIL; + } else { + if (ReCode == JD_REPORT_DATA) { /* output_buf addr > coordinate_report addr */ + memcpy(buf, rdata, buf_len); + index += JD_TOUCH_MAX_DATA_SIZE; + } else { /* ReCode == 0 */ + if (!g_module_fp.fp_get_touch_data(buf, buf_len)) { + JD_E("%s: can't read data from chip!\n", __func__); + kfree(rdata); + return JD_TS_GET_DATA_FAIL; + } + } + } + + for (i = 0; i < y_num; i++) { + for (j = 0; j < x_num; j++) { + + if (DataType == JD_DATA_TYPE_Difference || DataType == JD_DATA_TYPE_LAPLACE) { + if (pjadard_ts_data->rawdata_little_endian) { + new_data = (((int8_t)rdata[index + 1] << 8) | rdata[index]); + } else { + new_data = (((int8_t)rdata[index] << 8) | rdata[index + 1]); + } + } else { + if (pjadard_ts_data->rawdata_little_endian) { + new_data = (((uint8_t)rdata[index + 1] << 8) | rdata[index]); + } else { + new_data = (((uint8_t)rdata[index] << 8) | rdata[index + 1]); + } + } + jd_diag_mutual[i * x_num + j] = new_data; + + index += 2; + } + } + kfree(rdata); + jd_diag_mutual_cnt++; + + return ts_status; +} + +static int jadard_ts_operation(struct jadard_ts_data *ts, int irq_event, int ts_status) +{ + int touch_data_len = JD_TOUCH_DATA_SIZE; + uint8_t touch_data[JD_TOUCH_DATA_SIZE]; +#if defined(JD_REPORT_FORMAT_V2) + int i; + uint16_t finger_tmp; +#endif + + JD_D("%s: Entering, ts_status=%d, irq_event=%d\n", __func__, ts_status, irq_event); + memset(touch_data, 0x00, sizeof(touch_data)); + +#if defined(JD_REPORT_FORMAT_V2) + if (!pjadard_ic_data->JD_STYLUS_EN) { + touch_data_len -= JD_TOUCH_STYLUS_SIZE; + } +#else +#ifndef JD_SANSUMG_PALM_EN + if (!pjadard_ic_data->JD_STYLUS_EN) { + touch_data_len -= JD_TOUCH_STYLUS_SIZE; + } +#endif +#endif + + if (pjadard_ts_data->debug_diag_apk_enable == true) { + ts_status = jadard_touch_raw_get(touch_data, touch_data_len, ts_status); + } else { +#ifndef CONFIG_JD_HID +#if defined(JD_REPORT_FORMAT_V2) + /* Read second part report data */ + #ifndef JD_SANSUMG_PALM_EN + touch_data_len -= 5; + #endif + ts_status = jadard_touch_get(touch_data, touch_data_len, ts_status); + + /* Check finger report */ + pjadard_host_data->finger_num = 0; + finger_tmp = (uint16_t)((touch_data[1] << 8) + touch_data[0]); + for (i = 0; i < pjadard_ic_data->JD_MAX_PT; finger_tmp >>= 1, i++) { + if ((finger_tmp & 0x0001) == 0x0001) { + pjadard_host_data->id[i] |= 0x10; + pjadard_host_data->finger_num++; + } + } +#else + ts_status = jadard_touch_get(touch_data, touch_data_len, ts_status); +#endif +#else + memcpy(touch_data, hid_touch_data, touch_data_len); +#endif + } + + if (ts_status == JD_TS_GET_DATA_FAIL) + return ts_status; + + /* Copy FW package for APK */ +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (pjadard_ts_data->debug_fw_package_enable == true) { + if (touch_data_len + 4 <= JD_HID_TOUCH_DATA_SIZE) { + pjadard_report_data->report_rate_count &= 0xFFFF; + pjadard_report_data->touch_all_info[1] = (uint8_t)(pjadard_report_data->report_rate_count >> 8); + pjadard_report_data->touch_all_info[2] = (uint8_t)(pjadard_report_data->report_rate_count); + memcpy((pjadard_report_data->touch_all_info) + 4, touch_data, touch_data_len); + pjadard_report_data->report_rate_count++; + } else { + JD_E("%s: pjadard_report_data->touch_all_info was overflow\n", __func__); + } + } +#endif + +#ifndef CONFIG_JD_HID + ts_status = jadard_err_ctrl(touch_data, touch_data_len, ts_status); +#endif + + if ((ts_status == JD_REPORT_DATA) || (ts_status == JD_TS_NORMAL_START)) { + ts_status = g_module_fp.fp_distribute_touch_data(ts, touch_data, irq_event, ts_status); + ts_status = g_module_fp.fp_parse_report_data(ts, irq_event, ts_status); + } else { + return ts_status; + } + + return jadard_report_data(ts, irq_event, ts_status); +} + +#if defined(JD_USB_DETECT_GLOBAL) +void jadard_cable_detect(bool renew) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + uint32_t connect_status = jd_usb_detect_flag; + + if (ts->usb_status) { + if (((!!connect_status) != ts->usb_connected) || renew) { + if (!!connect_status) { + ts->usb_status[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->usb_status[1] = 0x00; + ts->usb_connected = 0x00; + } + + g_module_fp.fp_usb_detect_set(ts->usb_status); + JD_I("%s: Cable status change: 0x%2.2X\n", __func__, ts->usb_connected); + } + } +} +#endif + +void jadard_ts_work(struct jadard_ts_data *ts) +{ + int ts_status = JD_TS_NORMAL_START; + int irq_event = JD_REPORT_COORD; + + if (pjadard_debug != NULL) + pjadard_debug->fp_touch_dbg_func(ts, JD_ATTN_IN); + +#if defined(JD_USB_DETECT_GLOBAL) + /* Update usb status when power on */ + if (ts->update_usb_status < 3) { + jadard_cable_detect(true); + ts->update_usb_status++; + } else { + jadard_cable_detect(false); + } +#endif +#ifdef JD_SMART_WAKEUP + if (atomic_read(&ts->suspend_mode) && (ts->SMWP_enable)) { + irq_event = JD_REPORT_SMWP_EVENT; + __pm_wakeup_event(ts->ts_SMWP_wake_lock, JD_TS_WAKE_LOCK_TIMEOUT); + } +#endif + + switch (irq_event) { + case JD_REPORT_COORD: + ts_status = jadard_ts_operation(ts, irq_event, ts_status); + break; + case JD_REPORT_SMWP_EVENT: + ts_status = jadard_ts_operation(ts, irq_event, ts_status); + break; + default: + JD_E("%s: Not support event(%d)\n", __func__, irq_event); + ts_status = JD_IRQ_EVENT_FAIL; + break; + } + +#ifdef JD_RST_PIN_FUNC + if (ts_status == JD_TS_GET_DATA_FAIL) { + JD_I("%s: Now reset the Touch chip.\n", __func__); + g_module_fp.fp_ic_reset(false, true); + } +#endif + + if (pjadard_debug != NULL) + pjadard_debug->fp_touch_dbg_func(ts, JD_ATTN_OUT); +} + +#if defined(JD_USB_DETECT_CALLBACK) +/* +* Get usb or charging status at "/sys/class/power_supply/XXX/uevent" +* XXX: Computer type: usb/pc_port +* Adapter type: ac/dc/battery +*/ + +const char *jd_psy_name[2] = { + "usb", /* Computer type */ + "ac" /* Adapter type */ +}; + +void jadard_usb_status(int status, bool renew) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + if (ts->usb_status) { + if ((status != ts->usb_connected) || renew) { + if (status) { + ts->usb_status[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->usb_status[1] = 0x00; + ts->usb_connected = 0x00; + } + + g_module_fp.fp_usb_detect_set(ts->usb_status); + JD_I("%s: Cable status update: 0x%2.2X\n", __func__, ts->usb_connected); + } + } +} + +static int jadard_charger_notifier_callback(struct notifier_block *nb, + unsigned long val, void *v) +{ + int ret = 0; + struct power_supply *psy_usb = NULL; + struct power_supply *psy_ac = NULL; + union power_supply_propval prop_usb; + union power_supply_propval prop_ac; + + psy_usb = power_supply_get_by_name(jd_psy_name[0]); + if (!psy_usb) { + JD_E("Couldn't get %s psy\n", jd_psy_name[0]); + return -EINVAL; + } + + psy_ac = power_supply_get_by_name(jd_psy_name[1]); + if (!psy_ac) { + JD_E("Couldn't get %s psy\n", jd_psy_name[1]); + return -EINVAL; + } + + if (!strcmp(psy_usb->desc->name, jd_psy_name[0])) { + if (psy_usb && val == POWER_SUPPLY_PROP_STATUS) { + ret = power_supply_get_property(psy_usb, POWER_SUPPLY_PROP_ONLINE, &prop_usb); + if (ret < 0) { + JD_E("Couldn't get %s POWER_SUPPLY_PROP_ONLINE rc=%d\n", jd_psy_name[0], ret); + return ret; + } + } + } + + if (!strcmp(psy_ac->desc->name, jd_psy_name[1])) { + if (psy_ac && val == POWER_SUPPLY_PROP_STATUS) { + ret = power_supply_get_property(psy_ac, POWER_SUPPLY_PROP_ONLINE, &prop_ac); + if (ret < 0) { + JD_E("Couldn't get %s POWER_SUPPLY_PROP_ONLINE rc=%d\n", jd_psy_name[1], ret); + return ret; + } + } + } + + if (prop_usb.intval || prop_ac.intval) { + jadard_usb_status(1, false); + } else { + jadard_usb_status(0, false); + } + + return 0; +} + +static void jadard_charger_init(struct work_struct *work) +{ + int ret = 0; + struct power_supply *psy_usb = NULL; + struct power_supply *psy_ac = NULL; + union power_supply_propval prop_usb; + union power_supply_propval prop_ac; + + pjadard_ts_data->charger_notif.notifier_call = jadard_charger_notifier_callback; + ret = power_supply_reg_notifier(&pjadard_ts_data->charger_notif); + if (ret) { + JD_E("Unable to register charger_notifier: %d\n", ret); + } + + /* if power supply supplier registered brfore TP + * ps_notify_callback will not receive PSY_EVENT_PROP_ADDED + * event, and will cause miss to set TP into charger state. + * So check PS state in probe. + */ + psy_usb = power_supply_get_by_name(jd_psy_name[0]); + if (!psy_usb) { + JD_E("Get %s psy fail\n", jd_psy_name[0]); + } + + psy_ac = power_supply_get_by_name(jd_psy_name[1]); + if (!psy_ac) { + JD_E("Get %s psy fail\n", jd_psy_name[1]); + } + + if (psy_usb && psy_ac) { + if (!strcmp(psy_usb->desc->name, jd_psy_name[0])) { + ret = power_supply_get_property(psy_usb, POWER_SUPPLY_PROP_ONLINE, &prop_usb); + if (ret < 0) { + JD_E("Couldn't get %s POWER_SUPPLY_PROP_ONLINE rc=%d\n", jd_psy_name[0], ret); + } + } + + if (!strcmp(psy_ac->desc->name, jd_psy_name[1])) { + ret = power_supply_get_property(psy_ac, POWER_SUPPLY_PROP_ONLINE, &prop_ac); + if (ret < 0) { + JD_E("Couldn't get %s POWER_SUPPLY_PROP_ONLINE rc=%d\n", jd_psy_name[1], ret); + } + } + + if (prop_usb.intval || prop_ac.intval) { + jadard_usb_status(1, true); + } else { + jadard_usb_status(0, true); + } + } else { + JD_E("Please check system power_supply path\n"); + } +} +#endif + +#if defined(JD_AUTO_UPGRADE_FW) +static int jadard_upgrade_FW(void) +{ + bool result = false; + + jadard_int_enable(false); + + if (g_module_fp.fp_flash_write(0, g_jadard_fw, g_jadard_fw_len) < 0) { + JD_E("%s: TP upgrade fail\n", __func__); + } else { + JD_I("%s: TP upgrade success\n", __func__); + g_module_fp.fp_read_fw_ver(); + result = true; + } + +#ifndef JD_UPGRADE_FW_ARRAY + kfree(g_jadard_fw); +#endif + g_jadard_fw = NULL; + g_jadard_fw_len = 0; + + jadard_int_enable(true); + + return result; +} + +static bool jadard_auto_upgrade_check(void) +{ + bool upgrade = false; + + JD_D("%s:Entering\n", __func__); + + if (g_module_fp.fp_read_fw_ver_bin() == JD_NO_ERR) { + JD_I("pjadard_ic_data->fw_ver=%08x, g_jadard_fw_ver=%08x\n", + pjadard_ic_data->fw_ver, g_jadard_fw_ver); + JD_I("pjadard_ic_data->fw_cid_ver=%08x, g_jadard_fw_cid_ver=%08x\n", + pjadard_ic_data->fw_cid_ver, g_jadard_fw_cid_ver); + + if ((pjadard_ic_data->fw_ver < g_jadard_fw_ver) || + (pjadard_ic_data->fw_cid_ver < g_jadard_fw_cid_ver)) { + JD_I("Need to upgrade FW\n"); + upgrade = true; + } else { + JD_I("No need to upgrade FW\n"); + } + } + + return upgrade; +} + +static int jadard_get_FW(void) +{ + int ret = JD_NO_ERR; +#ifndef JD_UPGRADE_FW_ARRAY + int RetryCnt; + const struct firmware *fw = NULL; + + JD_I("file name = %s\n", jd_i_CTPM_firmware_name); + + for (RetryCnt = 0; RetryCnt < JD_UPGRADE_FW_RETRY_TIME; RetryCnt++) { + ret = request_firmware(&fw, jd_i_CTPM_firmware_name, pjadard_ts_data->dev); + if (ret < 0) { + JD_E("%s: Open file fail(ret:%d), RetryCnt = %d\n", __func__, ret, RetryCnt); + mdelay(1000); + } else { + break; + } + } + + if (RetryCnt == JD_UPGRADE_FW_RETRY_TIME) { + JD_E("%s: Open file fail retry over %d\n", __func__, JD_UPGRADE_FW_RETRY_TIME); + return JD_FILE_OPEN_FAIL; + } + + g_jadard_fw_len = fw->size; + g_jadard_fw = kzalloc(sizeof(char) * g_jadard_fw_len, GFP_KERNEL); + + if (g_jadard_fw == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + ret = JD_MEM_ALLOC_FAIL; + } else { + memcpy(g_jadard_fw, fw->data, sizeof(char) * g_jadard_fw_len); + } + release_firmware(fw); +#else + JD_I("file name = %s\n", jd_i_CTPM_firmware_name); + + g_jadard_fw_len = jd_fw_size; + g_jadard_fw = (uint8_t *)jd_i_firmware; +#endif + + return ret; +} + +static void jadard_upgrade_process(struct work_struct *work) +{ + JD_D("%s, Entering\n", __func__); + + if (jadard_get_FW() >= 0) { + if (jadard_auto_upgrade_check()) { + if (jadard_upgrade_FW() <= 0) { + JD_E("Auto upgrade fail\n"); + } else { + JD_I("Auto upgrade finish\n"); + } + } else { + #ifndef JD_UPGRADE_FW_ARRAY + kfree(g_jadard_fw); + #endif + g_jadard_fw = NULL; + g_jadard_fw_len = 0; + } + } +} +#endif + +#if defined(JD_CONFIG_NODE) +static ssize_t ts_suspend_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + return scnprintf(buf, 20, "ts->suspended = %d\n", ts->suspended); +} + +static ssize_t ts_suspend_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + if (buf[0] == '1') { + jadard_chip_common_suspend(ts); + } else if (buf[0] == '0') { + jadard_chip_common_resume(ts); + } + + JD_I("%s: ts->suspended = %d\n", __func__, ts->suspended); + + return count; +} + +static DEVICE_ATTR_RW(ts_suspend); + +static struct attribute *jadard_ts_debug_attrs[] = { + &dev_attr_ts_suspend.attr, + NULL, +}; + +static struct attribute_group jadard_ts_debug_attr_group = { + .attrs = jadard_ts_debug_attrs, +}; + +static int jadard_ts_filesys_create(struct jadard_ts_data *ts) +{ + int retval; + + /* create sysfs debug files */ + retval = sysfs_create_group(&ts->dev->kobj, + &jadard_ts_debug_attr_group); + if (retval < 0) { + JD_E("%s: Fail to create debug files!\n", __func__); + return -ENOMEM; + } + + /* convenient access to sysfs node */ + retval = sysfs_create_link(NULL, &ts->dev->kobj, "touchscreen"); + if (retval < 0) { + JD_E("%s: Failed to create link!\n", __func__); + return -ENOMEM; + } + + return JD_NO_ERR; +} + +static void jadard_ts_filesys_remove(struct jadard_ts_data *ts) +{ + sysfs_remove_link(NULL, "touchscreen"); + sysfs_remove_group(&ts->dev->kobj, &jadard_ts_debug_attr_group); +} +#endif + +#ifdef JD_SMART_WAKEUP +static ssize_t jadard_SMWP_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 128) { + JD_E("%s: len size less than 128\n", __func__); + return -ENOMEM; + } + + if (!proc_smwp_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "SMWP_enable = %d\n", ts->SMWP_enable); + + if (copy_to_user(buf, buf_tmp, len)) + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + proc_smwp_send_flag = true; + } else { + proc_smwp_send_flag = false; + } + + return ret; +} + +static ssize_t jadard_SMWP_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + if (buf_tmp[0] == '1') + ts->SMWP_enable = true; + else + ts->SMWP_enable = false; + + g_module_fp.fp_set_SMWP_enable(ts->SMWP_enable); + JD_I("%s: SMART_WAKEUP_enable = %d.\n", __func__, ts->SMWP_enable); + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_SMWP_ops = { + .proc_read = jadard_SMWP_read, + .proc_write = jadard_SMWP_write, +}; +#else +static struct file_operations jadard_proc_SMWP_ops = { + .owner = THIS_MODULE, + .read = jadard_SMWP_read, + .write = jadard_SMWP_write, +}; +#endif + +static ssize_t jadard_GESTURE_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + size_t ret = 0; + char *buf_tmp = NULL; + int i; + + if (len < 512) { + JD_E("%s: len size less than 512\n", __func__); + return -ENOMEM; + } + + if (!proc_smwp_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + + if (buf_tmp != NULL) { + for (i = 0; i < JD_GEST_SUP_NUM; i++) + ret += scnprintf(buf_tmp + ret, len - ret, "ges_en[%d] = %d\n", + i, ts->gesture_cust_en[i]); + + if (copy_to_user(buf, buf_tmp, len)) + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + proc_smwp_send_flag = true; + } else { + proc_smwp_send_flag = false; + } + + return ret; +} + +static ssize_t jadard_GESTURE_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[JD_GEST_SUP_NUM + 1] = {0}; + int i; + + if (len > sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + JD_I("jadard_GESTURE_CMD = %s\n", buf_tmp); + + for (i = 0; i < len - 1 && i < JD_GEST_SUP_NUM; i++) { + if (buf_tmp[i] == '1') { + ts->gesture_cust_en[i] = true; + } else { + ts->gesture_cust_en[i] = false; + } + JD_I("gesture_cust_en[%d] = %d\n", i, ts->gesture_cust_en[i]); + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_Gesture_ops = { + .proc_read = jadard_GESTURE_read, + .proc_write = jadard_GESTURE_write, +}; +#else +static struct file_operations jadard_proc_Gesture_ops = { + .owner = THIS_MODULE, + .read = jadard_GESTURE_read, + .write = jadard_GESTURE_write, +}; +#endif + +#ifdef JD_SYS_CLASS_SMWP_EN +/* + * Create /sys/class/gesture/jd_SMWP/SMWP + * Create /sys/class/gesture/jd_GESTURE/GESTURE +*/ +struct class *jd_gesture_class; +struct device *jd_SMWP_dev; +struct device *jd_GESTURE_dev; + +static ssize_t jd_SMWP_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, 64, "%s: ts->SMWP_enable = %d\n", __func__, pjadard_ts_data->SMWP_enable); +} + +static ssize_t jd_SMWP_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + if (buf[0] == '1') { + ts->SMWP_enable = 1; + } else { + ts->SMWP_enable = 0; + } + + g_module_fp.fp_set_SMWP_enable(ts->SMWP_enable); + JD_I("%s: SMART_WAKEUP_enable = %d\n", __func__, ts->SMWP_enable); + + return size; +} + +static struct device_attribute jd_SMWP_attr = { + .attr = { + .name = "SMWP", + .mode = S_IRUSR | S_IWUSR, + }, + .show = jd_SMWP_show, + .store = jd_SMWP_store, +}; + +static ssize_t jd_GESTURE_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[JD_GEST_SUP_NUM + 1] = {0}; + int i; + + for (i = 0; i < JD_GEST_SUP_NUM; i++) { + if (ts->gesture_cust_en[i] == 1) { + buf_tmp[i] = '1'; + } else { + buf_tmp[i] = '0'; + } + } + + return scnprintf(buf, 64, "gesture_en = %s\n", buf_tmp); +} + +static ssize_t jd_GESTURE_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + int i; + + for (i = 0; i < size - 1 && i < JD_GEST_SUP_NUM; i++) { + if (buf[i] == '1') { + ts->gesture_cust_en[i] = 1; + } else { + ts->gesture_cust_en[i] = 0; + } + JD_I("gesture_cust_en[%d] = %d\n", i, ts->gesture_cust_en[i]); + } + + return size; +} + +static struct device_attribute jd_GESTURE_attr = { + .attr = { + .name = "GESTURE", + .mode = S_IRUSR | S_IWUSR, + }, + .show = jd_GESTURE_show, + .store = jd_GESTURE_store, +}; + +static void jd_gesture_node_init(void) +{ + jd_gesture_class = class_create(THIS_MODULE, "gesture"); + if (IS_ERR(jd_gesture_class)) { + JD_E("Failed to create class (gesture)!\n"); + } + + jd_SMWP_dev = device_create(jd_gesture_class, NULL, 0, NULL, "jd_SMWP"); + if (IS_ERR(jd_SMWP_dev)) { + JD_E("Failed to create device (jd_SMWP_dev)!\n"); + } + + if (device_create_file(jd_SMWP_dev, &jd_SMWP_attr) < 0) + JD_E("Failed to create device file (%s)!\n", jd_SMWP_attr.attr.name); + + jd_GESTURE_dev = device_create(jd_gesture_class, NULL, 0, NULL, "jd_GESTURE"); + if (IS_ERR(jd_GESTURE_dev)) { + JD_E("Failed to create device (jd_GESTURE_dev)!\n"); + } + + if (device_create_file(jd_GESTURE_dev, &jd_GESTURE_attr) < 0) + JD_E("Failed to create device file (%s)!\n", jd_GESTURE_attr.attr.name); +} + +static void jd_gesture_node_remove(void) +{ + if (jd_SMWP_dev) { + device_remove_file(jd_SMWP_dev, &jd_SMWP_attr); + jd_SMWP_dev = NULL; + } + + if (jd_GESTURE_dev) { + device_remove_file(jd_GESTURE_dev, &jd_GESTURE_attr); + jd_GESTURE_dev = NULL; + } + + if (jd_gesture_class) { + device_destroy(jd_gesture_class, 0); + class_destroy(jd_gesture_class); + jd_gesture_class = NULL; + } +} +#endif +#endif + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING +static ssize_t jadard_sorting_test_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 512) { + JD_E("%s: len size less than 512\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + + if (buf_tmp != NULL) { + g_module_fp.fp_sorting_test(buf_tmp, len); + ret = strlen(buf_tmp); + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_sorting_test_ops = { + .proc_read = jadard_sorting_test_read, +}; + +#if defined(JD_OPPO_FUNC) +static struct proc_ops jadard_proc_baseline_test_ops = { + .proc_read = jadard_sorting_test_read, +}; + + +static struct proc_ops jadard_proc_black_test_ops = { + .proc_read = jadard_sorting_test_read, +}; +#endif +#else +static struct file_operations jadard_proc_sorting_test_ops = { + .owner = THIS_MODULE, + .read = jadard_sorting_test_read, +}; + +#if defined(JD_OPPO_FUNC) +static struct file_operations jadard_proc_baseline_test_ops = { + .owner = THIS_MODULE, + .read = jadard_sorting_test_read, +}; + + +static struct file_operations jadard_proc_black_test_ops = { + .owner = THIS_MODULE, + .read = jadard_sorting_test_read, +}; +#endif +#endif + +extern void jadard_sorting_init(void); +#endif + +#ifdef JD_HIGH_SENSITIVITY +static ssize_t jadard_high_sensitivity_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 128) { + JD_E("%s: len size less than 128\n", __func__); + return -ENOMEM; + } + + if (!proc_Hsens_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "High_sensitivity_enable = %d\n", ts->high_sensitivity_enable); + if (copy_to_user(buf, buf_tmp, len)) + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + proc_Hsens_send_flag = true; + } else { + proc_Hsens_send_flag = false; + } + + return ret; +} + +static ssize_t jadard_high_sensitivity_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + if (buf_tmp[0] == '1') { + ts->high_sensitivity_enable = true; + } else { + ts->high_sensitivity_enable = false; + } + + g_module_fp.fp_set_high_sensitivity(ts->high_sensitivity_enable); + JD_I("%s: High_sensitivity_enable = %d.\n", __func__, ts->high_sensitivity_enable); + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_high_sensitivity_ops = { + .proc_read = jadard_high_sensitivity_read, + .proc_write = jadard_high_sensitivity_write, +}; +#else +static struct file_operations jadard_proc_high_sensitivity_ops = { + .owner = THIS_MODULE, + .read = jadard_high_sensitivity_read, + .write = jadard_high_sensitivity_write, +}; +#endif +#endif + +#ifdef JD_ROTATE_BORDER +static ssize_t jadard_rotate_border_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 128) { + JD_E("%s: len size less than 128\n", __func__); + return -ENOMEM; + } + + if (!proc_rotate_border_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "rotate_border = %d (0x%04x)\n", ts->rotate_switch_mode, ts->rotate_border); + if (copy_to_user(buf, buf_tmp, len)) + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + proc_rotate_border_flag = true; + } else { + proc_rotate_border_flag = false; + } + + return ret; +} + +static ssize_t jadard_rotate_border_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[10] = {0}; + int RotateType; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + RotateType = buf_tmp[0] - '0'; + if ((RotateType < 1) || (RotateType > 3)) { + JD_E("%s: RotateType must (1,2,3)\n", __func__); + return -EINVAL; + } + + ts->rotate_switch_mode = RotateType; + switch (RotateType) { + case 1: /* Vertical */ + ts->rotate_border = 0xA55A; + break; + case 2: /* Horizontal notch left side */ + ts->rotate_border = 0xA11A; + break; + case 3: /* horizontal notch right side */ + ts->rotate_border = 0xA33A; + break; + } + + g_module_fp.fp_set_rotate_border(ts->rotate_border); + JD_I("%s: rotate_border = 0x%04x\n", __func__, ts->rotate_border); + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_rotate_border_ops = { + .proc_read = jadard_rotate_border_read, + .proc_write = jadard_rotate_border_write, +}; +#else +static struct file_operations jadard_proc_rotate_border_ops = { + .owner = THIS_MODULE, + .read = jadard_rotate_border_read, + .write = jadard_rotate_border_write, +}; +#endif +#endif + +#ifdef JD_EARPHONE_DETECT +static ssize_t jadard_earphone_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 128) { + JD_E("%s: len size less than 128\n", __func__); + return -ENOMEM; + } + + if (!proc_earphone_detect_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "Earphone_enable = %04x\n", ts->earphone_enable); + if (copy_to_user(buf, buf_tmp, len)) + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + proc_earphone_detect_flag = true; + } else { + proc_earphone_detect_flag = false; + } + + return ret; +} + +/* + * 1: 3.5mm earphone removed + * 2: 3.5mm earphone detected + * 3: type-c_earphone removed + * 4: type-c_earphone detected + * + * Example: 3.5mm earphone detected + * echo 2 > /proc/jadard_touch/EARPHONE + */ +static ssize_t jadard_earphone_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[10] = {0}; + uint8_t state; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + if (buf_tmp[0] >= '1' && buf_tmp[0] <= '4') { + state = (buf_tmp[0] - '0'); + JD_I("%s: Earphone state = %d\n", __func__, state); + g_module_fp.fp_set_earphone_enable(state); + } else { + JD_E("%s: Not support command!\n", __func__); + return -EINVAL; + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_earphone_ops = { + .proc_read = jadard_earphone_read, + .proc_write = jadard_earphone_write, +}; +#else +static struct file_operations jadard_proc_earphone_ops = { + .owner = THIS_MODULE, + .read = jadard_earphone_read, + .write = jadard_earphone_write, +}; +#endif +#endif + +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_DISABLE) +static ssize_t jadard_proximity_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 128) { + JD_E("%s: len size less than 128\n", __func__); + return -ENOMEM; + } + + if (!proc_proximity_detect_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "Proximity_enable = %d\n", ts->proximity_enable); + if (copy_to_user(buf, buf_tmp, len)) + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + proc_proximity_detect_flag = true; + } else { + proc_proximity_detect_flag = false; + } + + return ret; +} + +static ssize_t jadard_proximity_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + if (buf_tmp[0] == '1') { + ts->proximity_enable = 1; + } else { + ts->proximity_enable = 0; + } + + g_module_fp.fp_set_virtual_proximity(ts->proximity_enable); + JD_I("%s: Proximity_enable = %d.\n", __func__, ts->proximity_enable); + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_proximity_ops = { + .proc_read = jadard_proximity_read, + .proc_write = jadard_proximity_write, +}; +#else +static struct file_operations jadard_proc_proximity_ops = { + .owner = THIS_MODULE, + .read = jadard_proximity_read, + .write = jadard_proximity_write, +}; +#endif + +#ifdef JD_SYS_CLASS_PSENSOR_EN +/* + * Create /sys/class/sensor/jd_psensor/jd_proximity +*/ +struct class *jd_proximity_class; +struct device *jd_proximity_dev; + +static ssize_t jd_proximity_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, 64, "%s: ts->proximity_enable = %d\n", __func__, pjadard_ts_data->proximity_enable); +} + +static ssize_t jd_proximity_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + if (buf[0] == '1') { + ts->proximity_enable = 1; + } else { + ts->proximity_enable = 0; + } + + g_module_fp.fp_set_virtual_proximity(ts->proximity_enable); + JD_I("%s: Proximity_enable = %d\n", __func__, ts->proximity_enable); + + return size; +} + +static struct device_attribute jd_proximity_attr = { + .attr = { + .name = "jd_proximity", + .mode = S_IRUSR | S_IWUSR, + }, + .show = jd_proximity_show, + .store = jd_proximity_store, +}; + +static void jd_proximity_node_init(void) +{ + jd_proximity_class = class_create(THIS_MODULE, "sensor"); + if (IS_ERR(jd_proximity_class)) { + JD_E("Failed to create class (sensor)!\n"); + } + + jd_proximity_dev = device_create(jd_proximity_class, NULL, 0, NULL, "jd_psensor"); + if (IS_ERR(jd_proximity_dev)) { + JD_E("Failed to create device (jd_proximity_dev)!\n"); + } + + if (device_create_file(jd_proximity_dev, &jd_proximity_attr) < 0) + JD_E("Failed to create device file (%s)!\n", jd_proximity_attr.attr.name); +} + +static void jd_proximity_node_remove(void) +{ + if (jd_proximity_dev) { + device_remove_file(jd_proximity_dev, &jd_proximity_attr); + jd_proximity_dev = NULL; + } + + if (jd_proximity_class) { + device_destroy(jd_proximity_class, 0); + class_destroy(jd_proximity_class); + jd_proximity_class = NULL; + } +} +#endif +#endif + +int jadard_common_proc_init(void) +{ + pjadard_touch_proc_dir = proc_mkdir(JADARD_PROC_TOUCH_FOLDER, NULL); + if (pjadard_touch_proc_dir == NULL) { + JD_E(" %s: pjadard_touch_proc_dir file create failed!\n", __func__); + goto fail; + } + +#if defined(JD_OPPO_FUNC) + pjadard_touchpanel_proc_dir = proc_mkdir(JADARD_PROC_TOUCHPANLE_FOLDER, NULL); + if (pjadard_touchpanel_proc_dir == NULL) { + JD_E(" %s: pjadard_touchpanel_proc_dir file create failed!\n", __func__); + goto fail; + } +#endif + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + jadard_sorting_init(); + + jadard_proc_sorting_test_file = proc_create(JADARD_PROC_SORTING_TEST_FILE, (S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_sorting_test_ops); + if (jadard_proc_sorting_test_file == NULL) { + JD_E(" %s: proc self_test file create failed!\n", __func__); + goto fail; + } +#if defined(JD_OPPO_FUNC) + pjadard_baseline_test_file = proc_create(JADARD_PROC_BASELINE_TEST_FILE, (S_IRUGO), + pjadard_touchpanel_proc_dir, &jadard_proc_baseline_test_ops); + if (pjadard_baseline_test_file == NULL) { + JD_E(" %s: proc self_test file create failed!\n", __func__); + goto fail; + } + + pjadard_blackscreen_baseline_file = proc_create(JADARD_PROC_BLACK_SCREEN_TEST_FILE, (S_IRUGO), + pjadard_touchpanel_proc_dir, &jadard_proc_black_test_ops); + if (pjadard_blackscreen_baseline_file == NULL) { + JD_E(" %s: proc black_test file create failed!\n", __func__); + goto fail; + } +#endif +#endif + +#ifdef JD_SMART_WAKEUP + jadard_proc_SMWP_file = proc_create(JADARD_PROC_SMWP_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_SMWP_ops); + if (jadard_proc_SMWP_file == NULL) { + JD_E(" %s: proc SMWP file create failed!\n", __func__); + goto fail; + } + + jadard_proc_GESTURE_file = proc_create(JADARD_PROC_GESTURE_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_Gesture_ops); + if (jadard_proc_GESTURE_file == NULL) { + JD_E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail; + } +#endif + +#ifdef JD_HIGH_SENSITIVITY + jadard_proc_high_sensitivity_file = proc_create(JADARD_PROC_HIGH_SENSITIVITY_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_high_sensitivity_ops); + if (jadard_proc_high_sensitivity_file == NULL) { + JD_E(" %s: proc high sensitivity file create failed!\n", __func__); + goto fail; + } +#endif + +#ifdef JD_ROTATE_BORDER + jadard_proc_rotate_border_file = proc_create(JADARD_PROC_ROTATE_BORDER_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_rotate_border_ops); + if (jadard_proc_rotate_border_file == NULL) { + JD_E(" %s: proc rotate border file create failed!\n", __func__); + goto fail; + } +#endif + +#ifdef JD_EARPHONE_DETECT + jadard_proc_earphone_file = proc_create(JADARD_PROC_EARPHONE_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_earphone_ops); + if (jadard_proc_earphone_file == NULL) { + JD_E(" %s: proc earphone file create failed!\n", __func__); + goto fail; + } +#endif + +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_DISABLE) + jadard_proc_proximity_file = proc_create(JADARD_PROC_PROXIMITY_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_proximity_ops); + if (jadard_proc_proximity_file == NULL) { + JD_E(" %s: proc proximity file create failed!\n", __func__); + goto fail; + } +#endif + + return JD_NO_ERR; + +fail: + jadard_common_proc_deinit(); + + return -ENOMEM; +} + +void jadard_common_proc_deinit(void) +{ +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_DISABLE) + if (jadard_proc_proximity_file) { + remove_proc_entry(JADARD_PROC_PROXIMITY_FILE, pjadard_touch_proc_dir); + jadard_proc_proximity_file = NULL; + } +#endif + +#ifdef JD_EARPHONE_DETECT + if (jadard_proc_earphone_file) { + remove_proc_entry(JADARD_PROC_EARPHONE_FILE, pjadard_touch_proc_dir); + jadard_proc_earphone_file = NULL; + } +#endif + +#ifdef JD_ROTATE_BORDER + if (jadard_proc_rotate_border_file) { + remove_proc_entry(JADARD_PROC_ROTATE_BORDER_FILE, pjadard_touch_proc_dir); + jadard_proc_rotate_border_file = NULL; + } + +#endif + +#ifdef JD_HIGH_SENSITIVITY + if (jadard_proc_high_sensitivity_file) { + remove_proc_entry(JADARD_PROC_HIGH_SENSITIVITY_FILE, pjadard_touch_proc_dir); + jadard_proc_high_sensitivity_file = NULL; + } +#endif + +#ifdef JD_SMART_WAKEUP + if (jadard_proc_GESTURE_file) { + remove_proc_entry(JADARD_PROC_GESTURE_FILE, pjadard_touch_proc_dir); + jadard_proc_GESTURE_file = NULL; + } + + if (jadard_proc_SMWP_file) { + remove_proc_entry(JADARD_PROC_SMWP_FILE, pjadard_touch_proc_dir); + jadard_proc_SMWP_file = NULL; + } +#endif + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING +#if defined(JD_OPPO_FUNC) + if (pjadard_blackscreen_baseline_file) { + remove_proc_entry(JADARD_PROC_BLACK_SCREEN_TEST_FILE, pjadard_touchpanel_proc_dir); + pjadard_blackscreen_baseline_file = NULL; + } + + if (pjadard_baseline_test_file) { + remove_proc_entry(JADARD_PROC_BASELINE_TEST_FILE, pjadard_touchpanel_proc_dir); + pjadard_baseline_test_file =NULL; + } + + if (pjadard_touchpanel_proc_dir) { + remove_proc_entry(JADARD_PROC_TOUCHPANLE_FOLDER, NULL); + pjadard_touchpanel_proc_dir = NULL; + } +#endif + if (jadard_proc_sorting_test_file) { + remove_proc_entry(JADARD_PROC_SORTING_TEST_FILE, pjadard_touch_proc_dir); + jadard_proc_sorting_test_file = NULL; + } +#endif + + if (pjadard_touch_proc_dir) { + remove_proc_entry(JADARD_PROC_TOUCH_FOLDER, NULL); + pjadard_touch_proc_dir = NULL; + } +} + +int jadard_input_register(struct jadard_ts_data *ts) +{ + int ret = 0; +#if defined(JD_SMART_WAKEUP) + int i; +#endif + + ret = jadard_dev_set(ts); + if (ret < 0) { + JD_E("%s, input device set fail!\n", __func__); + return JD_INPUT_REG_FAIL; + } + + 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(BTN_TOUCH, ts->input_dev->keybit); + set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit); + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); +#ifdef JD_PALM_EN + set_bit(JD_BTN_PALM, ts->input_dev->keybit); +#endif + +#if defined(JD_SMART_WAKEUP) + for (i = 0; i < JD_GEST_SUP_NUM; i++) { + set_bit(jd_gest_key_def[i], ts->input_dev->keybit); + } +#endif + +#ifdef JD_PROTOCOL_A + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 3, 0, 0); +#else + set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); +#if defined(JD_PROTOCOL_B_3PA) + input_mt_init_slots(ts->input_dev, pjadard_ic_data->JD_MAX_PT, INPUT_MT_DIRECT); +#else + input_mt_init_slots(ts->input_dev, pjadard_ic_data->JD_MAX_PT); +#endif +#endif + JD_I("input_set_abs_params: min_x %d, max_x %d, min_y %d, max_y %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max - 1, ts->pdata->abs_y_min, ts->pdata->abs_y_max - 1); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, ts->pdata->abs_x_min, ts->pdata->abs_x_max - 1, + 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 - 1, + 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); +#ifdef JD_SANSUMG_PALM_EN + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, ts->pdata->abs_pressure_min, + ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); +#endif + +#ifndef JD_PROTOCOL_A +#if JD_REPORT_PRESSURE + 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); +#endif + 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); +#endif + + if (jadard_input_register_device(ts->input_dev) == 0) { + ret = JD_NO_ERR; + } else { + JD_E("%s: input device register fail\n", __func__); + input_free_device(ts->input_dev); + return JD_INPUT_REG_FAIL; + } + + if (pjadard_ic_data->JD_STYLUS_EN) { + set_bit(EV_SYN, ts->stylus_dev->evbit); + set_bit(EV_ABS, ts->stylus_dev->evbit); + set_bit(EV_KEY, ts->stylus_dev->evbit); + set_bit(BTN_TOUCH, ts->stylus_dev->keybit); + set_bit(BTN_TOOL_PEN, ts->stylus_dev->keybit); + set_bit(BTN_TOOL_RUBBER, ts->stylus_dev->keybit); + set_bit(INPUT_PROP_DIRECT, ts->stylus_dev->propbit); + + input_set_abs_params(ts->stylus_dev, ABS_PRESSURE, 0, 4095, 0, 0); + input_set_abs_params(ts->stylus_dev, ABS_DISTANCE, 0, 1, 0, 0); + input_set_abs_params(ts->stylus_dev, ABS_TILT_X, 0, 90, 0, 0); + input_set_abs_params(ts->stylus_dev, ABS_TILT_Y, 0, 360, 0, 0); + input_set_capability(ts->stylus_dev, EV_KEY, BTN_TOUCH); + input_set_capability(ts->stylus_dev, EV_KEY, BTN_STYLUS); + input_set_capability(ts->stylus_dev, EV_KEY, BTN_STYLUS2); + + input_set_abs_params(ts->stylus_dev, ABS_X, ts->pdata->abs_x_min, + ((ts->pdata->abs_x_max + 1) * pjadard_ic_data->JD_STYLUS_RATIO - 1), + ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->stylus_dev, ABS_Y, ts->pdata->abs_y_min, + ((ts->pdata->abs_y_max + 1) * pjadard_ic_data->JD_STYLUS_RATIO - 1), + ts->pdata->abs_y_fuzz, 0); + + if (jadard_input_register_device(ts->stylus_dev) == 0) { + ret = JD_NO_ERR; + } else { + JD_E("%s: input stylus register fail\n", __func__); + input_unregister_device(ts->input_dev); + input_free_device(ts->stylus_dev); + return JD_INPUT_REG_FAIL; + } + } + + JD_I("%s, input device registered.\n", __func__); + + return ret; +} + +#ifdef JD_CONFIG_FB +static void jadard_fb_register(struct work_struct *work) +{ + int ret = 0; + struct jadard_ts_data *ts = container_of(work, struct jadard_ts_data, work_fb.work); + + JD_I("%s: enter\n", __func__); + ts->fb_notif.notifier_call = jadard_fb_notifier_callback; +#ifdef JD_CONFIG_DRM + ret = drm_panel_notifier_register(ts->active_panel, &ts->fb_notif); +#else +#ifdef JD_CONFIG_DRM_MSM + ret = msm_drm_register_client(&ts->fb_notif); +#else + ret = fb_register_client(&ts->fb_notif); +#endif /* JD_CONFIG_DRM_MSM */ +#endif /* JD_CONFIG_DRM */ + + if (ret) { + JD_E(" Unable to register fb_notifier: %d\n", ret); + } +} +#endif /* JD_CONFIG_FB */ + +#ifdef JD_CONFIG_SPRD_DRM +/* +*jadard_resume_work_function +*Param:struct work_struct *work +*Return:void +*Purpose:queue work for Reduce screen time +*/ +static void jadard_resume_work_function(struct work_struct *work) +{ + jadard_chip_common_resume(pjadard_ts_data); +} + +static int jadard_drm_notifier_callback(struct notifier_block *self, unsigned long event, void *data) +{ + JD_I("event = %d, pjadard_ts_data->suspended = %d", (int)event, pjadard_ts_data->suspended); + + if ((event == DISPC_POWER_OFF) && !pjadard_ts_data->suspended) { + jadard_chip_common_suspend(pjadard_ts_data); + } else if ((event == DISPC_POWER_ON) && pjadard_ts_data->suspended) { + queue_work(pjadard_ts_data->jadard_resume_wq, &pjadard_ts_data->jadard_resume_work); + } + + return 0; +} +#endif + +#if defined(JD_CONFIG_DRM_MTK_V2) +static int jadard_disp_notifier_callback(struct notifier_block *nb, unsigned long event, void *v) +{ + struct jadard_ts_data *ts = container_of(nb, struct jadard_ts_data, disp_notifier); + int *blank = (int *)v; + + JD_I("%s: enter\n", __func__); + + if (ts && v) { + JD_I("MTK_DRM event = %lu, blank = %d\n", event, *blank); + switch (*blank) { + case MTK_DISP_BLANK_UNBLANK: + if (MTK_DISP_EARLY_EVENT_BLANK == event) { + JD_I("resume: event = %lu, Skipped\n", event); + } else if (MTK_DISP_EVENT_BLANK == event) { + JD_I("resume: event = %lu, TP_RESUME\n", event); + jadard_chip_common_resume(ts); + } + break; + case MTK_DISP_BLANK_POWERDOWN: + if (MTK_DISP_EARLY_EVENT_BLANK == event) { + JD_I("suspend: event = %lu, TP_SUSPEND\n", event); + jadard_chip_common_suspend(ts); + } else if (MTK_DISP_EVENT_BLANK == event) { + JD_I("suspend: event = %lu, Skipped\n", event); + } + break; + } + } else { + JD_E("%s: event data is null"); + return -ENOMEM; + } + + return 0; +} +#endif + +#if defined(JD_ESD_CHECK) +#define JD_CPU_PC (0x4000800C) +static void jadard_esd_check(struct work_struct *work) +{ +#ifdef JD_ZERO_FLASH + int upgrade = 0; + int counter = 0; +#endif + int same_data = 0; + uint8_t pre_rdata[4]; + uint8_t rdata[4], i, bypass; + + pjadard_ts_data->esd_check_running = true; + + while (pjadard_ts_data->esd_check_running) { + if ((pjadard_ts_data->suspended == false) && (pjadard_ts_data->ito_sorting_active == false) && + (pjadard_ts_data->diag_thread_active == false)) { + mutex_lock(&(pjadard_ts_data->sorting_active)); + /* jd_g_esd_check_enable = true; */ + + g_module_fp.fp_register_read(JD_CPU_PC, rdata, 4); + + if ((pre_rdata[0] == rdata[0]) && (pre_rdata[1] == rdata[1]) && (pre_rdata[2] == rdata[2]) && (pre_rdata[3] == rdata[3])) { + same_data++; + } else { + pre_rdata[0] = rdata[0]; + pre_rdata[1] = rdata[1]; + pre_rdata[2] = rdata[2]; + pre_rdata[3] = rdata[3]; + same_data = 0; + } + + if (((rdata[1] == 0x00) && (rdata[2] == 0x00) && (rdata[3] == 0x00)) || (same_data >= 5)) { + if ((rdata[0] == 0xD8) || (rdata[0] == 0xDA) || (rdata[0] == 0xDC) || (rdata[0] == 0xDE) || + (rdata[0] == 0xE0) || (rdata[0] == 0xE2) || (rdata[0] == 0xE4) || (rdata[0] == 0xE6) || + (same_data >= 5)) { + if (pjadard_ts_data->fw_ready == true) { + JD_I("PC(0-3):0x%02x, 0x%02x, 0x%02x, 0x%02x\n", rdata[0], rdata[1], rdata[2], rdata[3]); + + if (same_data >= 5) { + same_data = 0; + bypass = 0; + + for (i = 0; i < 10; i++) { + g_module_fp.fp_register_read(JD_CPU_PC, rdata, 4); + if ((pre_rdata[0] != rdata[0]) || (pre_rdata[1] != rdata[1]) || + (pre_rdata[2] != rdata[2]) || (pre_rdata[3] != rdata[3])) { + bypass = 1; + break; + } + } + + if (bypass == 0) { + #ifdef JD_ZERO_FLASH + JD_I("Upgrade fw by the same pc\n"); + pjadard_ts_data->power_on_upgrade = true; + + if (g_module_fp.fp_0f_esd_upgrade_fw(jd_i_CTPM_firmware_name) >= 0) { + jadard_report_all_leave_event(pjadard_ts_data); + upgrade = 1; + } + jadard_int_enable(true); + pjadard_ts_data->power_on_upgrade = false; + #else + JD_I("Reset Touch chip by the same pc\n"); + jadard_int_enable(false); + g_module_fp.fp_soft_reset(); + jadard_report_all_leave_event(pjadard_ts_data); + jadard_int_enable(true); + #endif + } + } else { + #ifdef JD_ZERO_FLASH + pjadard_ts_data->power_on_upgrade = true; + + if (g_module_fp.fp_0f_esd_upgrade_fw(jd_i_CTPM_firmware_name) >= 0) { + jadard_report_all_leave_event(pjadard_ts_data); + upgrade = 1; + } + jadard_int_enable(true); + pjadard_ts_data->power_on_upgrade = false; + #else + JD_I("Reset Touch chip by fault address\n"); + jadard_int_enable(false); + g_module_fp.fp_soft_reset(); + jadard_report_all_leave_event(pjadard_ts_data); + jadard_int_enable(true); + #endif + } + } + } + } + +#ifdef JD_ZERO_FLASH + /* Pram CRC check */ + if ((upgrade == 0) && (counter >= 4)) { + pjadard_report_data->crc_start = 1; + + JD_I("Pram CRC check\n"); + counter = 0; + + if (g_module_fp.fp_0f_esd_upgrade_fw(jd_i_CTPM_firmware_name) >= 0) { + jadard_report_all_leave_event(pjadard_ts_data); + } + jadard_int_enable(true); + + pjadard_report_data->crc_start = 0; + } + upgrade = 0; +#endif + jd_g_esd_check_enable = false; + mutex_unlock(&(pjadard_ts_data->sorting_active)); + + msleep(1000); +#ifdef JD_ZERO_FLASH + counter++; +#endif + } + } +} +#endif + +int jadard_chip_common_init(void) +{ + struct jadard_support_chip *ptr = g_module_fp.head_support_chip; + struct jadard_support_chip *del_ptr = NULL; + struct jadard_ts_data *ts = pjadard_ts_data; + struct jadard_platform_data *pdata = NULL; + int err = 0; + + JD_I("%s: enter\n", __func__); + + ts->fw_ready = false; +#ifdef JD_ZERO_FLASH + ts->power_on_upgrade = true; +#endif + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (pdata == NULL) { + err = -ENOMEM; + goto err_platform_data_fail; + } + + pjadard_ic_data = kzalloc(sizeof(*pjadard_ic_data), GFP_KERNEL); + if (pjadard_ic_data == NULL) { + err = -ENOMEM; + goto err_ic_data_fail; + } + + memset(pjadard_ic_data, 0x00, sizeof(struct jadard_ic_data)); + + pjadard_report_data = kzalloc(sizeof(struct jadard_report_data), GFP_KERNEL); + if (pjadard_report_data == NULL) { + err = -ENOMEM; + goto err_alloc_touch_data_fail; + } + + if (jadard_parse_dt(ts, pdata) < 0) { + JD_I(" pdata is NULL\n"); + err = JD_CHECK_DATA_ERROR; + goto err_alloc_pdata_fail; + } + +#ifdef JD_RST_PIN_FUNC + ts->rst_gpio = pdata->gpio_reset; +#endif + jadard_gpio_power_config(pdata); + ts->pdata = pdata; + /* Initial function pointer */ + jadard_mcu_cmd_struct_init(); + + while (ptr != NULL) { + if (ptr->chip_detect) { + if (ptr->chip_detect()) { + if (ptr->chip_init) { + ptr->chip_init(); + + /* Free jadard_support_chip memory */ + del_ptr = g_module_fp.head_support_chip; + while (del_ptr != NULL) { + g_module_fp.head_support_chip = del_ptr; + del_ptr = del_ptr->next; + kfree(g_module_fp.head_support_chip); + } + g_module_fp.head_support_chip = NULL; + break; + } + } + } + ptr = ptr->next; + } + + if (ptr == NULL) { + JD_E("%s: Could not find Jadard Chipset\n", __func__); + err = JD_CHECK_DATA_ERROR; + goto error_ic_detect_failed; + } + +#ifdef JD_AUTO_UPGRADE_FW + ts->jadard_upgrade_wq = create_singlethread_workqueue("JD_upgrade_reuqest"); + if (!ts->jadard_upgrade_wq) { + JD_E(" allocate syn_upgrade_wq failed\n"); + err = -ENOMEM; + goto err_upgrade_wq_failed; + } + + INIT_DELAYED_WORK(&ts->work_upgrade, jadard_upgrade_process); + queue_delayed_work(ts->jadard_upgrade_wq, &ts->work_upgrade, msecs_to_jiffies(JD_UPGRADE_DELAY_TIME)); +#endif + +#ifdef JD_ZERO_FLASH + ts->jadard_0f_upgrade_wq = create_singlethread_workqueue("JD_0f_update_reuqest"); + INIT_DELAYED_WORK(&ts->work_0f_upgrade, g_module_fp.fp_0f_operation); + queue_delayed_work(ts->jadard_0f_upgrade_wq, &ts->work_0f_upgrade, msecs_to_jiffies(JD_UPGRADE_DELAY_TIME)); +#endif +#ifdef JD_ESD_CHECK + ts->jadard_esd_check_wq = create_singlethread_workqueue("JD_esd_check_reuqest"); + INIT_DELAYED_WORK(&ts->work_esd_check, jadard_esd_check); + queue_delayed_work(ts->jadard_esd_check_wq, &ts->work_esd_check, msecs_to_jiffies(JD_ESD_CHECK_DELAY_TIME)); +#endif + + g_module_fp.fp_touch_info_set(); + +#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->usb_status[0] = 0xF0; + pdata->usb_status[1] = 0x00; +#endif + ts->suspended = false; + ts->rawdata_little_endian = true; +#if defined(JD_USB_DETECT_CALLBACK) || defined(JD_USB_DETECT_GLOBAL) + ts->usb_connected = 0; + ts->usb_status = pdata->usb_status; +#endif + +#ifdef JD_PROTOCOL_A + ts->protocol_type = PROTOCOL_TYPE_A; +#else + ts->protocol_type = PROTOCOL_TYPE_B; +#endif + JD_I("%s: Use Protocol Type %c\n", __func__, + ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); + err = jadard_input_register(ts); + if (err) { + JD_E("%s: Unable to register %s input device\n", + __func__, ts->input_dev->name); + goto err_input_register_device_failed; + } + +#ifdef JD_CONFIG_FB +#ifdef JD_CONFIG_DRM + ret = jadard_drm_check_dt(ts); + if (ret) { + JD_E(" parse drm-panel fail\n"); + goto err_get_intr_bit_failed; + } +#endif + ts->jadard_fb_wq = create_singlethread_workqueue("JD_FB_reuqest"); + if (!ts->jadard_fb_wq) { + JD_E(" allocate syn_fb_wq failed\n"); + err = -ENOMEM; + goto err_get_intr_bit_failed; + } + + INIT_DELAYED_WORK(&ts->work_fb, jadard_fb_register); + queue_delayed_work(ts->jadard_fb_wq, &ts->work_fb, msecs_to_jiffies(JD_FB_DELAY_TIME)); +#endif + +#ifdef JD_SMART_WAKEUP + ts->SMWP_enable = false; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) + ts->ts_SMWP_wake_lock = wakeup_source_register(ts->dev, JADARD_common_NAME); +#else + wakeup_source_init(ts->ts_SMWP_wake_lock, JADARD_common_NAME); +#endif +#endif + + err = jadard_report_data_init(); + if (err) { + JD_E(" %s: jadard_report_data_init failed!\n", __func__); + goto err_report_data_init_failed; + } + + if (jadard_common_proc_init()) { + JD_E(" %s: jadard_common proc_init failed!\n", __func__); + err = JD_CHECK_DATA_ERROR; + goto err_creat_proc_file_failed; + } + +#if defined(JD_USB_DETECT_CALLBACK) + if (ts->usb_status) { + ts->jadard_usb_detect_wq = create_singlethread_workqueue("JD_usb_detect_reuqest"); + INIT_DELAYED_WORK(&ts->work_usb_detect, jadard_charger_init); + queue_delayed_work(ts->jadard_usb_detect_wq, &ts->work_usb_detect, msecs_to_jiffies(JD_USB_DETECT_DELAY_TIME)); + } +#endif + +#ifdef CONFIG_JD_HID + ts->jadard_hid_mode_wq = create_singlethread_workqueue("JD_hid_mode_reuqest"); + INIT_DELAYED_WORK(&ts->work_hid_mode, jadard_hid_mode_init); + queue_delayed_work(ts->jadard_hid_mode_wq, &ts->work_hid_mode, msecs_to_jiffies(JD_HID_MODE_DELAY_TIME)); +#endif + + err = jadard_ts_register_interrupt(); + if (err) { + JD_E(" %s: jadard_ts_register_interrupt failed!\n", __func__); + goto err_register_interrupt_failed; + } + +#if defined(JD_CONFIG_NODE) + err = jadard_ts_filesys_create(ts); + if (err) { + JD_E(" %s: jadard_ts_filesys_create failed!\n", __func__); + goto err_sysfs_init_failed; + } +#endif + +#if defined(JD_CONFIG_SPRD_DRM) + ts->jadard_resume_wq = create_singlethread_workqueue("jadard_resume_wq"); + INIT_WORK(&ts->jadard_resume_work, jadard_resume_work_function); + + ts->drm_notify.notifier_call = jadard_drm_notifier_callback; + err = disp_notifier_register(&ts->drm_notify); + if (err < 0) { + JD_E("Failed to register drm_notify"); + goto err_register_drm_notif_failed; + } +#endif + +#if defined(JD_CONFIG_DRM_MTK_V2) + ts->disp_notifier.notifier_call = jadard_disp_notifier_callback; + err = mtk_disp_notifier_register("Jadard_Touch", &ts->disp_notifier); + if (err < 0) { + JD_E("Failed to register disp notifier"); + goto err_register_mtk_disp_notif_failed; + } +#endif + +#ifdef JD_ZERO_FLASH + /* Close ATTN before fw upgrade ready */ + jadard_int_enable(false); +#endif + +#ifdef CONFIG_TOUCHSCREEN_JADARD_DEBUG + if (jadard_debug_init()) { + JD_E(" %s: debug initial failed!\n", __func__); + err = -ENOMEM; + goto err_debug_init_failed; + } +#endif + +#if defined(JD_SMART_WAKEUP) && defined(JD_SYS_CLASS_SMWP_EN) + jd_gesture_node_init(); +#endif + +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_DISABLE) +#ifdef JD_SYS_CLASS_PSENSOR_EN + jd_proximity_node_init(); +#endif +#endif + + return JD_NO_ERR; + +#ifdef CONFIG_TOUCHSCREEN_JADARD_DEBUG +err_debug_init_failed: +#endif +#if defined(JD_CONFIG_DRM_MTK_V2) +err_register_mtk_disp_notif_failed: +#endif +#if defined(JD_CONFIG_SPRD_DRM) +err_register_drm_notif_failed: +#endif +#if defined(JD_CONFIG_NODE) +#if defined(JD_CONFIG_SPRD_DRM) + jadard_ts_filesys_remove(ts); +#endif +err_sysfs_init_failed: +#endif + jadard_ts_free_interrupt(); +err_register_interrupt_failed: +err_creat_proc_file_failed: +err_report_data_init_failed: +#ifdef JD_SMART_WAKEUP +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) + wakeup_source_unregister(ts->ts_SMWP_wake_lock); +#else + wakeup_source_trash(ts->ts_SMWP_wake_lock); +#endif +#endif +#ifdef JD_CONFIG_FB + cancel_delayed_work_sync(&ts->work_fb); + destroy_workqueue(ts->jadard_fb_wq); +err_get_intr_bit_failed: +#endif + input_unregister_device(ts->input_dev); + if (pjadard_ic_data->JD_STYLUS_EN) { + input_unregister_device(ts->stylus_dev); + } + +err_input_register_device_failed: +#ifdef JD_ESD_CHECK + cancel_delayed_work_sync(&ts->work_esd_check); + destroy_workqueue(ts->jadard_esd_check_wq); +#endif + +#ifdef JD_ZERO_FLASH + cancel_delayed_work_sync(&ts->work_0f_upgrade); + destroy_workqueue(ts->jadard_0f_upgrade_wq); +#endif + +#ifdef JD_AUTO_UPGRADE_FW + cancel_delayed_work_sync(&ts->work_upgrade); + destroy_workqueue(ts->jadard_upgrade_wq); +err_upgrade_wq_failed: +#endif +error_ic_detect_failed: + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); +#endif + + jadard_gpio_power_deconfig(pdata); +err_alloc_pdata_fail: + kfree(pjadard_report_data); +err_alloc_touch_data_fail: + kfree(pjadard_ic_data); +err_ic_data_fail: + kfree(pdata); +err_platform_data_fail: + kfree(ts); + + return err; +} + +void jadard_chip_common_deinit(void) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + JD_I("%s: enter\n", __func__); + +#if defined(JD_SMART_WAKEUP) && defined(JD_SYS_CLASS_SMWP_EN) + jd_gesture_node_remove(); +#endif + +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_DISABLE) +#ifdef JD_SYS_CLASS_PSENSOR_EN + jd_proximity_node_remove(); +#endif +#endif + +#if defined(JD_CONFIG_DRM_MTK_V2) + if (mtk_disp_notifier_unregister(&ts->disp_notifier)) { + JD_E("Error occurred when unregister disp_notifier"); + } +#endif + +#if defined(JD_CONFIG_SPRD_DRM) + disp_notifier_unregister(&ts->drm_notify); +#endif + +#if defined(JD_CONFIG_NODE) + jadard_ts_filesys_remove(ts); +#endif + + jadard_ts_free_interrupt(); + +#ifdef CONFIG_TOUCHSCREEN_JADARD_DEBUG + jadard_debug_remove(); +#endif + + jadard_common_proc_deinit(); + +#ifdef JD_SMART_WAKEUP +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0) + wakeup_source_unregister(ts->ts_SMWP_wake_lock); +#else + wakeup_source_trash(ts->ts_SMWP_wake_lock); +#endif +#endif + +#ifdef JD_CONFIG_FB +#ifdef JD_CONFIG_DRM + if (drm_panel_notifier_unregister(ts->active_panel, &ts->fb_notif)) + JD_E("Error occurred while unregistering drm_panel_notifier.\n"); +#else +#ifdef JD_CONFIG_DRM_MSM + if (msm_drm_unregister_client(&ts->fb_notif)) + JD_E("Error occurred while unregistering msm_drm_unregister.\n"); +#else + if (fb_unregister_client(&ts->fb_notif)) + JD_E("Error occurred while unregistering fb_notifier.\n"); +#endif /* JD_CONFIG_DRM_MSM */ +#endif /* JD_CONFIG_DRM */ + cancel_delayed_work_sync(&ts->work_fb); + destroy_workqueue(ts->jadard_fb_wq); +#endif /* JD_CONFIG_FB */ + + input_free_device(ts->input_dev); + +#ifdef JD_ESD_CHECK + cancel_delayed_work_sync(&ts->work_esd_check); + destroy_workqueue(ts->jadard_esd_check_wq); +#endif + +#ifdef JD_ZERO_FLASH + cancel_delayed_work_sync(&ts->work_0f_upgrade); + destroy_workqueue(ts->jadard_0f_upgrade_wq); +#endif + +#ifdef JD_AUTO_UPGRADE_FW + cancel_delayed_work_sync(&ts->work_upgrade); + destroy_workqueue(ts->jadard_upgrade_wq); +#endif + +#ifdef JD_USB_DETECT_CALLBACK + cancel_delayed_work_sync(&ts->work_usb_detect); + destroy_workqueue(ts->jadard_usb_detect_wq); +#endif + + jadard_gpio_power_deconfig(ts->pdata); + + if (gpio_is_valid(ts->pdata->gpio_irq)) + gpio_free(ts->pdata->gpio_irq); + +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(ts->pdata->gpio_reset)) + gpio_free(ts->pdata->gpio_reset); +#endif + + if (pjadard_host_data->id != NULL) { + kfree(pjadard_host_data->id); + pjadard_host_data->id = NULL; + } + + if (pjadard_host_data->x != NULL) { + kfree(pjadard_host_data->x); + pjadard_host_data->x = NULL; + } + + if (pjadard_host_data->y != NULL) { + kfree(pjadard_host_data->y); + pjadard_host_data->y = NULL; + } + + if (pjadard_host_data->w != NULL) { + kfree(pjadard_host_data->w); + pjadard_host_data->w = NULL; + } + + if (pjadard_host_data->event != NULL) { + kfree(pjadard_host_data->event); + pjadard_host_data->event = NULL; + } + + if (pjadard_host_data != NULL) { + kfree(pjadard_host_data); + pjadard_host_data = NULL; + } + + if (pjadard_report_data->touch_coord_info != NULL) { + kfree(pjadard_report_data->touch_coord_info); + pjadard_report_data->touch_coord_info = NULL; + } + + kfree(pjadard_report_data); + kfree(pjadard_ic_data); + kfree(ts->pdata); + kfree(ts); +} + +int jadard_chip_common_suspend(struct jadard_ts_data *ts) +{ + bool cancel_diag_thread = true; + + if (ts->suspended) { + JD_I("%s: Already suspended, Skipped\n", __func__); + return 0; + } else { + JD_I("%s: enter\n", __func__); + ts->suspended = true; + } + +#if defined(JD_SMART_WAKEUP) || defined(JD_USB_DETECT_GLOBAL) || defined(JD_USB_DETECT_CALLBACK) ||\ + defined(JD_HIGH_SENSITIVITY) || defined(JD_ROTATE_BORDER) || defined(JD_EARPHONE_DETECT) + g_module_fp.fp_resume_set_func(ts->suspended); +#endif + +#if defined(JD_SMART_WAKEUP) + cancel_diag_thread = !ts->SMWP_enable; +#endif + /* Cancel mutual data thread, if exist */ + if (ts->diag_thread_active && cancel_diag_thread) { + ts->diag_thread_active = false; + cancel_delayed_work_sync(&ts->jadard_diag_delay_wrok); + } + +#ifdef JD_ESD_CHECK + if (ts->esd_check_running == true) { + JD_I("Stop esd check\n"); + ts->esd_check_running = false; + cancel_delayed_work_sync(&ts->work_esd_check); + } +#endif + + if ((pjadard_debug != NULL) && (*pjadard_debug->fw_dump_going)) { + JD_I("%s: Flash dump is going, reject suspend\n", __func__); + return 0; + } + +#ifdef JD_SMART_WAKEUP + if (ts->SMWP_enable) { +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_SUSPEND_RESUME) + atomic_set(&ts->suspend_mode, 1); +#endif + irq_set_irq_wake(ts->jd_irq, 1); + JD_I("[jadard] %s: SMART_WAKEUP enable\n", __func__); + return 0; + } +#endif + +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_SUSPEND_RESUME) + jadard_int_enable(false); + atomic_set(&ts->suspend_mode, 1); +#endif + + JD_I("%s: end\n", __func__); + return 0; +} + +int jadard_chip_common_resume(struct jadard_ts_data *ts) +{ +#ifdef JD_ZERO_FLASH + bool skip_fw_upgrade = false; +#endif + + if (!ts->suspended) { + JD_I("%s: Already resumed, Skipped\n", __func__); + return 0; + } else { + JD_I("%s: enter\n", __func__); + ts->suspended = false; + } + + atomic_set(&ts->suspend_mode, 0); + +#if defined(JD_SMART_WAKEUP) + if (ts->SMWP_enable) { + irq_set_irq_wake(ts->jd_irq , 0); + } +#endif + +#ifdef JD_ZERO_FLASH + JD_I("Upgrade fw in zero flash mode\n"); +#if defined(JD_SMART_WAKEUP) + skip_fw_upgrade = ts->SMWP_enable; +#endif + if (ts->diag_thread_active && skip_fw_upgrade) { + JD_I("Diag thread is active! Skip Update with zero flash\n"); + } else if (g_module_fp.fp_0f_upgrade_fw(jd_i_CTPM_firmware_name) < 0) { + JD_E("Something is wrong! Skip Update with zero flash\n"); + } +#endif + + jadard_report_all_leave_event(ts); + +#if defined(JD_SMART_WAKEUP) || defined(JD_USB_DETECT_GLOBAL) || defined(JD_USB_DETECT_CALLBACK) ||\ + defined(JD_HIGH_SENSITIVITY) || defined(JD_ROTATE_BORDER) || defined(JD_EARPHONE_DETECT) + g_module_fp.fp_resume_set_func(ts->suspended); +#endif + + jadard_int_enable(true); + +#ifdef JD_ESD_CHECK + if (ts->esd_check_running == false) { + JD_I("Start esd check\n"); + ts->esd_check_running = true; + queue_delayed_work(ts->jadard_esd_check_wq, &ts->work_esd_check, 0); + } +#endif + + JD_I("%s: end \n", __func__); + return 0; +} diff --git a/drivers/input/touchscreen/jdchipset/jadard_common.h b/drivers/input/touchscreen/jdchipset/jadard_common.h new file mode 100644 index 0000000000000..e15c457362d31 --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_common.h @@ -0,0 +1,636 @@ +#ifndef JADARD_COMMON_H +#define JADARD_COMMON_H + +/* #include */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jadard_platform.h" + +#ifdef CONFIG_OF + #include +#endif + +#if defined(__JADARD_KMODULE__) +#include +#endif + +#define JADARD_DRIVER_VER "01.C9" /* MAJOR_VER.MINOR_VER */ +#define JADARD_DRIVER_CID_VER "00.00" /* MAJOR_CID_VER.MINOR_CID_VER */ +#define JADARD_PROC_TOUCH_FOLDER "jadard_touch" + +#define JD_TS_WAKE_LOCK_TIMEOUT (5000) +#define JD_READ_LEN_OVERFLOW (1) +#define JD_NO_ERR (0) +#define JD_WRITE_OVERFLOW (-1) +#define JD_MEM_ALLOC_FAIL (-2) +#define JD_UPGRADE_CONFLICT (-3) +#define JD_TIME_OUT (-4) +#define JD_CHIP_ID_ERROR (-5) +#define JD_APP_START_FAIL (-6) +#define JD_CHECK_DATA_ERROR (-7) +#define JD_FILE_OPEN_FAIL (-8) +#define JD_INPUT_REG_FAIL (-9) +#define JD_PRAM_CRC_PASS (-10) +/* Report format info. */ +/* #define JD_REPORT_FORMAT_V2 */ +/* #define JD_SANSUMG_PALM_EN */ +#if defined(JD_REPORT_FORMAT_V2) + #if defined(JD_SANSUMG_PALM_EN) + #define JD_PALM_EN + #define JD_TOUCH_DATA_SIZE (98) + #define JD_PALM_DATA_SIZE (2) + #define JD_TOUCH_PALM_INFO_SIZE (JD_PALM_DATA_SIZE*10) + #else + #define JD_TOUCH_DATA_SIZE (78) + #endif +#else + #if defined(JD_SANSUMG_PALM_EN) + #define JD_PALM_EN + #define JD_TOUCH_DATA_SIZE (124) + #define JD_PALM_DATA_SIZE (2) + #define JD_TOUCH_PALM_INFO_ADDR (104) + #else + #define JD_TOUCH_DATA_SIZE (78) + #endif +#endif + +#define JD_TOUCH_MAX_DATA_SIZE (256) +#define JD_HID_TOUCH_DATA_SIZE (JD_TOUCH_DATA_SIZE + 4) +#define JD_FINGER_DATA_SIZE (5) +#define JD_TOUCH_STATE_INFO_SIZE (5) /* Touch_State*4+Touch_Application*1 */ +#define JD_TOUCH_STYLUS_SIZE (14) +#define JD_GEST_SUP_NUM (23) + +#if defined(JD_REPORT_FORMAT_V2) + #define JD_TOUCH_HEADER_SIZE (3) + #define JD_TOUCH_STATE_ALL_SIZE (JD_TOUCH_STATE_INFO_SIZE + 6) + #define JD_FINGER_FRAME_ADDR (1) + #define JD_TOUCH_STYLUS_INFO_ADDR (3) +#else + #define JD_FINGER_NUM_ADDR (0) + #define JD_FINGER_FRAME_ADDR (1) + #define JD_TOUCH_EVENT_INFO_ADDR (2) + #define JD_TOUCH_COORD_INFO_ADDR (3) + #define JD_TOUCH_STATE_INFO_ADDR (53) + #define JD_TOUCH_STYLUS_INFO_ADDR (64) +#endif + +/* + * Thread delay time setting + */ +#define JD_UPGRADE_FW_RETRY_TIME (10) +#if defined(CONFIG_JD_DB) +#define JD_UPGRADE_DELAY_TIME (35000) +#else +#define JD_UPGRADE_DELAY_TIME (3000) +#endif +#define JD_FB_DELAY_TIME (15000) +#define JD_USB_DETECT_DELAY_TIME (35000) +#define JD_ESD_CHECK_DELAY_TIME (50000) +#define JD_HID_MODE_DELAY_TIME (50000) + +/*=========== Config select start ===========*/ +/* #define JD_REPORT_CHECKSUM */ +/* #define JD_REPORT_FRAME_CHECK */ + +/* + * 0 : Cell phone + * 1 : JD9366T Tablet + * 2 : JD9366TP/JD9366TS Tablet + */ +#define JD_PRODUCT_TYPE (0) + +/* + * Can't enable JD_AUTO_UPGRADE_FW and JD_ZERO_FLASH + * at the same time + */ +/* #define JD_AUTO_UPGRADE_FW */ +/* #define JD_ZERO_FLASH*/ + +/* + * All *.bin content store in an array (Jadard_firmware.i) and write to ram + */ +/* #define JD_UPGRADE_FW_ARRAY */ + +/* + * Program Jadard_ito_firmware.bin before sorting_test + * and program Jadard_firmware.bin after sorting_test + */ +/* #define JD_UPGRADE_ITO_FW */ + +/* + * USB detect function + * JD_USB_DETECT_CALLBACK support after Android10 + */ +/* #define JD_USB_DETECT_GLOBAL*/ +/* #define JD_USB_DETECT_CALLBACK */ + +/* + * JD_PROTOCOL_A : Report specific format of MTK platform + * JD_PROTOCOL_B(undef JD_PROTOCOL_A) : input_mt_init_slots(A, B) format of QCT platform + * JD_PROTOCOL_B_3PA : input_mt_init_slots(A, B, C) format of QCT platform + */ +/* #define JD_PROTOCOL_A */ +#define JD_PROTOCOL_B_3PA +/* + * Report Pressure in multitouch + * 1:enable(default), 0:disable +*/ +#define JD_REPORT_PRESSURE (1) + +/* Other config */ +/* #define JD_RST_PIN_FUNC +/* #define JD_SMART_WAKEUP */ +/* #define JD_SYS_CLASS_SMWP_EN */ +/* #define JD_HIGH_SENSITIVITY */ +/* #define JD_ROTATE_BORDER */ +/* #define JD_EARPHONE_DETECT */ +/* #define JD_PALM_EN */ +#if defined(JD_PALM_EN) +#define JD_BTN_PALM (0x118) +#endif + +/* + * Proximity mode options + * Disable: JD_PROXIMITY_DISABLE + * Enable: JD_PROXIMITY_SUSPEND_RESUME when sleep in/out + * JD_PROXIMITY_BACKLIGHT when backlight on/off + */ +#define JD_PROXIMITY_DISABLE 0 /* Don`t modify */ +#define JD_PROXIMITY_SUSPEND_RESUME 1 /* Don`t modify */ +#define JD_PROXIMITY_BACKLIGHT 2 /* Don`t modify */ +#define JD_PROXIMITY_MODE (JD_PROXIMITY_DISABLE) +/* #define JD_SYS_CLASS_PSENSOR_EN */ + +/* #define CONFIG_CHIP_DTCFG */ + +/* + * Customer/platform config + */ +/* #define JD_OPPO_FUNC */ + +/* + * Suspend/Resume function + * + * Frame Buffer (FB): JD_CONFIG_FB + * Direct Rendering Manager (DRM): JD_CONFIG_FB + JD_CONFIG_DRM + * Qualcomm MSM DRM: JD_CONFIG_FB + JD_CONFIG_DRM_MSM + * MTK Platform DRM V2: JD_CONFIG_DRM_MTK_V2 + * SPRD Platform DRM: JD_CONFIG_SPRD_DRM + * System Node: JD_CONFIG_NODE + */ +/* #define JD_CONFIG_FB */ +/* #define JD_CONFIG_DRM */ +/* #define JD_CONFIG_DRM_MSM */ +/* #define JD_CONFIG_DRM_MTK_V2 */ +/* #define JD_CONFIG_SPRD_DRM */ +/* #define JD_CONFIG_NODE */ + +/* + * Enable I2C single mode for with flash only + */ +/* #define JD_I2C_SINGLE_MODE */ + +/* + * Enable esd check for Zero-Flash only + */ +/* #define JD_ESD_CHECK */ + +/* + * Parse the jadard_sorting_threshold.h file and set sorting threshold + */ +/* #define JD_SORTING_THRES_BUILT_IN */ + +/* + * Enable each workarounds for FPGA only + */ +/* #define JD_FPGA_WORKAROUND */ +/*=========== Config select end =============*/ + +#if defined(JD_CONFIG_FB) + #include + #include +#if defined(JD_CONFIG_DRM) + #include +#endif +#if defined(JD_CONFIG_DRM_MSM) + #include +#endif +#endif + +#if defined(JD_CONFIG_SPRD_DRM) + #include +#endif + +#if defined(JD_CONFIG_DRM_MTK_V2) + #include "mtk_disp_notify.h" +#endif + +#if defined(JD_USB_DETECT_CALLBACK) + #include +#endif + +#if defined(CONFIG_JD_HID) + #include "jadard_hid.h" +#endif + +enum JD_DATA_TYPE { + JD_DATA_TYPE_RawData = 1, + JD_DATA_TYPE_Baseline, + JD_DATA_TYPE_Difference, + JD_DATA_TYPE_LISTEN, + JD_DATA_TYPE_LABEL, + JD_DATA_TYPE_LAPLACE, + JD_DATA_TYPE_RESERVE_7, + JD_DATA_TYPE_RESERVE_8, + JD_DATA_TYPE_RESERVE_9, + JD_DATA_TYPE_RESERVE_A, + JD_DATA_TYPE_RESERVE_B, + JD_DATA_TYPE_RESERVE_C, + JD_DATA_TYPE_RESERVE_D, + JD_DATA_TYPE_RESERVE_E, + JD_DATA_TYPE_RESERVE_F +}; + +enum JD_KEEP_TYPE { + JD_KEEP_TYPE_NormalValue = 1, + JD_KEEP_TYPE_MaxValue, + JD_KEEP_TYPE_MinValue, + JD_KEEP_TYPE_PeakValue +}; + +enum JD_IRQ_EVENT { + JD_REPORT_COORD = 1, + JD_REPORT_SMWP_EVENT, +}; + +enum JD_TS_STATUS { + JD_TS_UNUSUAL_DATA_FAIL = -4, + JD_TS_CHECKSUM_FAIL = -3, + JD_TS_GET_DATA_FAIL = -2, + JD_IRQ_EVENT_FAIL = -1, + JD_TS_NORMAL_START = 0, + JD_REPORT_DATA, + JD_RST_OK, +}; + +enum JD_DDREG_MODE { + JD_DDREG_MODE_0 = 0x00, + JD_DDREG_MODE_1, +}; + +enum JD_DBIC_REG_ADDR { + JD_DBIC_BASE_ADDR = 0x400001, + JD_DBIC_CMD = (JD_DBIC_BASE_ADDR << 8) + 0x40, + JD_DBIC_WRITE_DATA = (JD_DBIC_BASE_ADDR << 8) + 0x41, + JD_DBIC_READ_DATA = (JD_DBIC_BASE_ADDR << 8) + 0x42, + JD_DBIC_DUMMY1 = (JD_DBIC_BASE_ADDR << 8) + 0x43, + JD_DBIC_INT_EN = (JD_DBIC_BASE_ADDR << 8) + 0x44, + JD_DBIC_INT_CLR = (JD_DBIC_BASE_ADDR << 8) + 0x45, + JD_DBIC_SPI_RUN = (JD_DBIC_BASE_ADDR << 8) + 0x46, + JD_DBIC_CMD_LEN = (JD_DBIC_BASE_ADDR << 8) + 0x47, + JD_DBIC_SPI_FREQ = (JD_DBIC_BASE_ADDR << 8) + 0x48, + JD_DBIC_STATUS = (JD_DBIC_BASE_ADDR << 8) + 0x49, +}; + +enum JD_DBIC_RELATED_SETTING { + JD_DBIC_READ_WRITE_SUCCESS = 0x00, + JD_DBIC_READ_WRITE_FAIL = 0x01, + JD_DBIC_IRQ_VALID_MSK = 0x03, + JD_DBIC_WRITE_RUN = 0x01, + JD_DBIC_READ_RUN = 0x03, + JD_DBIC_INT_CLR_BUSY_MSK = 0x40, + JD_DBIC_STATUS_BUSY_MSK = 0x40, + JD_DBIC_STATUS_RDY_MSK = 0x80, + JD_DBIC_STATUS_RDY_BUSY_MSK = 0xC0, + JD_DBIC_READ_SET_CMD = 0xF1, + JD_DBIC_READ_DATA_CMD = 0xF2, +}; + +enum JD_DBI_DDREG_ADDR { + JD_DBI_DDREG_BASE_ADDR = 0x50000000, + JD_DBI_DDREG_STD_CMD_BASE_ADDR = 0x50800000, + JD_S_DBI_DDREG_BASE_ADDR = 0x51000000, + JD_S_DBI_DDREG_STD_CMD_BASE_ADDR = 0x51800000, +}; + +struct jadard_ts_data { + bool suspended; + bool rawdata_little_endian; + atomic_t suspend_mode; + uint8_t protocol_type; + uint8_t irq_enabled; + uint8_t debug_log_touch_level; + bool debug_fw_package_enable; + bool debug_diag_apk_enable; + bool dbi_std_mode_enable; + int rst_gpio; + int jd_irq; + bool rst_active; + bool diag_thread_active; + + struct device *dev; + struct input_dev *input_dev; + struct input_dev *stylus_dev; + struct i2c_client *client; + struct jadard_platform_data *pdata; + struct mutex rw_lock; + struct mutex sorting_active; + spinlock_t irq_active; + bool ito_sorting_active; + +/******* SPI-start *******/ + struct mutex spi_lock; + struct spi_device *spi; +/******* SPI-end *******/ + +#if defined(JD_CONFIG_FB) + struct notifier_block fb_notif; + struct workqueue_struct *jadard_fb_wq; + struct delayed_work work_fb; +#if defined(JD_CONFIG_DRM) + struct drm_panel *active_panel; +#endif +#endif + + struct workqueue_struct *fw_dump_wq; + struct work_struct fw_dump_work; + +#ifdef JD_AUTO_UPGRADE_FW + struct workqueue_struct *jadard_upgrade_wq; + struct delayed_work work_upgrade; +#endif + + bool fw_ready; +#ifdef JD_ZERO_FLASH + struct workqueue_struct *jadard_0f_upgrade_wq; + struct delayed_work work_0f_upgrade; + bool power_on_upgrade; +#endif + +#ifdef JD_ESD_CHECK + bool esd_check_running; + struct workqueue_struct *jadard_esd_check_wq; + struct delayed_work work_esd_check; +#endif + + struct workqueue_struct *jadard_diag_wq; + struct delayed_work jadard_diag_delay_wrok; + +#ifdef JD_SMART_WAKEUP + bool SMWP_enable; + bool gesture_cust_en[JD_GEST_SUP_NUM]; + struct wakeup_source *ts_SMWP_wake_lock; +#endif + +#if defined(JD_USB_DETECT_CALLBACK) || defined(JD_USB_DETECT_GLOBAL) + uint8_t usb_connected; + uint8_t *usb_status; +#if defined(JD_USB_DETECT_GLOBAL) + int update_usb_status; +#endif +#if defined(JD_USB_DETECT_CALLBACK) + struct notifier_block charger_notif; + struct workqueue_struct *jadard_usb_detect_wq; + struct delayed_work work_usb_detect; +#endif +#endif + +#ifdef JD_HIGH_SENSITIVITY + bool high_sensitivity_enable; +#endif + +#ifdef JD_ROTATE_BORDER + int rotate_switch_mode; + uint16_t rotate_border; +#endif + +#ifdef JD_EARPHONE_DETECT + /* High byte Low byte + * ------------------------------ + *| Type-c status | 3.5mm status | + * ------------------------------ + */ + uint16_t earphone_enable; +#endif + +#if (JD_PROXIMITY_MODE != JD_PROXIMITY_DISABLE) + uint8_t proximity_enable; + uint8_t proximity_detect; + uint8_t pre_proximity_detect; +#endif + +#ifdef JD_PALM_EN + uint8_t palm_detect; + uint8_t pre_palm_detect; +#endif + +#if defined(JD_CONFIG_SPRD_DRM) + struct notifier_block drm_notify; + struct workqueue_struct *jadard_resume_wq; + struct work_struct jadard_resume_work; +#endif + +#if defined(JD_CONFIG_DRM_MTK_V2) + struct notifier_block disp_notifier; +#endif + +#ifdef CONFIG_JD_HID + struct workqueue_struct *jadard_hid_mode_wq; + struct delayed_work work_hid_mode; +#endif +}; + +struct jadard_ic_data { + char chip_id[15]; + uint32_t fw_ver; + uint32_t fw_cid_ver; + char panel_maker[10]; + uint8_t panel_ver; + int JD_X_NUM; + int JD_Y_NUM; + int JD_X_RES; + int JD_Y_RES; + int JD_MAX_PT; + bool JD_INT_EDGE; + bool JD_STYLUS_EN; + uint8_t JD_STYLUS_ID_EN; + uint8_t JD_STYLUS_RATIO; + uint8_t JD_MODULE_CASCADE_MODE; + uint32_t JD_MASTER_ADDR_OFFSET; + uint32_t JD_SLAVE_ADDR_OFFSET; + uint32_t JD_BOTH_ADDR_OFFSET; + bool JD_DISABLE_MASTER_TO_SLAVE; +}; + +enum jadard_input_protocol_type { + PROTOCOL_TYPE_A = 0, + PROTOCOL_TYPE_B, +}; + +struct jadard_report_data { + int touch_data_size; + int touch_coord_size; + uint8_t *touch_coord_info; +#ifdef JD_SANSUMG_PALM_EN + int touch_palm_size; + uint8_t *touch_palm_info; +#endif + uint8_t touch_state_info[JD_TOUCH_STATE_INFO_SIZE]; + uint8_t touch_stylus_info[JD_TOUCH_STYLUS_SIZE]; +#if defined(JD_SMART_WAKEUP) + uint8_t touch_event_info; +#endif +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + uint32_t report_rate_count; + uint8_t touch_all_info[JD_HID_TOUCH_DATA_SIZE]; +#endif +#if defined(JD_ESD_CHECK) + uint8_t crc_retry; + uint8_t crc_start; +#endif +}; + +struct jadard_stylus_host_data { +#ifdef JD_REPORT_FRAME_CHECK + uint8_t pen_frame; + uint8_t pre_pen_frame; +#endif + uint64_t pen_id; + int x; + int y; + int w; + int event; + int tilt_x; + int tilt_y; + uint32_t hover; + uint32_t btn; + uint32_t btn2; + uint32_t pre_btn; + uint32_t pre_btn2; + uint8_t battery_info; +}; + +struct jadard_host_data { +#ifdef JD_REPORT_FRAME_CHECK + uint8_t finger_frame; + uint8_t pre_finger_frame; +#endif + uint8_t finger_num; + uint8_t *id; + int *x; + int *y; + int *w; +#ifdef JD_SANSUMG_PALM_EN + int *maj; + int *min; +#endif + int *event; +#ifdef JD_SMART_WAKEUP + int SMWP_event_chk; +#endif + struct jadard_stylus_host_data stylus; +}; + +enum jadard_host_data_event{ + JD_DOWN_EVENT = 0, + JD_UP_EVENT, + JD_CONTACT_EVENT, + JD_NO_EVENT +}; + +enum jadard_finger_event{ + JD_ATTN_IN = 1, + JD_ATTN_OUT, +}; + +struct jadard_debug { + bool proc_send_flag; + bool *fw_dump_going; + void (*fp_touch_dbg_func)(struct jadard_ts_data *ts, uint8_t start); +}; + +enum jadard_panel_maker{ + JD_PANEL_MAKER_NUM = 0x12, + JD_PANEL_MAKER_LIST_SIZE = JD_PANEL_MAKER_NUM + 1, + JD_PANEL_MAKER_CP = 0xFE, + JD_PANEL_MAKER_COB = 0xFF, +}; + +enum JD_LCD_STATUS { + JD_LCD_STATUS_SLEEP_IN = 0, + JD_LCD_STATUS_SLEEP_OUT, + JD_LCD_STATUS_DISPLAY_OFF, + JD_LCD_STATUS_DISPLAY_ON, + JD_LCD_STATUS_ERROR +}; + +enum jadard_cascade_mode { + JD_CASCADE_MODE_DISABLE = 0, + JD_CASCADE_MODE_ENABLE = 1, +}; + +int jadard_chip_common_init(void); +void jadard_chip_common_deinit(void); +void jadard_common_proc_deinit(void); +void jadard_ts_work(struct jadard_ts_data *ts); +uint8_t jadard_DbicWriteDDReg(uint8_t cmd, uint8_t *rpar, uint8_t rpar_len); +uint8_t jadard_DbicReadDDReg(uint8_t cmd, uint8_t *rpar, uint8_t rpar_len); +uint8_t jadard_DbiWriteDDReg(uint8_t page, uint8_t cmd, uint8_t *par, uint8_t par_len); +uint8_t jadard_DbiReadDDReg(uint8_t page, uint8_t cmd, uint8_t *rpar, uint8_t rpar_len, uint32_t offset); +int jadard_report_data_init(void); +void jadard_report_points(struct jadard_ts_data *ts); +int jadard_distribute_touch_data(struct jadard_ts_data *ts, uint8_t *buf, int irq_event, int ts_status); +int jadard_parse_report_data(struct jadard_ts_data *ts, int irq_event, int ts_status); +void jadard_log_touch_state(const char **bit_map); +int jadard_input_register(struct jadard_ts_data *ts); + +#if defined(JD_USB_DETECT_GLOBAL) +void jadard_cable_detect(bool renew); +#endif + +#if defined(JD_USB_DETECT_CALLBACK) +void jadard_usb_status(int status, bool renew); +#endif + +extern int jadard_chip_common_suspend(struct jadard_ts_data *ts); +extern int jadard_chip_common_resume(struct jadard_ts_data *ts); +extern int jadard_parse_dt(struct jadard_ts_data *ts, + struct jadard_platform_data *pdata); +extern int jadard_dev_set(struct jadard_ts_data *ts); +extern int jadard_input_register_device(struct input_dev *input_dev); + +#if defined(JD_CONFIG_DRM) +extern int jadard_drm_check_dt(struct jadard_ts_data *ts); +#endif + +#ifdef CONFIG_TOUCHSCREEN_JADARD_DEBUG +extern int jadard_debug_init(void); +extern int jadard_debug_remove(void); +#endif + +#if defined(__JADARD_KMODULE__) +extern int jadard_common_init(void); +extern void jadard_common_exit(void); +#endif + +#endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_debug.c b/drivers/input/touchscreen/jdchipset/jadard_debug.c new file mode 100644 index 0000000000000..630eafc4f32ed --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_debug.c @@ -0,0 +1,2608 @@ +#include "jadard_common.h" +#include "jadard_module.h" +#include "jadard_debug.h" + +extern struct jadard_module_fp g_module_fp; +extern struct jadard_ts_data *pjadard_ts_data; +extern struct jadard_ic_data *pjadard_ic_data; +extern struct jadard_report_data *pjadard_report_data; +extern struct jadard_host_data *pjadard_host_data; +extern struct jadard_debug *pjadard_debug; +extern struct proc_dir_entry *pjadard_touch_proc_dir; +extern struct jadard_common_variable g_common_variable; + +#if !defined(JD_ZERO_FLASH) && defined(JD_UPGRADE_FW_ARRAY) +extern char *jd_i_CTPM_firmware_name; +extern uint8_t jd_i_firmware[]; +extern uint32_t jd_fw_size; +#endif + +static struct timespec64 timeStart, timeEnd, timeDelta; + +void jadard_log_touch_data(uint8_t finger_event) +{ + int i = 0; + int coord_size = pjadard_report_data->touch_coord_size; + uint8_t *buf = pjadard_report_data->touch_coord_info; + + if (finger_event == JD_ATTN_OUT) { + JD_I("finger_num = %d\n", pjadard_host_data->finger_num); + + if (buf != NULL) { + for (i = 0; i < coord_size; i += 5) { + if ((i + 4) < coord_size) { + JD_I("[%2d] 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", + i, buf[i + 0], buf[i + 1], buf[i + 2], buf[i + 3], buf[i + 4]); + } + } + } + + g_module_fp.fp_log_touch_state(); + } +} + +void jadard_log_touch_int_devation(int finger_event) +{ + if (finger_event == JD_ATTN_IN) { + ktime_get_ts64(&timeStart); + } else if (finger_event == JD_ATTN_OUT) { + ktime_get_ts64(&timeEnd); + timeDelta.tv_nsec = (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) - + (timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); + JD_I("Touch latency = %ld us\n", timeDelta.tv_nsec / 1000); + } +} + +void jadard_log_touch_event(struct jadard_ts_data *ts, uint8_t finger_event) +{ + int i = 0; + + if (finger_event == JD_ATTN_OUT) { + for (i = 0; i < pjadard_ic_data->JD_MAX_PT; i++) { + if (pjadard_host_data->event[i] == JD_DOWN_EVENT) { + JD_I("status: ID:%d Down, X:%d, Y:%d, W:%d\n", pjadard_host_data->id[i], + pjadard_host_data->x[i], pjadard_host_data->y[i], pjadard_host_data->w[i]); + } else if (pjadard_host_data->event[i] == JD_UP_EVENT) { + JD_I("status: ID:%d Up, X:%d, Y:%d\n", pjadard_host_data->id[i], + pjadard_host_data->x[i], pjadard_host_data->y[i]); + } + } + } +} + +void jadard_touch_dbg_func(struct jadard_ts_data *ts, uint8_t start) +{ + switch (ts->debug_log_touch_level) { + case 1: + jadard_log_touch_data(start); + break; + case 2: + jadard_log_touch_int_devation(start); + break; + case 3: + jadard_log_touch_event(ts, start); + break; + } +} + +static ssize_t jadard_debug_level_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 64) { + JD_E("%s: len size less than 64\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "debug_log_touch_level = %d\n", + pjadard_ts_data->debug_log_touch_level); + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +static ssize_t jadard_debug_level_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + ts->debug_log_touch_level = 0; + + if (buf_tmp[0] >= '0' && buf_tmp[0] <= '3') { + ts->debug_log_touch_level = (buf_tmp[0] - '0'); + } else { + JD_E("%s: Not support command!\n", __func__); + return -EINVAL; + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_debug_level_ops = { + .proc_read = jadard_debug_level_read, + .proc_write = jadard_debug_level_write, +}; +#else +static struct file_operations jadard_proc_debug_level_ops = { + .owner = THIS_MODULE, + .read = jadard_debug_level_read, + .write = jadard_debug_level_write, +}; +#endif + +static ssize_t jadard_fw_package_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t ret = 0; + char *buf_tmp = NULL; + int i = 0, tmp, packet_len; + + if (len < 1024) { + JD_E("%s: len size less than 1024\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + + if (buf_tmp != NULL) { + #if defined(JD_SANSUMG_PALM_EN) + packet_len = JD_HID_TOUCH_DATA_SIZE; + #else + if (pjadard_ic_data->JD_STYLUS_EN) { + packet_len = JD_HID_TOUCH_DATA_SIZE; + } else { + packet_len = JD_HID_TOUCH_DATA_SIZE - JD_TOUCH_STYLUS_SIZE; + } + #endif + + for (i = 0; i < packet_len; i++) { + tmp = i % 5; + + if (tmp == 0) { + ret += scnprintf(buf_tmp + ret, len - ret, "[%2d] 0x%02X", + i, pjadard_report_data->touch_all_info[i]); + } else if (tmp == 4) { + ret += scnprintf(buf_tmp + ret, len - ret, " 0x%02X\n", + pjadard_report_data->touch_all_info[i]); + } else { + ret += scnprintf(buf_tmp + ret, len - ret, " 0x%02X", + pjadard_report_data->touch_all_info[i]); + } + } + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +static ssize_t jadard_fw_package_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + if (buf_tmp[0] >= '1') { + pjadard_report_data->report_rate_count = 0; + pjadard_report_data->touch_all_info[1] = 0; + pjadard_report_data->touch_all_info[2] = 0; + ts->debug_fw_package_enable = true; + } else { + ts->debug_fw_package_enable = false; + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_fw_package_ops = { + .proc_read = jadard_fw_package_read, + .proc_write = jadard_fw_package_write, +}; +#else +static struct file_operations jadard_proc_fw_package_ops = { + .owner = THIS_MODULE, + .read = jadard_fw_package_read, + .write = jadard_fw_package_write, +}; +#endif + +static ssize_t jadard_reset_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + +#ifdef JD_RST_PIN_FUNC + if (buf_tmp[0] == '1') { + g_module_fp.fp_ic_reset(false, false); + } else if (buf_tmp[0] == '2') { + g_module_fp.fp_ic_reset(false, true); + } else if (buf_tmp[0] == '3') { + g_module_fp.fp_ic_reset(true, false); + } else if (buf_tmp[0] == '4') { + g_module_fp.fp_ic_reset(true, true); + } else +#endif + if (buf_tmp[0] == 's') { + g_module_fp.fp_ic_soft_reset(); + } else { + JD_E("%s: Not support command!\n", __func__); + return -EINVAL; + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_reset_ops = { + .proc_write = jadard_reset_write, +}; +#else +static struct file_operations jadard_proc_reset_ops = { + .owner = THIS_MODULE, + .write = jadard_reset_write, +}; +#endif + +static ssize_t jadard_attn_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + char *buf_tmp = NULL; + + if (len < 16) { + JD_E("%s: len size less than 16\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "attn = %d\n", + gpio_get_value(pjadard_ts_data->pdata->gpio_irq)); + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_attn_ops = { + .proc_read = jadard_attn_read, +}; +#else +static struct file_operations jadard_proc_attn_ops = { + .owner = THIS_MODULE, + .read = jadard_attn_read, +}; +#endif + +static ssize_t jadard_int_en_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 16) { + JD_E("%s: len size less than 16\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "irq = %d\n", ts->irq_enabled); + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +static ssize_t jadard_int_en_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + if (buf_tmp[0] == '0') { + jadard_int_en_set(false); + } else if (buf_tmp[0] == '1') { + jadard_int_en_set(true); + } else { + JD_E("%s: Not support command!\n", __func__); + return -EINVAL; + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_int_en_ops = { + .proc_read = jadard_int_en_read, + .proc_write = jadard_int_en_write, +}; +#else +static struct file_operations jadard_proc_int_en_ops = { + .owner = THIS_MODULE, + .read = jadard_int_en_read, + .write = jadard_int_en_write, +}; +#endif + +static void jadard_diag_arrange_print(struct seq_file *s, bool transpose, int i, int j, + struct jadard_diag_mutual_data *dump) +{ + if (transpose) { + if (dump == NULL) { + seq_printf(s, "%7d", jd_diag_mutual[i * pjadard_ic_data->JD_Y_NUM + j]); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "%7d", jd_diag_mutual[i * pjadard_ic_data->JD_Y_NUM + j]); + } + } else { + if (dump == NULL) { + seq_printf(s, "%7d", jd_diag_mutual[j * pjadard_ic_data->JD_Y_NUM + i]); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "%7d", jd_diag_mutual[j * pjadard_ic_data->JD_Y_NUM + i]); + } + } +} + +static void jadard_diag_arrange_row(struct seq_file *s, bool transpose, int i, int row_num, + struct jadard_diag_mutual_data *dump) +{ + int j, in_loop; + + if (transpose) + in_loop = pjadard_ic_data->JD_Y_NUM; + else + in_loop = pjadard_ic_data->JD_X_NUM; + + if (row_num > 0) { + for (j = row_num - 1; j >= 0; j--) + jadard_diag_arrange_print(s, transpose, i, j, dump); + + if (dump == NULL) { + seq_printf(s, "\n"); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "\n"); + } + } else { + for (j = 0; j < in_loop; j++) + jadard_diag_arrange_print(s, transpose, i, j, dump); + + if (dump == NULL) { + seq_printf(s, "\n"); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "\n"); + } + } +} + +static void jadard_diag_arrange_column(struct seq_file *s, bool transpose, int col_num, int row_num, + struct jadard_diag_mutual_data *dump) +{ + int i, out_loop; + + if (transpose) + out_loop = pjadard_ic_data->JD_X_NUM; + else + out_loop = pjadard_ic_data->JD_Y_NUM; + + if (col_num > 0) { + for (i = col_num - 1; i >= 0; i--) { + if (dump == NULL) { + seq_printf(s, "%4c%02d%c", '[', col_num - i, ']'); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "%4c%02d%c", '[', col_num - i, ']'); + } + + jadard_diag_arrange_row(s, transpose, i, row_num, dump); + } + } else { + for (i = 0; i < out_loop; i++) { + if (dump == NULL) { + seq_printf(s, "%4c%02d%c", '[', i + 1, ']'); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "%4c%02d%c", '[', i + 1, ']'); + } + jadard_diag_arrange_row(s, transpose, i, row_num, dump); + } + } +} + +static void jadard_diag_arrange(struct seq_file *s, int x_num, int y_num, + struct jadard_diag_mutual_data *dump) +{ + int i; + bool transpose = (bool)((diag_arr_num >> 2) & 0x01); + uint8_t y_reverse = (diag_arr_num >> 1) & 0x01; + uint8_t x_reverse = (diag_arr_num >> 0) & 0x01; + + if (((s == NULL) && (dump == NULL)) || ((s != NULL) && (dump != NULL))) { + JD_E("%s: Not support this condition\n", __func__); + return; + } + + if (dump == NULL) { + seq_printf(s, "%7c", ' '); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "%7c", ' '); + } + + if (transpose) { + for (i = 1 ; i <= y_num; i++) { + if (dump == NULL) { + seq_printf(s, "%4c%02d%c", '[', i, ']'); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "%4c%02d%c", '[', i, ']'); + } + } + + if (dump == NULL) { + seq_printf(s, "\n"); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "\n"); + } + jadard_diag_arrange_column(s, transpose, y_reverse * x_num, x_reverse * y_num, dump); + } else { + for (i = 1; i <= x_num; i++) { + if (dump == NULL) { + seq_printf(s, "%4c%02d%c", '[', i, ']'); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "%4c%02d%c", '[', i, ']'); + } + } + + if (dump == NULL) { + seq_printf(s, "\n"); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "\n"); + } + jadard_diag_arrange_column(s, transpose, y_reverse * y_num, x_reverse * x_num, dump); + } + + if (dump == NULL) { + seq_printf(s, "\nChannelEnd\n"); + } else { + dump->write_len += scnprintf(dump->buf + dump->write_len, + dump->buf_len - dump->write_len, "\n"); + } +} + +static void *jadard_diag_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) { + return NULL; + } + + return (void *)((unsigned long) *pos + 1); +} + +static void jadard_diag_seq_stop(struct seq_file *s, void *v) +{ + /* Nothing to do */ +} + +static void *jadard_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; /* if retun NULL, next step will stop */ +} + +static int jadard_diag_seq_show(struct seq_file *s, void *v) +{ + int x_num = pjadard_ic_data->JD_X_NUM; + int y_num = pjadard_ic_data->JD_Y_NUM; + + seq_printf(s, "ChannelStart: %4d, %4d\n", x_num, y_num); + jd_diag_mutual_cnt &= 0x7FFF; + seq_printf(s, "Frame: %d\n", jd_diag_mutual_cnt); + jadard_diag_arrange(s, x_num, y_num, NULL); + + return 0; +} + +/* start->show->next->stop */ +static struct seq_operations jadard_diag_seq_ops = { + .start = jadard_diag_seq_start, + .stop = jadard_diag_seq_stop, + .next = jadard_diag_seq_next, + .show = jadard_diag_seq_show, +}; + +static int jadard_diag_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &jadard_diag_seq_ops); +}; + +/* Mutual data thread */ +static bool jadard_ts_diag_func(void) +{ + uint32_t index = 0; + int i, j, new_data; + uint8_t *rdata = NULL; + int x_num = pjadard_ic_data->JD_X_NUM; + int y_num = pjadard_ic_data->JD_Y_NUM; + uint16_t rdata_size = x_num * y_num * sizeof(uint16_t); + int *PeakMax = NULL; + int *PeakMin = NULL; + + rdata = kzalloc(rdata_size * sizeof(uint8_t), GFP_KERNEL); + if (rdata == NULL) { + JD_E("%s, rdata memory allocate fail: %d\n", __func__, __LINE__); + return false; + } + + if (KeepType == JD_KEEP_TYPE_PeakValue) { + PeakMax = kzalloc(y_num * x_num * sizeof(int), GFP_KERNEL); + if (PeakMax == NULL) { + JD_E("%s, PeakMax memory allocate fail: %d\n", __func__, __LINE__); + kfree(rdata); + return false; + } + + PeakMin = kzalloc(y_num * x_num * sizeof(int), GFP_KERNEL); + if (PeakMin == NULL) { + JD_E("%s, PeakMin memory allocate fail: %d\n", __func__, __LINE__); + kfree(rdata); + kfree(PeakMax); + return false; + } + } + + if (g_module_fp.fp_get_mutual_data(DataType, rdata, rdata_size) < 0) { + /* Time out, set -23131(Blue screen) */ + for (i = 0; i < x_num * y_num; i++) { + jd_diag_mutual[i] = -23131; + } + + kfree(rdata); + if (KeepType == JD_KEEP_TYPE_PeakValue) { + kfree(PeakMax); + kfree(PeakMin); + } + jd_diag_mutual_cnt++; + + return false; + } + + for (i = 0; i < y_num; i++) { + for (j = 0; j < x_num; j++) { + if (DataType == JD_DATA_TYPE_Difference || DataType == JD_DATA_TYPE_LAPLACE) { + if (pjadard_ts_data->rawdata_little_endian) { + new_data = (((int8_t)rdata[index + 1] << 8) | rdata[index]); + } else { + new_data = (((int8_t)rdata[index] << 8) | rdata[index + 1]); + } + } else { + if (pjadard_ts_data->rawdata_little_endian) { + new_data = (((uint8_t)rdata[index + 1] << 8) | rdata[index]); + } else { + new_data = (((uint8_t)rdata[index] << 8) | rdata[index + 1]); + } + } + + /* KeepType => 1:NormalValue 2:MaxValue 3:MinValue 4:PeakValue */ + if (KeepType == JD_KEEP_TYPE_NormalValue) { + jd_diag_mutual[i * x_num + j] = new_data; + } else if (KeepType == JD_KEEP_TYPE_MaxValue) { + if (jd_diag_mutual[i * x_num + j] < new_data) + jd_diag_mutual[i * x_num + j] = new_data; + } else if (KeepType == JD_KEEP_TYPE_MinValue) { + if (jd_diag_mutual[i * x_num + j] > new_data) + jd_diag_mutual[i * x_num + j] = new_data; + } else if (KeepType == JD_KEEP_TYPE_PeakValue) { + if (new_data > PeakMax[i * x_num + j]) + PeakMax[i * x_num + j] = new_data; + else if (new_data < PeakMin[i * x_num + j]) + PeakMin[i * x_num + j] = new_data; + + new_data = PeakMax[i * x_num + j] - PeakMin[i * x_num + j]; + + if (jd_diag_mutual[i * x_num + j] < new_data) + jd_diag_mutual[i * x_num + j] = new_data; + } + + index += 2; + } + } + kfree(rdata); + /* Free memory */ + if (PeakMax) { + kfree(PeakMax); + } + /* Free memory */ + if (PeakMin) { + kfree(PeakMin); + } + + if ((KeepFrame > 0) && (KeepFrame > jd_diag_mutual_cnt)) { +#ifdef JD_KEEP_RAWDATA_DISABLE + struct jadard_diag_mutual_data dump; + + dump.buf_len = x_num * y_num * 10; + dump.buf = kzalloc(dump.buf_len * sizeof(char), GFP_KERNEL); + if (dump.buf == NULL) { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + return false; + } + + dump.write_len = 0; + jd_diag_mutual_cnt++; + + if (jd_diag_mutual_cnt == 1) { + dump.write_len += scnprintf(dump.buf + dump.write_len, + dump.buf_len - dump.write_len, "ChannelStart: %4d, %4d\n", x_num, y_num); + } + + dump.write_len += scnprintf(dump.buf + dump.write_len, + dump.buf_len - dump.write_len, "Frame: %d\n", jd_diag_mutual_cnt); + + jadard_diag_arrange(NULL, x_num, y_num, &dump); + + if (jd_diag_mutual_cnt == KeepFrame) { + dump.write_len += scnprintf(dump.buf + dump.write_len, + dump.buf_len - dump.write_len, "ChannelEnd\n"); + } + + /* save mutual data in file */ + if (!IS_ERR(jd_diag_mutual_fn)) { +#if defined(__JADARD_GKI__) + JD_I("Cancel write keep rawdata file for GKI\n"); +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + kernel_write(jd_diag_mutual_fn, dump.buf, dump.write_len, &jd_diag_mutual_fn->f_pos); +#else + kernel_write(jd_diag_mutual_fn, dump.buf, dump.write_len, jd_diag_mutual_fn->f_pos); + jd_diag_mutual_fn->f_pos += dump.write_len; +#endif +#endif + } + kfree(dump.buf); + dump.buf = NULL; +#endif + } else { + jd_diag_mutual_cnt++; + } + + return true; +} + +/* Mutual data thread */ +static bool jadard_ts_buf_func(void) +{ + uint16_t index = 0; + int x_num = pjadard_ic_data->JD_X_NUM; + int y_num = pjadard_ic_data->JD_Y_NUM; + uint16_t rdata_size = x_num * y_num * buf_rd_byte_num; + + if (g_module_fp.fp_get_mutual_data(DataType, jd_buf, rdata_size) < 0) { + /* Time out, set -23131(Blue screen) */ + for (index = 0; index < rdata_size; index++) + jd_buf[index] = 0xA5; + + jd_diag_mutual_cnt++; + + return false; + } + + jd_diag_mutual_cnt++; + + return true; +} + +static void jadard_ts_diag_work_func(struct work_struct *work) +{ + while (pjadard_ts_data->diag_thread_active) { + if (jd_g_buf_rd_enable) { + if (!jadard_ts_buf_func()) + JD_E("%s : Read mutual data fail\n", __func__); + } else { + if (!jadard_ts_diag_func()) + JD_E("%s : Get mutual data fail\n", __func__); + } + } +} + +/* + * DataType => 1:RawData 2:Baseline 3:Difference 4:Listen 5:Label 6:Laplace Reserve:7~F(15) + * KeepType => 1:NormalValue 2:MaxValue 3:MinValue 4:PeakValue + * KeepFrame => Number(Disable:0, Enable:1 ~ 2000) + * + * Example: echo 0_0_0 > /proc/jadard_touch/diag + * Stop diag thread and set MCU into report coordinate mode + * Example: echo 1_2_0 > /proc/jadard_touch/diag + * Set DataType = 1, KeepType = 2, KeepFrame = 0(Disable) + * Example: echo 1_2_100 > /proc/jadard_touch/diag + * Set DataType = 1, KeepType = 2, KeepFrame = 100 + * KeepFrame data will save to "/sdcard/JD_XXX_Dump.txt" + */ +static ssize_t jadard_diag_write(struct file *filp, const char __user *buf, + size_t len, loff_t *data) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[20] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (len == 0) { + JD_I("%s: no command equal 0 char.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len - 1)) { + return -EFAULT; + } + + /* Cancel mutual data thread, if exist */ + if (pjadard_ts_data->diag_thread_active) { + pjadard_ts_data->diag_thread_active = false; + cancel_delayed_work_sync(&pjadard_ts_data->jadard_diag_delay_wrok); + } + ts->debug_diag_apk_enable = false; + jd_g_buf_rd_enable = false; + + DataType = JD_DATA_TYPE_RawData; + KeepType = JD_KEEP_TYPE_NormalValue; + KeepFrame = 0; + + if ((len >= 6) && (len <= 9)) { + if ((buf_tmp[1] == '_') && (buf_tmp[3] == '_')) { + if ((buf_tmp[0] >= 48) && (buf_tmp[0] <= 57)) { /* 0~9 */ + DataType = buf_tmp[0] - '0'; + } else if ((buf_tmp[0] >= 65) && (buf_tmp[0] <= 70)) { /* A~F */ + DataType = buf_tmp[0] - 'A' + 10; + } else if ((buf_tmp[0] >= 97) && (buf_tmp[0] <= 102)) { /* a~f */ + DataType = buf_tmp[0] - 'a' + 10; + } + KeepType = buf_tmp[2] - '0'; + + if (len == 6) { + KeepFrame = buf_tmp[4] - '0'; + } else if (len == 7) { + KeepFrame = (buf_tmp[4] - '0') * 10 + (buf_tmp[5] - '0'); + } else if (len == 8) { + KeepFrame = (buf_tmp[4] - '0') * 100 + (buf_tmp[5] - '0') * 10 + + (buf_tmp[6] - '0'); + } else { + KeepFrame = (buf_tmp[4] - '0') * 1000 + (buf_tmp[5] - '0') * 100 + + (buf_tmp[6] - '0') * 10 + (buf_tmp[7] - '0'); + } + + if (KeepFrame > 2000) + KeepFrame = 2000; + } else { + JD_E("%s: Not support command:<%s>\n", __func__, buf_tmp); + return -EINVAL; + } + } else { + JD_E("%s: Not support command:<%s>\n", __func__, buf_tmp); + return -EINVAL; + } + + JD_I("%s: DataType:%d, KeepType:%d, KeepFrame:%d\n", __func__, DataType, KeepType, KeepFrame); + +#ifndef JD_KEEP_RAWDATA_DISABLE + if (KeepFrame > 0) { + JD_I("%s: Keep rawdata was disable, please using JDMT APK\n", __func__); + return len; + } +#endif + /* Check DataType and KeepType were available */ + if ((DataType < 1) || (DataType > 15) || (KeepType < 1) || (KeepType > 4)) { + if ((DataType != 0) || (KeepType != 0)) { + JD_E("%s: DataType must (0~F) and KeepType must (0~4)\n", __func__); + return -EINVAL; + } + } + + if (jd_diag_mutual) { + memset(jd_diag_mutual, 0x00, pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM * sizeof(int)); + } else { + JD_E("%s, jd_diag_mutual memory allocate fail: %d\n", __func__, __LINE__); + return len; + } + + if ((DataType > 0) && (KeepType > 0)) { + /* 1. Set mutual data type */ + g_module_fp.fp_mutual_data_set((uint8_t)DataType); + +#ifdef JD_KEEP_RAWDATA_DISABLE + /* 1.1 Open file for save mutual data log, if KeepFrame > 0 */ + if (KeepFrame > 0) { + switch (DataType) { + case JD_DATA_TYPE_RawData: + jd_diag_mutual_fn = filp_open(JD_RAWDATA_DUMP_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0); + jd_diag_mutual_fn->f_pos = 0; + break; + case JD_DATA_TYPE_Baseline: + jd_diag_mutual_fn = filp_open(JD_BASE_DUMP_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0); + jd_diag_mutual_fn->f_pos = 0; + break; + case JD_DATA_TYPE_Difference: + jd_diag_mutual_fn = filp_open(JD_DIFF_DUMP_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0); + jd_diag_mutual_fn->f_pos = 0; + break; + case JD_DATA_TYPE_LISTEN: + jd_diag_mutual_fn = filp_open(JD_LISTEN_DUMP_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0); + jd_diag_mutual_fn->f_pos = 0; + break; + case JD_DATA_TYPE_LABEL: + jd_diag_mutual_fn = filp_open(JD_LABEL_DUMP_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0); + jd_diag_mutual_fn->f_pos = 0; + case JD_DATA_TYPE_LAPLACE: + jd_diag_mutual_fn = filp_open(JD_LAPLACE_DUMP_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0); + jd_diag_mutual_fn->f_pos = 0; + break; + default: + JD_I("%s: Data type is not support. DataType is %d \n", __func__, DataType); + } + } +#endif + /* 2. Start mutual data thread */ + jadard_int_enable(false); + msleep(1000); + pjadard_ts_data->diag_thread_active = true; + + g_module_fp.fp_EnterBackDoor(); + JD_I("Enter backdoor\n"); + + jd_diag_mutual_cnt = 0; + queue_delayed_work(pjadard_ts_data->jadard_diag_wq, + &pjadard_ts_data->jadard_diag_delay_wrok, msecs_to_jiffies(1000)); + JD_I("%s: Start get mutual data\n", __func__); + jadard_int_enable(true); + +#ifdef JD_KEEP_RAWDATA_DISABLE + if (KeepFrame > 0) { + /* 2.1 Wait data ready */ + while (KeepFrame > jd_diag_mutual_cnt) { + msleep(100); + } + + switch (DataType) { + case JD_DATA_TYPE_RawData: + JD_I("%s: Save file to %s\n", __func__, JD_RAWDATA_DUMP_FILE); + break; + case JD_DATA_TYPE_Baseline: + JD_I("%s: Save file to %s\n", __func__, JD_BASE_DUMP_FILE); + break; + case JD_DATA_TYPE_Difference: + JD_I("%s: Save file to %s\n", __func__, JD_DIFF_DUMP_FILE); + break; + case JD_DATA_TYPE_LISTEN: + JD_I("%s: Save file to %s\n", __func__, JD_LISTEN_DUMP_FILE); + break; + case JD_DATA_TYPE_LABEL: + JD_I("%s: Save file to %s\n", __func__, JD_LABEL_DUMP_FILE); + break; + case JD_DATA_TYPE_LAPLACE: + JD_I("%s: Save file to %s\n", __func__, JD_LAPLACE_DUMP_FILE); + break; + default: + JD_I("%s: Data type is not support. DataType is %d \n", __func__, DataType); + } + + if (jd_diag_mutual_fn != NULL) { + filp_close(jd_diag_mutual_fn, NULL); + jd_diag_mutual_fn = NULL; + } + + /* 3. Stop thread */ + if (pjadard_ts_data->diag_thread_active) { + pjadard_ts_data->diag_thread_active = false; + cancel_delayed_work_sync(&pjadard_ts_data->jadard_diag_delay_wrok); + } + } +#endif + } else if ((DataType == 0) && (KeepType == 0) && (KeepFrame == 0)) { + g_module_fp.fp_mutual_data_set(JD_DATA_TYPE_RawData); + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_diag_ops = { + .proc_open = jadard_diag_proc_open, + .proc_read = seq_read, + .proc_release = seq_release, + .proc_write = jadard_diag_write, +}; +#else +static struct file_operations jadard_proc_diag_ops = { + .owner = THIS_MODULE, + .open = jadard_diag_proc_open, + .read = seq_read, + .release = seq_release, + .write = jadard_diag_write, +}; +#endif + +static ssize_t jadard_diag_arrange_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 32) { + JD_E("%s: len size less than 32\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + ret += scnprintf(buf_tmp + ret, len - ret, "diag_arr_num = %d\n", diag_arr_num); + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +/* + * Bit0: X reverse + * Bit1: Y reverse + * Bit2: Transpose + * Example: echo 5 > /proc/jadard_touch/diag_arr + * Transpose and X reverse + */ +static ssize_t jadard_diag_arrange_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + diag_arr_num = buf_tmp[0] - '0'; + + if ((diag_arr_num > 7) || (diag_arr_num < 0)) { + diag_arr_num = 0; + JD_E("%s: Not support command, set to 0\n", __func__); + } + + JD_I("%s: diag_arr_num = %d \n", __func__, diag_arr_num); + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_diag_arrange_ops = { + .proc_read = jadard_diag_arrange_read, + .proc_write = jadard_diag_arrange_write, +}; +#else +static struct file_operations jadard_proc_diag_arrange_ops = { + .owner = THIS_MODULE, + .read = jadard_diag_arrange_read, + .write = jadard_diag_arrange_write, +}; +#endif + +static void *jadard_diag_apk_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) { + return NULL; + } + + return (void *)((unsigned long) *pos + 1); +} + +static void jadard_diag_apk_seq_stop(struct seq_file *s, void *v) +{ + /* Nothing to do */ +} + +static void *jadard_diag_apk_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; /* if retun NULL, next step will stop */ +} + +static int jadard_diag_apk_seq_show(struct seq_file *s, void *v) +{ + int x_num = pjadard_ic_data->JD_X_NUM; + int y_num = pjadard_ic_data->JD_Y_NUM; + int i, j; + + seq_printf(s, "%d %d ", x_num, y_num); + jd_diag_mutual_cnt &= 0x7FFF; + seq_printf(s, "%d ", jd_diag_mutual_cnt); + + for (i = 0; i < y_num; i++) { + for (j = 0; j < x_num; j++) { + seq_printf(s, "%d ", jd_diag_mutual[j * y_num + i]); + } + } + + for (i = 0; i < JD_HID_TOUCH_DATA_SIZE; i++) { + seq_printf(s, "0x%02X ", pjadard_report_data->touch_all_info[i]); + } + + seq_printf(s, "\n"); + + return 0; +} + +/* start->show->next->stop */ +static struct seq_operations jadard_diag_apk_seq_ops = { + .start = jadard_diag_apk_seq_start, + .stop = jadard_diag_apk_seq_stop, + .next = jadard_diag_apk_seq_next, + .show = jadard_diag_apk_seq_show, +}; + +static int jadard_diag_apk_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &jadard_diag_apk_seq_ops); +}; + +/* + * DataType => 1:RawData 2:Baseline 3:Difference 4:Listen 5:Label 6:Laplace Reserve:7~F(15) + */ +static ssize_t jadard_diag_apk_write(struct file *filp, const char __user *buf, + size_t len, loff_t *data) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (len == 0) { + JD_I("%s: no command equal 0 char.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len - 1)) { + return -EFAULT; + } + + /* Cancel mutual data thread, if exist */ + if (pjadard_ts_data->diag_thread_active) { + pjadard_ts_data->diag_thread_active = false; + cancel_delayed_work_sync(&pjadard_ts_data->jadard_diag_delay_wrok); + } + ts->debug_fw_package_enable = false; + ts->debug_diag_apk_enable = false; + + DataType = JD_DATA_TYPE_RawData; + KeepType = JD_KEEP_TYPE_NormalValue; + + if ((len > 1)) { + if ((buf_tmp[0] >= 48) && (buf_tmp[0] <= 57)) { /* 0~9 */ + DataType = buf_tmp[0] - '0'; + } else if ((buf_tmp[0] >= 65) && (buf_tmp[0] <= 70)) { /* A~F */ + DataType = buf_tmp[0] - 'A' + 10; + } else if ((buf_tmp[0] >= 97) && (buf_tmp[0] <= 102)) { /* a~f */ + DataType = buf_tmp[0] - 'a' + 10; + } + } else { + JD_E("%s: Not support command:<%s>, len:%zu\n", __func__, buf_tmp, len); + return -EINVAL; + } + + JD_I("%s: DataType:%d\n", __func__, DataType); + + /* Check DataType was available */ + if ((DataType < 1) || (DataType > 15)) { + if (DataType != 0) { + JD_E("%s: DataType must (0~F)\n", __func__); + return -EINVAL; + } + } + + if (jd_diag_mutual) { + memset(jd_diag_mutual, 0x00, pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM * sizeof(int)); + } else { + JD_E("%s, jd_diag_mutual memory allocate fail: %d\n", __func__, __LINE__); + return len; + } + + if (DataType > 0) { + ts->debug_diag_apk_enable = true; + /* 1. Set mutual data type */ + g_module_fp.fp_mutual_data_set((uint8_t)DataType); + + /* 2. Start mutual data thread */ + jd_diag_mutual_cnt = 0; + JD_I("%s: Start get mutual data\n", __func__); + + pjadard_report_data->report_rate_count = 0; + pjadard_report_data->touch_all_info[1] = 0; + pjadard_report_data->touch_all_info[2] = 0; + ts->debug_fw_package_enable = true; + } else { /* DataType == 0 */ + g_module_fp.fp_mutual_data_set(JD_DATA_TYPE_RawData); + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_diag_apk_ops = { + .proc_open = jadard_diag_apk_proc_open, + .proc_read = seq_read, + .proc_release = seq_release, + .proc_write = jadard_diag_apk_write, +}; +#else +static struct file_operations jadard_proc_diag_apk_ops = { + .owner = THIS_MODULE, + .open = jadard_diag_apk_proc_open, + .read = seq_read, + .release = seq_release, + .write = jadard_diag_apk_write, +}; +#endif + +static void *jadard_buf_rd_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos >= 1) { + return NULL; + } + + return (void *)((unsigned long) *pos + 1); +} + +static void jadard_buf_rd_seq_stop(struct seq_file *s, void *v) +{ + /* Nothing to do */ +} + +static void *jadard_buf_rd_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + (*pos)++; + return NULL; /* if retun NULL, next step will stop */ +} + +static int jadard_buf_rd_seq_show(struct seq_file *s, void *v) +{ + int index, i; + int x_num = pjadard_ic_data->JD_X_NUM; + int y_num = pjadard_ic_data->JD_Y_NUM; + + //seq_printf(s, "%d %d ", x_num, y_num); + jd_diag_mutual_cnt &= 0x7FFF; + seq_printf(s, "%d ", jd_diag_mutual_cnt); + + for (index = 0; index < x_num * y_num * buf_rd_byte_num; index += buf_rd_byte_num) { + for (i = buf_rd_byte_num - 1; i >= 0; i--) + seq_printf(s, "%02X", jd_buf[index + i]); + seq_printf(s, " "); + } + + seq_printf(s, "\n"); + + return 0; +} + +/* start->show->next->stop */ +static struct seq_operations jadard_buf_rd_seq_ops = { + .start = jadard_buf_rd_seq_start, + .stop = jadard_buf_rd_seq_stop, + .next = jadard_buf_rd_seq_next, + .show = jadard_buf_rd_seq_show, +}; + +static int jadard_buf_rd_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &jadard_buf_rd_seq_ops); +}; + +/* + * DataType => 1:RawData 2:Baseline 3:Difference 4:Listen 5:Label 6:Laplace Reserve:7~F(15) + */ +static ssize_t jadard_buf_rd_write(struct file *filp, const char __user *buf, + size_t len, loff_t *data) +{ + //struct jadard_ts_data *ts = pjadard_ts_data; + char buf_tmp[10] = {0}; + uint32_t type = 0; + int i; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (len == 0) { + JD_I("%s: no command equal 0 char.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len - 1)) { + return -EFAULT; + } + + if ((buf_tmp[0] == 't') && (buf_tmp[1] == ' ')) { + /* Cancel mutual data thread, if exist */ + if (pjadard_ts_data->diag_thread_active) { + pjadard_ts_data->diag_thread_active = false; + cancel_delayed_work_sync(&pjadard_ts_data->jadard_diag_delay_wrok); + } + jd_g_buf_rd_enable = false; + + //DataType = 0; + for (i = 2; i < len - 1; i++) { + uint8_t byte = buf_tmp[i]; + if (byte >= '0' && byte <= '9') { /* 0~9 */ + byte = byte - '0'; + } else if (byte >= 'A' && byte <= 'F') { /* A~F */ + byte = byte - 'A' + 10; + } else if (byte >= 'a' && byte <= 'f') { /* a~f */ + byte = byte - 'a' + 10; + } + type = (type << 4) | (byte & 0xF); + } + DataType = (int)type; + + JD_I("%s: DataType:%d\n", __func__, DataType); + + if (DataType > 0) { + /* 1. Set mutual data type */ + g_module_fp.fp_mutual_data_set((uint8_t)DataType); + /* 2. Start mutual data thread */ + jadard_int_enable(false); + msleep(1000); + pjadard_ts_data->diag_thread_active = true; + jd_g_buf_rd_enable = true; + + g_module_fp.fp_EnterBackDoor(); + JD_I("Enter backdoor\n"); + + jd_diag_mutual_cnt = 0; + queue_delayed_work(pjadard_ts_data->jadard_diag_wq, + &pjadard_ts_data->jadard_diag_delay_wrok, msecs_to_jiffies(1000)); + JD_I("%s: Start get mutual data\n", __func__); + jadard_int_enable(true); + } else if (DataType == 0) { + g_module_fp.fp_mutual_data_set(JD_DATA_TYPE_RawData); + } + } else if ((buf_tmp[0] == 'b') && (buf_tmp[1] == ' ')) { + buf_rd_byte_num = buf_tmp[2] - '0'; + + if ((buf_rd_byte_num != 4) && (buf_rd_byte_num != 2)) { + JD_E("%s: Not support num = %d, set to 2\n", __func__, buf_rd_byte_num); + buf_rd_byte_num = 2; + } + + JD_I("%s: buf_rd_byte_num = %d \n", __func__, buf_rd_byte_num); + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_buf_rd_ops = { + .proc_open = jadard_buf_rd_proc_open, + .proc_read = seq_read, + .proc_release = seq_release, + .proc_write = jadard_buf_rd_write, +}; +#else +static struct file_operations jadard_proc_buf_rd_ops = { + .owner = THIS_MODULE, + .open = jadard_buf_rd_proc_open, + .read = seq_read, + .release = seq_release, + .write = jadard_buf_rd_write, +}; +#endif + +static ssize_t jadard_proc_fw_dump_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + char *buf_tmp = NULL; + + if (len < 64) { + JD_E("%s: len size less than 64\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + if (fw_dump_going && (!fw_dump_complete)) { + ret += scnprintf(buf_tmp + ret, len - ret, "Please wait a moment\n"); + ret += scnprintf(buf_tmp + ret, len - ret, "FW dump is running\n"); + } else if ((!fw_dump_going) && fw_dump_complete) { + ret += scnprintf(buf_tmp + ret, len - ret, "FW dump finish\n"); + } + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +static void jadard_ts_fw_dump_work_func(struct work_struct *work) +{ +#if defined(__JADARD_GKI__) + JD_I("Cancel dump fw bin for GKI\n"); +#else + struct file *fn; + uint32_t read_len; + uint8_t i, chip_num = 1; + + JD_I("%s: enter\n", __func__); + + jadard_int_enable(false); + fw_dump_going = true; + +#ifdef JD_ZERO_FLASH + if (pjadard_ic_data->JD_MODULE_CASCADE_MODE == JD_CASCADE_MODE_ENABLE) { + chip_num = 2; + } +#endif + + for (i = 0; i < chip_num; i++) { +#ifdef JD_ZERO_FLASH + read_len = g_common_variable.RAM_LEN; + if (i == 1) { + g_module_fp.fp_ram_read(pjadard_ic_data->JD_SLAVE_ADDR_OFFSET, fw_buffer, read_len); + } else { + g_module_fp.fp_ram_read(pjadard_ic_data->JD_MASTER_ADDR_OFFSET, fw_buffer, read_len); + } +#else + read_len = g_common_variable.FW_SIZE; + g_module_fp.fp_flash_read(0, fw_buffer, read_len); +#endif + JD_I("%s: Read FW from chip complete\n", __func__); + + if (i == 1) { + fn = filp_open(JD_SLAVE_FW_DUMP_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0); + } else { + fn = filp_open(JD_MASTER_FW_DUMP_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0); + } + + if (!IS_ERR(fn)) { + JD_I("%s: create file and ready to write\n", __func__); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + kernel_write(fn, fw_buffer, read_len * sizeof(uint8_t), &fn->f_pos); +#else + kernel_write(fn, fw_buffer, read_len * sizeof(uint8_t), fn->f_pos); +#endif + filp_close(fn, NULL); + + if (i == 1) { + JD_I("%s: Save data to %s\n", __func__, JD_SLAVE_FW_DUMP_FILE); + } else { + JD_I("%s: Save data to %s\n", __func__, JD_MASTER_FW_DUMP_FILE); + } + } + } + + jadard_int_enable(true); + fw_dump_going = false; +#endif + fw_dump_complete = true; + fw_dump_busy = false; +} + +/* + * Dump FW(by flash/ram) then Save data to "JD_FW_DUMP_FILE" + */ +static ssize_t jadard_proc_fw_dump_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[10] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + JD_I("%s: buf_tmp = %s\n", __func__, buf_tmp); + + if (fw_dump_busy) { + JD_E("%s: FW dump is busy, reject request!\n", __func__); + return len; + } + + if (buf_tmp[0] == '1') { + fw_dump_busy = true; + fw_dump_complete = false; + + queue_work(pjadard_ts_data->fw_dump_wq, &pjadard_ts_data->fw_dump_work); + } else { + JD_E("%s: Not support command!\n", __func__); + return -EINVAL; + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_fw_dump_ops = { + .proc_read = jadard_proc_fw_dump_read, + .proc_write = jadard_proc_fw_dump_write, +}; +#else +static struct file_operations jadard_proc_fw_dump_ops = { + .owner = THIS_MODULE, + .read = jadard_proc_fw_dump_read, + .write = jadard_proc_fw_dump_write, +}; +#endif + +static ssize_t jadard_proc_register_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + uint8_t *rdata = NULL; + uint32_t ReadAddr; + char *buf_tmp = NULL; + int i; + + if (len < 2048) { + JD_E("%s: len size less than 2048\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + /* Read data from chip */ + if (reg_read_len == 0) { + /* if reg_read_len = 0, default 1 */ + reg_read_len = 1; + } + + rdata = kzalloc(reg_read_len * sizeof(char), GFP_KERNEL); + if (rdata == NULL) { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + return ret; + } + + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + ReadAddr = (reg_cmd[3] << 24) + (reg_cmd[2] << 16) + (reg_cmd[1] << 8) + reg_cmd[0]; + + if (g_module_fp.fp_register_read(ReadAddr, rdata, reg_read_len) == JD_READ_LEN_OVERFLOW) { + ret += scnprintf(buf_tmp + ret, len - ret, "Read length was overflow\n"); + } else { + /* Set output data */ + ret += scnprintf(buf_tmp + ret, len - ret, "Register: %02X,%02X,%02X,%02X\n", + reg_cmd[3], reg_cmd[2], reg_cmd[1], reg_cmd[0]); + + for (i = 0; i < reg_read_len; i++) { + ret += scnprintf(buf_tmp + ret, len - ret, "0x%2.2X ", rdata[i]); + + if ((i % 16) == 15) + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + } + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + } + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + kfree(rdata); + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +/* + * Example: Only support lower case + * ADDRESS: 1~4 byte size, according to the chip of HW design + * Write register: echo w:xADDRESS:x11:x22:x33 > /proc/jadard_touch/register + * write ADDRESS 3bytes data(0x11,0x22,0x33), MAX:64bytes + * Read register: echo r:xADDRESS:x1F > /proc/jadard_touch/register + * read ADDRESS 0x1F(31)bytes, MAX:0xFF + */ +static ssize_t jadard_proc_register_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[64 * 4 + 8] = {0}; + char tok_data[64 * 4 + 8] = {0}; + char *p_tok_data = tok_data; + char *token = NULL; + char *const delim = ":"; + uint8_t w_data[64]; + int w_data_len = 0; + unsigned long result = 0; + bool reg_addr = true; + bool format_err = false; + char temp[4]; + int i; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (len == 0) { + JD_I("%s: no command equal 0 char.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len - 1)) { + return -EFAULT; + } + + JD_I("%s: buf_tmp = %s\n", __func__, buf_tmp); + + if ((buf_tmp[0] == 'r' || buf_tmp[0] == 'w') && buf_tmp[1] == ':' && buf_tmp[2] == 'x') { + memset(w_data, 0x00, sizeof(w_data)); + memcpy(p_tok_data, buf_tmp + 3, strlen(buf_tmp) - 3); + + while ((token = strsep(&p_tok_data, delim)) != NULL) { + /* I("token=%s, strlen(token)=%d\n", token, (int)strlen(token)); */ + if (reg_addr) { + /* Save register addrress */ + if (strlen(token) % 2 == 0) { + memset(reg_cmd, 0x00, sizeof(reg_cmd)); + reg_cmd_len = (uint8_t)(strlen(token) / 2); + memset(temp, 0x00, sizeof(temp)); + + for (i = 0; i < reg_cmd_len; i++) { + memcpy(temp, token + i * 2, 2); + + if (!kstrtoul(temp, 16, &result)) { + reg_cmd[reg_cmd_len - 1 - i] = result; + } else { + format_err = true; + break; + } + } + } else { + format_err = true; + } + + reg_addr = false; + } else { + /* Save register data */ + if ((token[0] == 'x') && (strlen(token) == 3)) { + memset(temp, 0x00, sizeof(temp)); + memcpy(temp, token + 1, 2); + + if (!kstrtoul(temp, 16, &result)) { + if (buf_tmp[0] == 'w') { + w_data[w_data_len++] = (uint8_t)result; + } else { + reg_read_len = (uint8_t)result; + break; + } + } else { + format_err = true; + } + } else { + format_err = true; + } + } + + if (format_err) { + JD_E("%s: (%s)Command format error!\n", __func__, token); + return -EINVAL; + } + } + + if (buf_tmp[0] == 'w') { + uint32_t WriteAddr = (reg_cmd[3] << 24) + (reg_cmd[2] << 16) + + (reg_cmd[1] << 8) + reg_cmd[0]; + + if (g_module_fp.fp_register_write(WriteAddr, w_data, w_data_len) < 0) { + JD_E("%s: Write register(%x) fail!\n", __func__, WriteAddr); + } + } + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_register_ops = { + .proc_read = jadard_proc_register_read, + .proc_write = jadard_proc_register_write, +}; +#else +static struct file_operations jadard_proc_register_ops = { + .owner = THIS_MODULE, + .read = jadard_proc_register_read, + .write = jadard_proc_register_write, +}; +#endif + +static ssize_t jadard_proc_display_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + uint8_t *rdata = NULL; + char *buf_tmp = NULL; + int i; + + if (len < 2048) { + JD_E("%s: len size less than 2048\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + /* Read data from chip */ + if (dd_reg_read_len == 0) { + /* if reg_read_len = 0, default 1 */ + dd_reg_read_len = 1; + } + + rdata = kzalloc(dd_reg_read_len * sizeof(char), GFP_KERNEL); + if (rdata == NULL) { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + return ret; + } + + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + if (pjadard_ic_data->JD_MODULE_CASCADE_MODE == JD_CASCADE_MODE_ENABLE) { + /* Read master dd register */ + if (g_module_fp.fp_dd_register_read(dd_reg_page, dd_reg_cmd, rdata, dd_reg_read_len, + pjadard_ic_data->JD_MASTER_ADDR_OFFSET) == JD_DBIC_READ_WRITE_FAIL) { + ret += scnprintf(buf_tmp + ret, len - ret, "Read master display register fail!\n"); + } else { + /* Set output data */ + if (g_common_variable.dbi_dd_reg_mode == JD_DDREG_MODE_1) { + ret += scnprintf(buf_tmp + ret, len - ret, "Master display register page: 0x%02X\n", dd_reg_page); + } + ret += scnprintf(buf_tmp + ret, len - ret, "Master display register: 0x%02X\n", dd_reg_cmd); + + for (i = 0; i < dd_reg_read_len; i++) { + ret += scnprintf(buf_tmp + ret, len - ret, "0x%2.2X ", rdata[i]); + + if ((i % 16) == 15) + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + } + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + } + + /* Read slave dd register */ + if (g_module_fp.fp_dd_register_read(dd_reg_page, dd_reg_cmd, rdata, dd_reg_read_len, + pjadard_ic_data->JD_SLAVE_ADDR_OFFSET) == JD_DBIC_READ_WRITE_FAIL) { + ret += scnprintf(buf_tmp + ret, len - ret, "Read slave display register fail!\n"); + } else { + /* Set output data */ + if (g_common_variable.dbi_dd_reg_mode == JD_DDREG_MODE_1) { + ret += scnprintf(buf_tmp + ret, len - ret, "Slave display register page: 0x%02X\n", dd_reg_page); + } + ret += scnprintf(buf_tmp + ret, len - ret, "Slave display register: 0x%02X\n", dd_reg_cmd); + + for (i = 0; i < dd_reg_read_len; i++) { + ret += scnprintf(buf_tmp + ret, len - ret, "0x%2.2X ", rdata[i]); + + if ((i % 16) == 15) + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + } + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + } + } else { + if (g_module_fp.fp_dd_register_read(dd_reg_page, dd_reg_cmd, rdata, dd_reg_read_len, 0) == JD_DBIC_READ_WRITE_FAIL) { + ret += scnprintf(buf_tmp + ret, len - ret, "Read display register fail!\n"); + } else { + /* Set output data */ + if (g_common_variable.dbi_dd_reg_mode == JD_DDREG_MODE_1) { + ret += scnprintf(buf_tmp + ret, len - ret, "Display register page: 0x%02X\n", dd_reg_page); + } + ret += scnprintf(buf_tmp + ret, len - ret, "Display register: 0x%02X\n", dd_reg_cmd); + + for (i = 0; i < dd_reg_read_len; i++) { + ret += scnprintf(buf_tmp + ret, len - ret, "0x%2.2X ", rdata[i]); + + if ((i % 16) == 15) + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + } + ret += scnprintf(buf_tmp + ret, len - ret, "\n"); + } + } + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + kfree(rdata); + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +/* + * Example: Only support lower case + * ADDRESS: 1byte size, according to the chip of HW design + * < MODE_0 > + * Write display register: echo w:xADDRESS:x11:x22:x33 > /proc/jadard_touch/display + * write ADDRESS 3bytes data(0x11,0x22,0x33), MAX:64bytes + * Read display register: echo r:xADDRESS:x11 > /proc/jadard_touch/display + * read ADDRESS 0x11(17)bytes, MAX:0xFF + * < MODE_1 > + * Write display register: echo w:xPAGE:xADDRESS:x11:x22:x33 > /proc/jadard_touch/display + * write ADDRESS of the PAGE 3bytes data(0x11,0x22,0x33), MAX:64bytes + * Read display register: echo r:xPAGE:xADDRESS:x11 > /proc/jadard_touch/display + * read ADDRESS of the PAGE 0x11(17)bytes, MAX:0xFF + * Don't care PAGE when nokia standard comand + * Write sleep in: echo w:x00:x10 > /proc/jadard_touch/display + */ +static ssize_t jadard_proc_display_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[64 * 4 + 2] = {0}; + char tok_data[64 * 4 + 2] = {0}; + char *p_tok_data = tok_data; + char *token = NULL; + char *const delim = ":"; + uint8_t w_data[64]; + uint8_t w_data_len = 0; + unsigned long result = 0; + bool reg_page = false; + bool reg_addr = true; + bool format_err = false; + char temp[4]; + + if (g_common_variable.dbi_dd_reg_mode == JD_DDREG_MODE_1) { + reg_page = true; + reg_addr = false; + } else { /* MODE_0 */ + reg_page = false; + reg_addr = true; + } + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (len == 0) { + JD_I("%s: no command equal 0 char.\n", __func__); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len - 1)) { + return -EFAULT; + } + + JD_I("%s: buf_tmp = %s\n", __func__, buf_tmp); + + if ((buf_tmp[0] == 'r' || buf_tmp[0] == 'w') && buf_tmp[1] == ':' && buf_tmp[2] == 'x') { + memset(w_data, 0x00, sizeof(w_data)); + memcpy(p_tok_data, buf_tmp + 2, strlen(buf_tmp) - 2); + + while ((token = strsep(&p_tok_data, delim)) != NULL) { + if ((token[0] == 'x') && (strlen(token) == 3)) { + memset(temp, 0x00, sizeof(temp)); + memcpy(temp, token + 1, 2); + + if (reg_page) { + /* Save register page */ + dd_reg_page = 0x00; + + if (!kstrtoul(temp, 16, &result)) { + dd_reg_page = (uint8_t)result & 0x0F; + } else { + format_err = true; + } + + reg_page = false; + reg_addr = true; + } else { + /* Save register addr/data */ + if (!kstrtoul(temp, 16, &result)) { + if (reg_addr) { + dd_reg_cmd = (uint8_t)result; + reg_addr = false; + } else { + if (buf_tmp[0] == 'w') { + w_data[w_data_len++] = (uint8_t)result; + } else { + dd_reg_read_len = (uint8_t)result; + break; + } + } + } else { + format_err = true; + } + } + } else { + format_err = true; + } + + if (format_err) { + JD_E("%s: (%s)Command format error!\n", __func__, token); + return -EINVAL; + } + } + + if (buf_tmp[0] == 'w') { + if (g_module_fp.fp_dd_register_write(dd_reg_page, dd_reg_cmd, w_data, w_data_len) == JD_DBIC_READ_WRITE_FAIL) { + JD_E("%s: Write display register(%x) fail!\n", __func__, dd_reg_cmd); + } + + dd_reg_read_len = w_data_len; + } + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_display_ops = { + .proc_read = jadard_proc_display_read , + .proc_write = jadard_proc_display_write, +}; +#else +static struct file_operations jadard_proc_display_ops = { + .owner = THIS_MODULE, + .read = jadard_proc_display_read , + .write = jadard_proc_display_write, +}; +#endif + +/* + * dbi_std_mode_enable: + * 0: Only can write nokia standard command(0x10 0x11 0x28 0x29 0x34 0x35) + * 1: Can write all nokia standard command + */ +static ssize_t jadard_proc_display_std_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[128] = {0}; + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + JD_I("%s: buf_tmp = %s", __func__, buf_tmp); + + if ((buf_tmp[0] == 'S') && (buf_tmp[1] == 'T') && (buf_tmp[2] == 'D')) { + pjadard_ts_data->dbi_std_mode_enable = !(pjadard_ts_data->dbi_std_mode_enable); + + if (pjadard_ts_data->dbi_std_mode_enable) { + JD_I("Dbi std mode enable\n"); + } else { + JD_I("Dbi std mode disable\n"); + } + } else { + JD_E("%s: Command format error!\n", __func__); + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_display_std_ops = { + .proc_write = jadard_proc_display_std_write, +}; +#else +static struct file_operations jadard_proc_display_std_ops = { + .owner = THIS_MODULE, + .write = jadard_proc_display_std_write, +}; +#endif + +static ssize_t jadard_debug_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t ret = 0; + char *buf_tmp = NULL; + + if (len < 512) { + JD_E("%s: len size less than 512\n", __func__); + return -ENOMEM; + } + + if (!pjadard_debug->proc_send_flag) { + buf_tmp = kzalloc(len * sizeof(char), GFP_KERNEL); + if (buf_tmp != NULL) { + if (debug_cmd == 'v') { + ret += scnprintf(buf_tmp + ret, len - ret, "IC ID: %s\n", pjadard_ic_data->chip_id); + ret += scnprintf(buf_tmp + ret, len - ret, "FW_VER: %08x\n", pjadard_ic_data->fw_ver); + ret += scnprintf(buf_tmp + ret, len - ret, "FW_CID_VER: %08x\n", pjadard_ic_data->fw_cid_ver); + ret += scnprintf(buf_tmp + ret, len - ret, "PANEL_MAKER: %s\n", pjadard_ic_data->panel_maker); + ret += scnprintf(buf_tmp + ret, len - ret, "PANEL_VER: %02x\n", pjadard_ic_data->panel_ver); + ret += scnprintf(buf_tmp + ret, len - ret, "Driver_VER: %s\n", JADARD_DRIVER_VER); + ret += scnprintf(buf_tmp + ret, len - ret, "Driver_CID_VER: %s\n", JADARD_DRIVER_CID_VER); + } else if (debug_cmd == 'i') { + ret += scnprintf(buf_tmp + ret, len - ret, "Jadard Touch IC Information: "); + ret += scnprintf(buf_tmp + ret, len - ret, "%s\n", pjadard_ic_data->chip_id); + + if (pjadard_ic_data->JD_INT_EDGE) { + ret += scnprintf(buf_tmp + ret, len - ret, "Driver register Interrupt: EDGE TIRGGER\n"); + } else { + ret += scnprintf(buf_tmp + ret, len - ret, "Driver register Interrupt: LEVEL TRIGGER\n"); + } + + if (pjadard_ts_data->protocol_type == PROTOCOL_TYPE_A) { + ret += scnprintf(buf_tmp + ret, len - ret, "Protocol: TYPE_A\n"); + } else { + ret += scnprintf(buf_tmp + ret, len - ret, "Protocol: TYPE_B\n"); + } + + ret += scnprintf(buf_tmp + ret, len - ret, "Freq_Band: %d\n", g_module_fp.fp_get_freq_band()); + ret += scnprintf(buf_tmp + ret, len - ret, "X_Num: %d\n", pjadard_ic_data->JD_X_NUM); + ret += scnprintf(buf_tmp + ret, len - ret, "Y_Num: %d\n", pjadard_ic_data->JD_Y_NUM); + ret += scnprintf(buf_tmp + ret, len - ret, "X_Resolution: %d\n", pjadard_ic_data->JD_X_RES); + ret += scnprintf(buf_tmp + ret, len - ret, "Y_Resolution: %d\n", pjadard_ic_data->JD_Y_RES); + ret += scnprintf(buf_tmp + ret, len - ret, "Max Points: %d\n", pjadard_ic_data->JD_MAX_PT); + ret += scnprintf(buf_tmp + ret, len - ret, "Product_Type: %d\n", JD_PRODUCT_TYPE); + ret += scnprintf(buf_tmp + ret, len - ret, "Cascade_Mode: %d\n", pjadard_ic_data->JD_MODULE_CASCADE_MODE); + } else if (debug_cmd == 't') { + if (fw_upgrade_complete) { + ret += scnprintf(buf_tmp + ret, len - ret, "FW Upgrade Complete\n"); + } else { + ret += scnprintf(buf_tmp + ret, len - ret, "FW Upgrade Fail\n"); + } + } else if (debug_cmd == 'm') { + if (pjadard_ic_data->JD_DISABLE_MASTER_TO_SLAVE) { + ret += scnprintf(buf_tmp + ret, len - ret, "Direct read slave register\n"); + } else { + ret += scnprintf(buf_tmp + ret, len - ret, "Read slave by master\n"); + } + } else if (debug_cmd == 'd') { + if (jd_g_dbg_enable) { + ret += scnprintf(buf_tmp + ret, len - ret, "Debug Enable\n"); + } else { + ret += scnprintf(buf_tmp + ret, len - ret, "Debug Disable\n"); + } + } + + if (copy_to_user(buf, buf_tmp, len)) { + JD_E("%s, copy_to_user fail: %d\n", __func__, __LINE__); + } + + kfree(buf_tmp); + } else { + JD_E("%s, Memory allocate fail: %d\n", __func__, __LINE__); + } + + pjadard_debug->proc_send_flag = true; + } else { + pjadard_debug->proc_send_flag = false; + } + + return ret; +} + +static ssize_t jadard_debug_write(struct file *file, const char *buf, + size_t len, loff_t *pos) +{ + char buf_tmp[128] = {0}; + char fileName[128]; + int ret = 0; +#if !defined(JD_ZERO_FLASH) && !defined(JD_UPGRADE_FW_ARRAY) + const struct firmware *fw = NULL; +#endif + + if (len >= sizeof(buf_tmp)) { + JD_I("%s: no command exceeds %ld chars.\n", __func__, sizeof(buf_tmp)); + return -EFAULT; + } + + if (copy_from_user(buf_tmp, buf, len)) { + return -EFAULT; + } + + JD_I("%s: buf_tmp = %s", __func__, buf_tmp); + + if (buf_tmp[0] == 'v') { + /* FW and Driver version */ + g_module_fp.fp_read_fw_ver(); + debug_cmd = buf_tmp[0]; + } else if ((buf_tmp[0] == 'i') && (buf_tmp[1] != 'b')) { + /* IC information */ + debug_cmd = buf_tmp[0]; + } else if (buf_tmp[0] == 't') { + if (pjadard_ts_data->diag_thread_active) { + JD_I("Diag thread is active! Skip Update with zero flash\n"); + return -EFAULT; + } + debug_cmd = buf_tmp[0]; + /* Start upgrade flow*/ + jadard_int_enable(false); + fw_upgrade_complete = false; + memset(fileName, 0, sizeof(fileName)); + scnprintf(fileName, len - 2, "%s", buf_tmp + 2); +#ifndef JD_UPGRADE_FW_ARRAY + JD_I("%s: Bin file name(%s)\n", __func__, fileName); +#endif + +#ifdef JD_ESD_CHECK + if (pjadard_ts_data->esd_check_running == true) { + JD_I("Stop esd check\n"); + pjadard_ts_data->esd_check_running = false; + cancel_delayed_work_sync(&pjadard_ts_data->work_esd_check); + } +#endif + +#ifdef JD_ZERO_FLASH + JD_I("Running Zero flash upgrade\n"); + + pjadard_ts_data->power_on_upgrade = true; + ret = g_module_fp.fp_0f_upgrade_fw(fileName); + pjadard_ts_data->power_on_upgrade = true; + + if (ret < 0) { + fw_upgrade_complete = false; + JD_I("Zero flash upgrade fail\n"); + } else { + fw_upgrade_complete = true; + JD_I("Zero flash upgrade success\n"); + } +#else + JD_I("Running flash upgrade\n"); +#ifdef JD_UPGRADE_FW_ARRAY + JD_I("file name = %s\n", jd_i_CTPM_firmware_name); + JD_I("FW size is %dBytes\n", (int)jd_fw_size); + + ret = g_module_fp.fp_flash_write(0, (uint8_t *)jd_i_firmware, jd_fw_size); + if (ret < 0) { + JD_E("%s: TP upgrade fail\n", __func__); + fw_upgrade_complete = false; + } else { + JD_I("%s: TP upgrade success\n", __func__); + fw_upgrade_complete = true; + } +#else + ret = request_firmware(&fw, fileName, pjadard_ts_data->dev); + if (ret < 0) { + JD_I("Fail to open file: %s (ret:%d)\n", fileName, ret); + return ret; + } + + JD_I("FW size is %dBytes\n", (int)fw->size); + + if (g_module_fp.fp_flash_write(0, (uint8_t *)fw->data, fw->size) < 0) { + JD_E("%s: TP upgrade fail\n", __func__); + fw_upgrade_complete = false; + } else { + JD_I("%s: TP upgrade success\n", __func__); + fw_upgrade_complete = true; + } + + release_firmware(fw); +#endif +#endif + g_module_fp.fp_read_fw_ver(); + jadard_int_enable(true); + +#ifdef JD_ESD_CHECK + if (pjadard_ts_data->esd_check_running == false) { + JD_I("Start esd check\n"); + pjadard_ts_data->esd_check_running = true; + queue_delayed_work(pjadard_ts_data->jadard_esd_check_wq, &pjadard_ts_data->work_esd_check, 0); + } +#endif + } else if ((buf_tmp[0] == 'e') && (buf_tmp[1] == 'r') && (buf_tmp[2] == 'a') && + (buf_tmp[3] == 's') && (buf_tmp[4] == 'e')) { +#ifdef JD_ESD_CHECK + if (pjadard_ts_data->esd_check_running == true) { + JD_I("Stop esd check\n"); + pjadard_ts_data->esd_check_running = false; + cancel_delayed_work_sync(&pjadard_ts_data->work_esd_check); + } +#endif + + if (g_module_fp.fp_flash_erase() < 0) { + JD_E("%s: Flash erase fail\n", __func__); + } else { + JD_I("%s: Flash erase finish\n", __func__); + } + } else if (buf_tmp[0] == 'm') { + debug_cmd = buf_tmp[0]; + if (pjadard_ic_data->JD_MODULE_CASCADE_MODE == JD_CASCADE_MODE_ENABLE) { + pjadard_ic_data->JD_DISABLE_MASTER_TO_SLAVE = !(pjadard_ic_data->JD_DISABLE_MASTER_TO_SLAVE); + + if (pjadard_ic_data->JD_DISABLE_MASTER_TO_SLAVE) { + JD_I("Direct read slave register\n"); + } else { + JD_I("Read slave by master\n"); + } + } else { + pjadard_ic_data->JD_DISABLE_MASTER_TO_SLAVE = true; + JD_I("Direct read slave register\n"); + } + } else if (buf_tmp[0] == 'd') { + debug_cmd = buf_tmp[0]; + jd_g_dbg_enable = !jd_g_dbg_enable; + + if (jd_g_dbg_enable) { + JD_I("Debug Enable\n"); + } else { + JD_I("Debug Disable\n"); + } + } else if ((buf_tmp[0] == 'i') && (buf_tmp[1] == 'b')) { + g_module_fp.fp_EnterBackDoor(); + JD_I("Enter backdoor\n"); + } else if ((buf_tmp[0] == 'o') && (buf_tmp[1] == 'b')) { + g_module_fp.fp_ExitBackDoor(); + JD_I("Exit backdoor\n"); + } else { + debug_cmd = 0; + } + + return len; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0) +static struct proc_ops jadard_proc_debug_ops = { + .proc_read = jadard_debug_read, + .proc_write = jadard_debug_write, +}; +#else +static struct file_operations jadard_proc_debug_ops = { + .owner = THIS_MODULE, + .read = jadard_debug_read, + .write = jadard_debug_write, +}; +#endif + +int jadard_touch_proc_init(void) +{ + jadard_proc_report_debug_file = proc_create(JADARD_PROC_REPORT_DEBUG_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_debug_level_ops); + if (jadard_proc_report_debug_file == NULL) { + JD_E(" %s: proc report_debug file create failed!\n", __func__); + goto fail; + } + + jadard_proc_fw_package_file = proc_create(JADARD_PROC_FW_PACKAGE_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_fw_package_ops); + if (jadard_proc_fw_package_file == NULL) { + JD_E(" %s: proc report_debug file create failed!\n", __func__); + goto fail; + } + + jadard_proc_reset_file = proc_create(JADARD_PROC_RESET_FILE, (S_IWUGO), + pjadard_touch_proc_dir, &jadard_proc_reset_ops); + if (jadard_proc_reset_file == NULL) { + JD_E(" %s: proc reset file create failed!\n", __func__); + goto fail; + } + + jadard_proc_attn_file = proc_create(JADARD_PROC_ATTN_FILE, (S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_attn_ops); + if (jadard_proc_attn_file == NULL) { + JD_E(" %s: proc attn file create failed!\n", __func__); + goto fail; + } + + jadard_proc_int_en_file = proc_create(JADARD_PROC_INT_EN_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_int_en_ops); + if (jadard_proc_int_en_file == NULL) { + JD_E(" %s: proc int en file create failed!\n", __func__); + goto fail; + } + + jadard_proc_fw_dump_file = proc_create(JADARD_PROC_FW_DUMP_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_fw_dump_ops); + if (jadard_proc_fw_dump_file == NULL) { + JD_E(" %s: proc flash dump file create failed!\n", __func__); + goto fail; + } + + jadard_proc_diag_file = proc_create(JADARD_PROC_DIAG_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_diag_ops); + if (jadard_proc_diag_file == NULL) { + JD_E(" %s: proc diag file create failed!\n", __func__); + goto fail; + } + + jadard_proc_diag_arr_file = proc_create(JADARD_PROC_DIAG_ARR_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_diag_arrange_ops); + if (jadard_proc_diag_arr_file == NULL) { + JD_E(" %s: proc diag file create failed!\n", __func__); + goto fail; + } + + jadard_proc_register_file = proc_create(JADARD_PROC_REGISTER_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_register_ops); + if (jadard_proc_register_file == NULL) { + JD_E(" %s: proc register file create failed!\n", __func__); + goto fail; + } + + jadard_proc_display_file = proc_create(JADARD_PROC_DISPLAY_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_display_ops); + if (jadard_proc_display_file == NULL) { + JD_E(" %s: proc register file create failed!\n", __func__); + goto fail; + } + + if (g_common_variable.dbi_dd_reg_mode == JD_DDREG_MODE_1) { + jadard_proc_display_std_file = proc_create(JADARD_PROC_DISPLAY_STD_FILE, (S_IWUGO), + pjadard_touch_proc_dir, &jadard_proc_display_std_ops); + if (jadard_proc_display_std_file == NULL) { + JD_E(" %s: proc register file create failed!\n", __func__); + goto fail; + } + } + + jadard_proc_debug_file = proc_create(JADARD_PROC_DEBUG_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_debug_ops); + if (jadard_proc_debug_file == NULL) { + JD_E(" %s: proc debug file create failed!\n", __func__); + goto fail; + } + + jadard_proc_diag_apk_file = proc_create(JADARD_PROC_DIAG_APK_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_diag_apk_ops); + if (jadard_proc_diag_apk_file == NULL) { + JD_E(" %s: proc diag apk file create failed!\n", __func__); + goto fail; + } + + jadard_proc_buf_rd_file = proc_create(JADARD_PROC_BUF_RD_FILE, (S_IWUGO | S_IRUGO), + pjadard_touch_proc_dir, &jadard_proc_buf_rd_ops); + if (jadard_proc_buf_rd_file == NULL) { + JD_E(" %s: proc diag apk file create failed!\n", __func__); + goto fail; + } + + return 0; + +fail: + jadard_touch_proc_deinit(); + + return -ENOMEM; +} + +static void jadard_debug_data_init(void) +{ + /* Global variable initial */ + jd_diag_mutual_fn = NULL; + jd_diag_mutual = NULL; + jd_diag_mutual_cnt = 0; + jd_buf = NULL; + diag_arr_num = 0; + reg_read_len = 1; + dd_reg_read_len = 1; + fw_buffer = NULL; + debug_cmd = 'v'; + fw_upgrade_complete = false; + jd_g_dbg_enable = false; + jd_g_buf_rd_enable = false; + buf_rd_byte_num = 2; + + pjadard_debug->fp_touch_dbg_func = jadard_touch_dbg_func; + pjadard_debug->fw_dump_going = &fw_dump_going; + pjadard_debug->proc_send_flag = false; +} + +int jadard_debug_init(void) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + int err = 0; + + JD_I("%s:Enter\n", __func__); + + if (ts == NULL) { + JD_E("%s: pjadard_ts_data struct is NULL \n", __func__); + return -EPROBE_DEFER; + } + + pjadard_debug = kzalloc(sizeof(*pjadard_debug), GFP_KERNEL); + if (pjadard_debug == NULL) { + JD_E("%s, pjadard_debug buffer allocate fail\n", __func__); + err = -ENOMEM; + goto err_alloc_debug_data_failed; + } + + jadard_debug_data_init(); + + ts->fw_dump_wq = create_singlethread_workqueue("jadard_fw_dump_wq"); + + if (!ts->fw_dump_wq) { + JD_E("%s: create flash workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_fw_dump_wq_failed; + } + + INIT_WORK(&ts->fw_dump_work, jadard_ts_fw_dump_work_func); + fw_dump_busy = false; + fw_buffer = kzalloc(g_common_variable.FW_SIZE * sizeof(uint8_t), GFP_KERNEL); + + if (fw_buffer == NULL) { + JD_E("%s: FW buffer allocate failed\n", __func__); + err = -ENOMEM; + goto err_alloc_fw_buffer_failed; + } + + ts->jadard_diag_wq = create_singlethread_workqueue("jadard_diag"); + + if (!ts->jadard_diag_wq) { + JD_E("%s: create diag workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_diag_wq_failed; + } + + INIT_DELAYED_WORK(&ts->jadard_diag_delay_wrok, jadard_ts_diag_work_func); + + /* Allocate mutual data memory */ + jd_diag_mutual = kzalloc(pjadard_ic_data->JD_X_NUM * + pjadard_ic_data->JD_Y_NUM * sizeof(int), GFP_KERNEL); + + if (jd_diag_mutual == NULL) { + JD_E("%s: mutual buffer allocate failed\n", __func__); + err = -ENOMEM; + goto err_alloc_memory_failed; + } + + jd_buf = kzalloc(pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM * + buf_rd_byte_num * sizeof(uint8_t), GFP_KERNEL); + + if (jd_buf == NULL) { + JD_E("%s: Rawdata buffer allocate failed\n", __func__); + err = -ENOMEM; + goto err_alloc_jd_buf_failed; + } + + jadard_touch_proc_init(); + + return 0; + +err_alloc_jd_buf_failed: + kfree(jd_diag_mutual); +err_alloc_memory_failed: + cancel_delayed_work_sync(&ts->jadard_diag_delay_wrok); + destroy_workqueue(ts->jadard_diag_wq); +err_create_diag_wq_failed: + destroy_workqueue(ts->fw_dump_wq); +err_alloc_fw_buffer_failed: + kfree(fw_buffer); +err_create_fw_dump_wq_failed: + kfree(pjadard_debug); +err_alloc_debug_data_failed: + + return err; +} + +void jadard_touch_proc_deinit(void) +{ + if (jadard_proc_buf_rd_file) { + remove_proc_entry(JADARD_PROC_BUF_RD_FILE, pjadard_touch_proc_dir); + jadard_proc_buf_rd_file = NULL; + } + + if (jadard_proc_diag_apk_file) { + remove_proc_entry(JADARD_PROC_DIAG_APK_FILE, pjadard_touch_proc_dir); + jadard_proc_diag_apk_file = NULL; + } + + if (jadard_proc_debug_file) { + remove_proc_entry(JADARD_PROC_DEBUG_FILE, pjadard_touch_proc_dir); + jadard_proc_debug_file = NULL; + } + + if (g_common_variable.dbi_dd_reg_mode == JD_DDREG_MODE_1) { + if (jadard_proc_display_std_file) { + remove_proc_entry(JADARD_PROC_DISPLAY_STD_FILE, pjadard_touch_proc_dir); + jadard_proc_display_std_file = NULL; + } + } + + if (jadard_proc_display_file) { + remove_proc_entry(JADARD_PROC_DISPLAY_FILE, pjadard_touch_proc_dir); + jadard_proc_display_file = NULL; + } + + if (jadard_proc_register_file) { + remove_proc_entry(JADARD_PROC_REGISTER_FILE, pjadard_touch_proc_dir); + jadard_proc_register_file = NULL; + } + + if (jadard_proc_diag_arr_file) { + remove_proc_entry(JADARD_PROC_DIAG_ARR_FILE, pjadard_touch_proc_dir); + jadard_proc_diag_arr_file = NULL; + } + + if (jadard_proc_diag_file) { + remove_proc_entry(JADARD_PROC_DIAG_FILE, pjadard_touch_proc_dir); + jadard_proc_diag_file = NULL; + } + + if (jadard_proc_fw_dump_file) { + remove_proc_entry(JADARD_PROC_FW_DUMP_FILE, pjadard_touch_proc_dir); + jadard_proc_fw_dump_file = NULL; + } + + if (jadard_proc_int_en_file) { + remove_proc_entry(JADARD_PROC_INT_EN_FILE, pjadard_touch_proc_dir); + jadard_proc_int_en_file = NULL; + } + + if (jadard_proc_attn_file) { + remove_proc_entry(JADARD_PROC_ATTN_FILE, pjadard_touch_proc_dir); + jadard_proc_attn_file = NULL; + } + + if (jadard_proc_reset_file) { + remove_proc_entry(JADARD_PROC_RESET_FILE, pjadard_touch_proc_dir); + jadard_proc_reset_file = NULL; + } + + if (jadard_proc_fw_package_file) { + remove_proc_entry(JADARD_PROC_FW_PACKAGE_FILE, pjadard_touch_proc_dir); + jadard_proc_fw_package_file = NULL; + } + + if (jadard_proc_report_debug_file) { + remove_proc_entry(JADARD_PROC_REPORT_DEBUG_FILE, pjadard_touch_proc_dir); + jadard_proc_report_debug_file = NULL; + } +} + +int jadard_debug_remove(void) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + jadard_touch_proc_deinit(); + kfree(jd_buf); + kfree(jd_diag_mutual); + cancel_delayed_work_sync(&ts->jadard_diag_delay_wrok); + destroy_workqueue(ts->jadard_diag_wq); + destroy_workqueue(ts->fw_dump_wq); + kfree(fw_buffer); + kfree(pjadard_debug); + + return 0; +} + +#ifndef CONFIG_JD_DB +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); +#endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_debug.h b/drivers/input/touchscreen/jdchipset/jadard_debug.h new file mode 100644 index 0000000000000..b26adb8fbc81a --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_debug.h @@ -0,0 +1,78 @@ +#ifndef H_JADARD_DEBUG +#define H_JADARD_DEBUG + +#define JADARD_PROC_REPORT_DEBUG_FILE "report_debug" +#define JADARD_PROC_FW_PACKAGE_FILE "fw_package" +#define JADARD_PROC_RESET_FILE "reset" +#define JADARD_PROC_ATTN_FILE "attn" +#define JADARD_PROC_INT_EN_FILE "int_en" +#define JADARD_PROC_DIAG_FILE "diag" +#define JADARD_PROC_DIAG_ARR_FILE "diag_arr" +#define JADARD_PROC_DIAG_APK_FILE "diag_apk" +#define JADARD_PROC_FW_DUMP_FILE "fw_dump" +#define JADARD_PROC_REGISTER_FILE "register" +#define JADARD_PROC_DISPLAY_FILE "display" +#define JADARD_PROC_DISPLAY_STD_FILE "display_std" +#define JADARD_PROC_DEBUG_FILE "debug" +#define JADARD_PROC_BUF_RD_FILE "buf_rd" + +static struct proc_dir_entry *jadard_proc_report_debug_file; +static struct proc_dir_entry *jadard_proc_fw_package_file; +static struct proc_dir_entry *jadard_proc_reset_file; +static struct proc_dir_entry *jadard_proc_attn_file; +static struct proc_dir_entry *jadard_proc_int_en_file; +static struct proc_dir_entry *jadard_proc_diag_file; +static struct proc_dir_entry *jadard_proc_diag_arr_file; +static struct proc_dir_entry *jadard_proc_diag_apk_file; +static struct proc_dir_entry *jadard_proc_fw_dump_file; +static struct proc_dir_entry *jadard_proc_register_file; +static struct proc_dir_entry *jadard_proc_display_file; +static struct proc_dir_entry *jadard_proc_display_std_file; +static struct proc_dir_entry *jadard_proc_debug_file; +static struct proc_dir_entry *jadard_proc_buf_rd_file; + +#define JD_MASTER_FW_DUMP_FILE "/sdcard/JD_MASTER_FW_Dump.bin" +#define JD_SLAVE_FW_DUMP_FILE "/sdcard/JD_SLAVE_FW_Dump.bin" +#define JD_RAWDATA_DUMP_FILE "/sdcard/JD_RAWDATA_Dump.txt" +#define JD_DIFF_DUMP_FILE "/sdcard/JD_DIFF_Dump.txt" +#define JD_BASE_DUMP_FILE "/sdcard/JD_BASE_Dump.txt" +#define JD_LISTEN_DUMP_FILE "/sdcard/JD_LISTEN_Dump.txt" +#define JD_LABEL_DUMP_FILE "/sdcard/JD_LABEL_Dump.txt" +#define JD_LAPLACE_DUMP_FILE "/sdcard/JD_LAPLACE_Dump.txt" + +struct jadard_diag_mutual_data { + char *buf; + int buf_len; + int write_len; +}; + +int DataType; +static int KeepType; +static int KeepFrame; + +static struct file *jd_diag_mutual_fn; +int *jd_diag_mutual; +int jd_diag_mutual_cnt; +uint8_t *jd_buf; +static uint8_t diag_arr_num; +static uint8_t reg_cmd[4]; +static uint8_t reg_cmd_len; +static uint8_t reg_read_len; +static uint8_t dd_reg_page; +static uint8_t dd_reg_cmd; +static uint8_t dd_reg_read_len; + +static uint8_t *fw_buffer; +static bool fw_dump_busy; +static bool fw_dump_complete; +static bool fw_dump_going; + +static char debug_cmd; +static bool fw_upgrade_complete; +bool jd_g_dbg_enable; +static bool jd_g_buf_rd_enable; +static uint8_t buf_rd_byte_num; +int jadard_touch_proc_init(void); +void jadard_touch_proc_deinit(void); + +#endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_ic_JD9366T.c b/drivers/input/touchscreen/jdchipset/jadard_ic_JD9366T.c new file mode 100644 index 0000000000000..125724e961a18 --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_ic_JD9366T.c @@ -0,0 +1,3764 @@ +#include "jadard_platform.h" +#include "jadard_common.h" +#include "jadard_module.h" +#include "jadard_ic_JD9366T.h" + +extern struct jadard_module_fp g_module_fp; +extern struct jadard_ts_data *pjadard_ts_data; +extern struct jadard_ic_data *pjadard_ic_data; +extern struct jadard_report_data *pjadard_report_data; +extern struct jadard_common_variable g_common_variable; + +extern char *jd_panel_maker_list[JD_PANEL_MAKER_LIST_SIZE]; + +#ifdef JD_AUTO_UPGRADE_FW +extern uint8_t *g_jadard_fw; +extern uint32_t g_jadard_fw_ver; +extern uint32_t g_jadard_fw_cid_ver; +#endif + +#ifdef CONFIG_TOUCHSCREEN_JADARD_DEBUG +extern int *jd_diag_mutual; +#endif + +static void jd9366t_ChipInfoInit(void) +{ + /* Initial section info */ + g_jd9366t_section_info.section_info_ready = false; + g_jd9366t_section_info.section_info_ready_addr = JD9366T_MEMORY_ADDR_ERAM; + + g_jd9366t_section_info.dsram_num_start_addr = JD9366T_MEMORY_ADDR_ERAM + 2; + g_jd9366t_section_info.dsram_section_info_start_addr = JD9366T_MEMORY_ADDR_ERAM + 4; + + g_jd9366t_section_info.esram_num_start_addr = (g_jd9366t_section_info.dsram_section_info_start_addr + + JD9366T_MAX_DSRAM_NUM * sizeof(struct JD9366T_INFO_CONTENT)); + g_jd9366t_section_info.esram_section_info_start_addr = g_jd9366t_section_info.esram_num_start_addr + 4; +} + +static bool jd9366t_DoneStatusIsHigh(uint8_t usValue, uint8_t DoneStatus) +{ + return ((usValue & DoneStatus) == DoneStatus); +} + +static bool jd9366t_DoneStatusIsLow(uint8_t usValue, uint8_t BusyStatus, uint8_t DoneStatus) +{ + return ((usValue & BusyStatus) == DoneStatus); +} + +static int jd9366t_Read_BackDoor_RegSingle(uint32_t addr, uint8_t *rdata) +{ + int ReCode; + uint8_t addrBuf[JD_SEVEN_SIZE]; + uint8_t readBuf[JD_ONE_SIZE]; + + addrBuf[0] = 0x68; + addrBuf[1] = 0xF3; + addrBuf[2] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[3] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[4] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[5] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[6] = 0x03; + + ReCode = jadard_bus_read(addrBuf, sizeof(addrBuf), readBuf, sizeof(readBuf), JADARD_BUS_RETRY_TIMES); + *rdata = readBuf[0]; + + return ReCode; +} + +static int jd9366t_Read_BackDoor_RegSingle_I2C(uint32_t addr, uint8_t *rdata) +{ + int ReCode; + uint8_t addrBuf[JD_SIX_SIZE]; + uint8_t readBuf[JD_ONE_SIZE]; + + addrBuf[0] = 0xF3; + addrBuf[1] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[2] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[3] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[4] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[5] = 0x03; + + ReCode = jadard_bus_read(addrBuf, sizeof(addrBuf), readBuf, sizeof(readBuf), JADARD_BUS_RETRY_TIMES); + *rdata = readBuf[0]; + + return ReCode; +} + +static int jd9366t_Write_BackDoor_RegSingle(uint32_t addr, uint8_t wdata) +{ + uint8_t addrBuf[JD_SEVEN_SIZE]; + uint8_t writeBuf[JD_ONE_SIZE]; + + addrBuf[0] = 0x68; + addrBuf[1] = 0xF2; + addrBuf[2] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[3] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[4] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[5] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[6] = 0x03; + writeBuf[0] = wdata; + + return jadard_bus_write(addrBuf, sizeof(addrBuf), writeBuf, sizeof(writeBuf), JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Write_BackDoor_RegSingle_I2C(uint32_t addr, uint8_t wdata) +{ + uint8_t addrBuf[JD_SIX_SIZE]; + uint8_t writeBuf[JD_ONE_SIZE]; + + addrBuf[0] = 0xF2; + addrBuf[1] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[2] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[3] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[4] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[5] = 0x03; + writeBuf[0] = wdata; + + return jadard_bus_write(addrBuf, sizeof(addrBuf), writeBuf, sizeof(writeBuf), JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Read_BackDoor_RegMulti(uint32_t addr, uint8_t *rdata, uint16_t rlen) +{ + uint8_t addrBuf[JD_SEVEN_SIZE]; + + addrBuf[0] = 0x68; + addrBuf[1] = 0xF3; + addrBuf[2] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[3] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[4] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[5] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[6] = 0x03; + + return jadard_bus_read(addrBuf, sizeof(addrBuf), rdata, rlen, JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Read_BackDoor_RegMulti_I2C(uint32_t addr, uint8_t *rdata, uint16_t rlen) +{ + uint8_t addrBuf[JD_SIX_SIZE]; + + addrBuf[0] = 0xF3; + addrBuf[1] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[2] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[3] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[4] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[5] = 0x03; + + return jadard_bus_read(addrBuf, sizeof(addrBuf), rdata, rlen, JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Write_BackDoor_RegMulti(uint32_t addr, uint8_t *wdata, uint16_t wlen) +{ + uint8_t addrBuf[JD_SEVEN_SIZE]; + + addrBuf[0] = 0x68; + addrBuf[1] = 0xF2; + addrBuf[2] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[3] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[4] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[5] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[6] = 0x03; + + return jadard_bus_write(addrBuf, sizeof(addrBuf), wdata, wlen, JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Write_BackDoor_RegMulti_I2C(uint32_t addr, uint8_t *wdata, uint16_t wlen) +{ + uint8_t addrBuf[JD_SIX_SIZE]; + + addrBuf[0] = 0xF2; + addrBuf[1] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[2] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[3] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[4] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[5] = 0x03; + + return jadard_bus_write(addrBuf, sizeof(addrBuf), wdata, wlen, JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Read_FW_RegSingleI2c(uint32_t addr, uint8_t *rdata) +{ + int ReCode; + uint8_t addrBuf[JD_SIX_SIZE]; + uint8_t readBuf[JD_ONE_SIZE]; + + addrBuf[0] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[1] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[2] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[3] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[4] = 0x00; + addrBuf[5] = 0x01; + + ReCode = jadard_bus_read(addrBuf, sizeof(addrBuf), readBuf, sizeof(readBuf), JADARD_BUS_RETRY_TIMES); + *rdata = readBuf[0]; + + return ReCode; +} + +static int jd9366t_Write_FW_RegSingleI2c(uint32_t addr, uint8_t wdata) +{ + uint8_t addrBuf[JD_SIX_SIZE]; + uint8_t writeBuf[JD_ONE_SIZE]; + + addrBuf[0] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[1] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[2] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[3] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[4] = 0x00; + addrBuf[5] = 0x01; + writeBuf[0] = wdata; + + return jadard_bus_write(addrBuf, sizeof(addrBuf), writeBuf, sizeof(writeBuf), JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Read_FW_RegMultiI2c(uint32_t addr, uint8_t *rdata, uint16_t rlen) +{ + uint8_t addrBuf[JD_SIX_SIZE]; + + addrBuf[0] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[1] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[2] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[3] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[4] = (uint8_t)((rlen & 0xFF00) >> 8); + addrBuf[5] = (uint8_t)((rlen & 0x00FF) >> 0); + + return jadard_bus_read(addrBuf, sizeof(addrBuf), rdata, rlen, JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Write_FW_RegMultiI2c(uint32_t addr, uint8_t *wdata, uint16_t wlen) +{ + uint8_t addrBuf[JD_SIX_SIZE]; + + addrBuf[0] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[1] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[2] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[3] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[4] = (uint8_t)((wlen & 0xFF00) >> 8); + addrBuf[5] = (uint8_t)((wlen & 0x00FF) >> 0); + + return jadard_bus_write(addrBuf, sizeof(addrBuf), wdata, wlen, JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Read_FW_RegSingleSpi(uint32_t addr, uint8_t *rdata) +{ + int ReCode; + uint8_t addrBuf[JD_EIGHT_SIZE]; + uint8_t readBuf[JD_ONE_SIZE]; + + addrBuf[0] = 0x68; + addrBuf[1] = 0xF3; + addrBuf[2] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[3] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[4] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[5] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[6] = 0x00; + addrBuf[7] = 0x01; + + ReCode = jadard_bus_read(addrBuf, sizeof(addrBuf), readBuf, sizeof(readBuf), JADARD_BUS_RETRY_TIMES); + *rdata = readBuf[0]; + + return ReCode; +} + +static int jd9366t_Write_FW_RegSingleSpi(uint32_t addr, uint8_t wdata) +{ + uint8_t addrBuf[JD_EIGHT_SIZE]; + uint8_t writeBuf[JD_ONE_SIZE]; + + addrBuf[0] = 0x68; + addrBuf[1] = 0xF2; + addrBuf[2] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[3] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[4] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[5] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[6] = 0x00; + addrBuf[7] = 0x01; + writeBuf[0] = wdata; + + return jadard_bus_write(addrBuf, sizeof(addrBuf), writeBuf, sizeof(writeBuf), JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Read_FW_RegMultiSpi(uint32_t addr, uint8_t *rdata, uint16_t rlen) +{ + uint8_t addrBuf[JD_EIGHT_SIZE]; + + addrBuf[0] = 0x68; + addrBuf[1] = 0xF3; + addrBuf[2] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[3] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[4] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[5] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[6] = (uint8_t)((rlen & 0xFF00) >> 8); + addrBuf[7] = (uint8_t)((rlen & 0x00FF) >> 0); + + return jadard_bus_read(addrBuf, sizeof(addrBuf), rdata, rlen, JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_Write_FW_RegMultiSpi(uint32_t addr, uint8_t *wdata, uint16_t wlen) +{ + uint8_t addrBuf[JD_EIGHT_SIZE]; + + addrBuf[0] = 0x68; + addrBuf[1] = 0xF2; + addrBuf[2] = (uint8_t)((addr & 0xFF000000) >> 24); + addrBuf[3] = (uint8_t)((addr & 0x00FF0000) >> 16); + addrBuf[4] = (uint8_t)((addr & 0x0000FF00) >> 8); + addrBuf[5] = (uint8_t)((addr & 0x000000FF) >> 0); + addrBuf[6] = (uint8_t)((wlen & 0xFF00) >> 8); + addrBuf[7] = (uint8_t)((wlen & 0x00FF) >> 0); + + return jadard_bus_write(addrBuf, sizeof(addrBuf), wdata, wlen, JADARD_BUS_RETRY_TIMES); +} + +static int jd9366t_ReadRegSingle(uint32_t addr, uint8_t *rdata) +{ + int ReCode; + + if (!pjadard_ts_data->diag_thread_active) + jd9366t_EnterBackDoor(NULL); + + if (g_jd9366t_chip_info.back_door_mode) { + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + ReCode = jd9366t_Read_BackDoor_RegSingle(addr, rdata); + } else { + ReCode = jd9366t_Read_BackDoor_RegSingle_I2C(addr, rdata); + } + } else { + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + ReCode = jd9366t_Read_FW_RegSingleSpi(addr, rdata); + } else { + ReCode = jd9366t_Read_FW_RegSingleI2c(addr, rdata); + } + } + + if (!pjadard_ts_data->diag_thread_active) + jd9366t_ExitBackDoor(); + + return ReCode; +} + +static int jd9366t_WriteRegSingle(uint32_t addr, uint8_t wdata) +{ + int ReCode; + + if (!pjadard_ts_data->diag_thread_active) + jd9366t_EnterBackDoor(NULL); + + if (g_jd9366t_chip_info.back_door_mode) { + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + ReCode = jd9366t_Write_BackDoor_RegSingle(addr, wdata); + } else { + ReCode = jd9366t_Write_BackDoor_RegSingle_I2C(addr, wdata); + } + } else { + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + ReCode = jd9366t_Write_FW_RegSingleSpi(addr, wdata); + } else { + ReCode = jd9366t_Write_FW_RegSingleI2c(addr, wdata); + } + } + + if (!pjadard_ts_data->diag_thread_active) + jd9366t_ExitBackDoor(); + + return ReCode; +} + +static int jd9366t_ReadRegMulti(uint32_t addr, uint8_t *rdata, uint16_t rlen) +{ + int ReCode; + + if (!pjadard_ts_data->diag_thread_active) + jd9366t_EnterBackDoor(NULL); + + if (g_jd9366t_chip_info.back_door_mode) { + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + ReCode = jd9366t_Read_BackDoor_RegMulti(addr, rdata, rlen); + } else { + ReCode = jd9366t_Read_BackDoor_RegMulti_I2C(addr, rdata, rlen); + } + } else { + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + ReCode = jd9366t_Read_FW_RegMultiSpi(addr, rdata, rlen); + } else { + ReCode = jd9366t_Read_FW_RegMultiI2c(addr, rdata, rlen); + } + } + + if (!pjadard_ts_data->diag_thread_active) + jd9366t_ExitBackDoor(); + + return ReCode; +} + +static int jd9366t_WriteRegMulti(uint32_t addr, uint8_t *wdata, uint16_t wlen) +{ + int ReCode; + + if (!pjadard_ts_data->diag_thread_active) + jd9366t_EnterBackDoor(NULL); + + if (g_jd9366t_chip_info.back_door_mode) { + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + ReCode = jd9366t_Write_BackDoor_RegMulti(addr, wdata, wlen); + } else { + ReCode = jd9366t_Write_BackDoor_RegMulti_I2C(addr, wdata, wlen); + } + } else { + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + ReCode = jd9366t_Write_FW_RegMultiSpi(addr, wdata, wlen); + } else { + ReCode = jd9366t_Write_FW_RegMultiI2c(addr, wdata, wlen); + } + } + + if (!pjadard_ts_data->diag_thread_active) + jd9366t_ExitBackDoor(); + + return ReCode; +} + +static int module_jd9366t_register_write(uint32_t WriteAddr, uint8_t *WriteData, uint32_t WriteLen) +{ + return jd9366t_WriteRegMulti(WriteAddr, WriteData, (uint16_t)WriteLen); +} + +static int jd9366t_GetID(uint16_t *pRomID) +{ + int ReCode; + uint8_t rbuf[JD_TWO_SIZE]; + + ReCode = jd9366t_ReadRegMulti((uint32_t)JD9366T_SOC_REG_ADDR_CHIP_ID2, rbuf, sizeof(rbuf)); + + if (ReCode < 0) + return ReCode; + + *pRomID = (uint16_t)((rbuf[1] << 8) + rbuf[0]); + + if (*pRomID == JD9366T_ID) { + JD_I("%s: IC ID: %04x\n", __func__, *pRomID); + } else { + JD_E("%s: Error IC ID: %04x\n", __func__, *pRomID); + ReCode = JD_CHIP_ID_ERROR; + } + + return ReCode; +} + +static int jd9366t_EnterBackDoor(uint16_t *pRomID) +{ + int ReCode; +#ifndef JD_I2C_SINGLE_MODE + uint8_t addrBuf[JD_SIX_SIZE]; + uint8_t writeBuf[JD_ONE_SIZE]; + + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + addrBuf[0] = 0x68; + addrBuf[1] = 0xF2; + addrBuf[2] = 0xAA; + addrBuf[3] = 0x55; + addrBuf[4] = 0x0F; + addrBuf[5] = 0xF0; + writeBuf[0] = 0x68; + + ReCode = jadard_bus_write(addrBuf, sizeof(addrBuf), writeBuf, sizeof(writeBuf), JADARD_BUS_RETRY_TIMES); + } else { + addrBuf[0] = 0xF2; + addrBuf[1] = 0xAA; + addrBuf[2] = 0x55; + addrBuf[3] = 0x0F; + addrBuf[4] = 0xF0; + writeBuf[0] = 0x68; + + ReCode = jadard_bus_write(addrBuf, sizeof(addrBuf) - 1, writeBuf, sizeof(writeBuf), JADARD_BUS_RETRY_TIMES); + } + + if (ReCode < 0) { + JD_E("%s: EnterBackDoor fail\n", __func__); + } else { + g_jd9366t_chip_info.back_door_mode = true; + + /* If pRomID != NULL, Read IC ID */ + if (pRomID) { + ReCode = jd9366t_GetID(pRomID); + } + } + + return ReCode; +#else + g_jd9366t_chip_info.back_door_mode = false; + /* If pRomID != NULL, Read IC ID */ + if (pRomID) { + ReCode = jd9366t_GetID(pRomID); + } else { + ReCode = JD_NO_ERR; + } + + return ReCode; +#endif +} + +static int jd9366t_ExitBackDoor(void) +{ +#ifndef JD_I2C_SINGLE_MODE + int ReCode; + uint8_t addrBuf[JD_SIX_SIZE]; + uint8_t writeBuf[JD_ONE_SIZE]; + + if ((pjadard_ts_data != NULL) && (pjadard_ts_data->spi != NULL)) { + addrBuf[0] = 0x68; + addrBuf[1] = 0xF2; + addrBuf[2] = 0xAA; + addrBuf[3] = 0x88; + addrBuf[4] = 0x00; + addrBuf[5] = 0x00; + writeBuf[0] = 0x00; + + ReCode = jadard_bus_write(addrBuf, sizeof(addrBuf), writeBuf, sizeof(writeBuf), JADARD_BUS_RETRY_TIMES); + } else { + addrBuf[0] = 0xF2; + addrBuf[1] = 0xAA; + addrBuf[2] = 0x88; + addrBuf[3] = 0x00; + addrBuf[4] = 0x00; + writeBuf[0] = 0x00; + + ReCode = jadard_bus_write(addrBuf, sizeof(addrBuf) - 1, writeBuf, sizeof(writeBuf), JADARD_BUS_RETRY_TIMES); + } + + if (ReCode < 0) { + JD_E("%s: ExitBackDoor fail\n", __func__); + } else { + g_jd9366t_chip_info.back_door_mode = false; + } + + return ReCode; +#else + return JD_NO_ERR; +#endif +} + +/* static int jd9366t_DisableSleepOutInt(void) +{ + return jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_SLPOUT_INT_EN, + (uint8_t)SOC_RELATED_SETTING_DISABLE_SLEEP_OUT_INT); +} + +static int jd9366t_EnableSleepOutInt(void) +{ + return jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_SLPOUT_INT_EN, + (uint8_t)SOC_RELATED_SETTING_ENABLE_SLEEP_OUT_INT); +} */ + +static int jd9366t_DisableWDTRun(void) +{ + int ReCode; + + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_TIMER_REG_ADDR_WDT_CONFIG, + (uint8_t)JD9366T_TIMER_RELATED_SETTING_WDT_STOP); + + if (ReCode < 0) { + JD_E("%s: Disable WDT run fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_StartMCUClock(void) +{ + int ReCode; + + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_CPU_CLK_STOP, + (uint8_t)JD9366T_SOC_PASSWORD_START_MCU_CLOCK); + + if (ReCode < 0) { + JD_E("%s: Start MCU clock fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_StopMCUClock(void) +{ +#ifndef JD_I2C_SINGLE_MODE + int ReCode; + + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_CPU_CLK_STOP, + (uint8_t)JD9366T_SOC_PASSWORD_STOP_MCU_CLOCK); + + if (ReCode < 0) { + JD_E("%s: Stop MCU clock fail\n", __func__); + } + + return ReCode; +#else + return JD_NO_ERR; +#endif +} + +static int jd9366t_StartMCU(void) +{ + int ReCode; + + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_PRAM_PROG, + (uint8_t)JD9366T_SOC_PASSWORD_START_MCU); + + if (ReCode < 0) { + JD_E("%s: Start MCU fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_StopMCU(void) +{ + int ReCode; + + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_PRAM_PROG, + (uint8_t)JD9366T_SOC_PASSWORD_STOP_MCU); + + if (ReCode < 0) { + JD_E("%s: Stop MCU fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_ResetSOC(void) +{ + int ReCode; + int retry = 0; + + do { + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_RGU_0, + (uint8_t)JD9366T_SOC_PASSWORD_SOC_RESET); + } while ((++retry < 5) && (ReCode < 0)); + + if (ReCode < 0) { + JD_E("%s: Reset SOC fail\n", __func__); + } else { + g_jd9366t_chip_info.back_door_mode = false; + } + + return ReCode; +} + +static int jd9366t_ResetMCU(void) +{ + int ReCode; + + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_CPU_SOFT_RESET, + (uint8_t)JD9366T_SOC_PASSWORD_MCU_RESET); + + if (ReCode < 0) { + JD_E("%s: Reset MCU fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_PorInit(void) +{ + int ReCode; + + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_POR_INIT, + (uint8_t)JD9366T_SOC_PASSWORD_POR_CLEAR); + + if (ReCode < 0) { + JD_E("%s: Por init fail\n", __func__); + } else { + JD_I("%s: Por init\n", __func__); + } + + return ReCode; +} + +static void jd9366t_PinReset(void) +{ +#ifdef JD_RST_PIN_FUNC + JD_I("%s: Now reset the Touch chip\n", __func__); + + if (gpio_is_valid(pjadard_ts_data->rst_gpio)) { + if (gpio_request(pjadard_ts_data->rst_gpio, "jadard_reset_gpio")) { + JD_E("unable to request rst-gpio [%d]\n", pjadard_ts_data->rst_gpio); + goto err_gpio; + } + + if (gpio_direction_output(pjadard_ts_data->rst_gpio, 1)) { + JD_E("unable to set direction for rst-gpio [%d]\n", pjadard_ts_data->rst_gpio); + gpio_free(pjadard_ts_data->rst_gpio); + goto err_gpio; + } + + jadard_gpio_set_value(pjadard_ts_data->rst_gpio, 1); + mdelay(10); + jadard_gpio_set_value(pjadard_ts_data->rst_gpio, 0); + mdelay(10); + jadard_gpio_set_value(pjadard_ts_data->rst_gpio, 1); + mdelay(100); + + gpio_free(pjadard_ts_data->rst_gpio); + } else { + JD_E("rst-gpio [%d] is not valid\n", pjadard_ts_data->rst_gpio); + } + +err_gpio: +#endif + /* EnterBackDoor */ + jd9366t_EnterBackDoor(NULL); + + /* Fix MCU doesn't enable after TP HW reset */ + jd9366t_StartMCU(); +} + +static void jd9366t_SetMpapPwSync(uint8_t value) +{ + uint8_t wdata[JD_TWO_SIZE] = {0x00, 0x00}; + + wdata[0] = value; + jd9366t_WriteRegMulti(g_jd9366t_chip_info.dsram_host_addr.mpap_pw_sync, wdata, sizeof(wdata)); +} + +static int jd9366t_DisableTouchScan(void) +{ + int ReCode; + uint8_t wdata[JD_TWO_SIZE]; + + wdata[0] = 0x01; + wdata[1] = 0x98; + + jd9366t_SetMpapPwSync(0); + ReCode = jd9366t_WriteRegMulti(g_jd9366t_chip_info.dsram_host_addr.mpap_pw, wdata, sizeof(wdata)); + jd9366t_SetMpapPwSync(1); + + if (ReCode < 0) { + JD_E("%s: Disable touch scan fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_EnableTouchScan(void) +{ + return jd9366t_WriteRegSingle((uint32_t)JD9366T_STC1_REG_ADDR_AFE_SCAN_CTRL, + (uint8_t)JD9366T_STC1_RELATED_SETTING_STC_SCAN_ENABLE); +} + +static int jd9366t_DisableRTCRun(void) +{ + return jd9366t_WriteRegSingle((uint32_t)JD9366T_TIMER_REG_ADDR_RTC_CONFIG, + (uint8_t)JD9366T_TIMER_RELATED_SETTING_DISABLE_RTC_RUN); +} + +static int jd9366t_EnableRTCRun(void) +{ + return jd9366t_WriteRegSingle((uint32_t)JD9366T_TIMER_REG_ADDR_RTC_CONFIG, + (uint8_t)JD9366T_TIMER_RELATED_SETTING_ENABLE_RTC_RUN); +} + +static int jd9366t_SetFlashSPISpeed(uint8_t flash_spi_speed_level) +{ + int ReCode; + + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_BAUD_RATE, flash_spi_speed_level); + + if (ReCode < 0) { + JD_E("%s: Set flash SPI speed fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_GetFlashSPIFStatus(uint16_t usTimeOut, uint8_t *rdata) +{ + int ReCode; + uint32_t i = 0; + uint8_t usValue = (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_SPIF_BUSY; + bool spif_busy_status_done = false; + + do { + /* Read SPI status until done */ + mdelay(2); + ReCode = jd9366t_ReadRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_STATUS, &usValue); + + if (ReCode < 0) { + JD_E("%s: Read flash SPI status fail\n", __func__); + return ReCode; + } else { + i += 2; + } + + spif_busy_status_done = jd9366t_DoneStatusIsHigh(usValue, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_SPIF_DONE); + + /* Read SPI data when rdata was not NULL */ + if (rdata != NULL) { + ReCode = jd9366t_ReadRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_RDATA, rdata); + if (ReCode < 0) { + JD_E("%s: Read SPI RDATA fail\n", __func__); + return ReCode; + } + } + } while ((i < usTimeOut) && !spif_busy_status_done); + + if (i >= usTimeOut) { + JD_E("%s: Get Flash SPI status timeout\n", __func__); + return JD_TIME_OUT; + } + + return ReCode; +} + +static int jd9366t_ICSetExFlashCSNOutDisable(void) +{ + return jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_CSN_H); +} + +static int jd9366t_ICSetExFlashCSNOutEnable(void) +{ + return jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_CSN_L); +} + +static int jd9366t_ICWriteExFlashFlow(uint8_t cmd, uint32_t addr, uint16_t addr_len) +{ + int ReCode, i; + uint8_t wBuf[JD_THREE_SIZE]; + uint8_t dummy; + + /* Set SPI frequency to 12MHz */ + wBuf[0] = (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_12MHz; + + ReCode = jd9366t_WriteRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_BAUD_RATE, wBuf, 1); + if (ReCode < 0) { + JD_E("%s: Set SPI frequency to 12MHz fail\n", __func__); + return ReCode; + } + + wBuf[0] = (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_CSN_L; /* Set CSN out enable [CSN = L] */ + wBuf[1] = 0x01; /* set SPI enable */ + wBuf[2] = cmd; /* set Flash command */ + + ReCode = jd9366t_WriteRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT, wBuf, sizeof(wBuf)); + if (ReCode < 0) { + JD_E("%s: SPI setting fail\n", __func__); + return ReCode; + } + + /* Read SPI status until done */ + ReCode = jd9366t_GetFlashSPIFStatus(50, &dummy); + if (ReCode < 0) { + JD_E("%s: Get flash SPI status fail\n", __func__); + return ReCode; + } + + for (i = 0; i < addr_len; i++) { + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_WDATA, + (uint8_t)(addr >> ((addr_len - i - 1) * 8))); + if (ReCode < 0) { + JD_E("%s: Set flash SPI addrress fail\n", __func__); + return ReCode; + } + + ReCode = jd9366t_GetFlashSPIFStatus(50, &dummy); + if (ReCode < 0) { + JD_E("%s: Get flash SPI status fail\n", __func__); + return ReCode; + } + } + + /* Set CSN out disable [CSN = H] */ + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_CSN_H); + if (ReCode < 0) { + JD_E("%s: Set CSN high fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_ICReadExFlashFlow(uint8_t cmd, uint32_t addr, uint16_t addr_len, + uint8_t *rdata, uint16_t rdata_len) +{ + int ReCode, i; + uint8_t wBuf[JD_THREE_SIZE]; + uint8_t dummy; + + /* Set SPI frequency to 12MHz */ + wBuf[0] = (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_12MHz; + + ReCode = jd9366t_WriteRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_BAUD_RATE, wBuf, 1); + if (ReCode < 0) { + JD_E("%s: Set SPI frequency to 12MHz fail\n", __func__); + return ReCode; + } + + /* Set CSN out enable [CSN = L] */ + wBuf[0] = (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_CSN_L; + wBuf[1] = 0x01; /* set SPI enable */ + wBuf[2] = cmd; /* set Flash command */ + + ReCode = jd9366t_WriteRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT, wBuf, sizeof(wBuf)); + if (ReCode < 0) { + JD_E("%s: SPI setting fail\n", __func__); + return ReCode; + } + + /* Read SPI status until done */ + ReCode = jd9366t_GetFlashSPIFStatus(50, &dummy); + if (ReCode < 0) { + JD_E("%s: Get flash SPI status fail\n", __func__); + return ReCode; + } + + for (i = 0; i < addr_len; i++) { + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_WDATA, + (uint8_t)(addr >> ((addr_len - i - 1) * 8))); + if (ReCode < 0) { + JD_E("%s: Set flash SPI addrress fail\n", __func__); + return ReCode; + } + + ReCode = jd9366t_GetFlashSPIFStatus(50, &dummy); + if (ReCode < 0) { + JD_E("%s: Get flash SPI status fail\n", __func__); + return ReCode; + } + } + + for (i = 0; i < rdata_len; i++) { + /* set Dummy data */ + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_WDATA, (uint8_t)(i + 1)); + if (ReCode < 0) { + JD_E("%s: Set flash SPI read addrress fail\n", __func__); + return ReCode; + } + + /* Read SPI status until done & read SPI data */ + ReCode = jd9366t_GetFlashSPIFStatus(50, rdata + i); + if (ReCode < 0) { + JD_E("%s: Get flash SPI status fail\n", __func__); + return ReCode; + } + } + + /* Set CSN out disable [CSN = H] */ + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_CSN_H); + if (ReCode < 0) { + JD_E("%s: Set CSN high fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_ICGetExFlashStatus(uint16_t usTimeOut) +{ + int ReCode; + uint32_t i = 0; + uint8_t usValue = (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_FLASH_BUSY; + bool flash_busy_status_done = false; + + do { + /* Set CSN out enable [CSN = L] */ + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_CSN_L); + if (ReCode < 0) { + JD_E("%s: Set CSN low fail\n", __func__); + return ReCode; + } + + /* Set read flash status start */ + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_DMA_2WFLASHEN_1WRITE_0START, + (uint8_t)JD9366T_DMA_RELATED_SETTING_READ_FLASH_STATUS); + if (ReCode < 0) { + JD_E("%s: Set read flash status start fail\n", __func__); + return ReCode; + } + + /* Wait Flash Status Register 1 ready */ + mdelay(5); + + /* Set CSN out disable [CSN = H] */ + ReCode = jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_CSN_H); + if (ReCode < 0) { + JD_E("%s: Set CSN high fail\n", __func__); + return ReCode; + } + + /* Read Ex-Flash status until done */ + ReCode = jd9366t_ReadRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_DMA_BUSY_OR_START, &usValue); + if (ReCode < 0) { + JD_E("%s: Read Ex-Flash status fail\n", __func__); + return ReCode; + } else { + i += 5; + } + + flash_busy_status_done = jd9366t_DoneStatusIsLow(usValue, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_FLASH_BUSY, + (uint8_t)JD9366T_MASTER_SPI_RELATED_SETTING_FLASH_DONE); + } while ((i < usTimeOut) && !flash_busy_status_done); + + if (i >= usTimeOut) { + JD_E("%s: Get Ex-Flash status timeout\n", __func__); + return JD_TIME_OUT; + } + + return ReCode; +} + +static int jd9366t_EraseSector(uint32_t addr) +{ + int ReCode; + + /* Write enable */ + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_WRITE_ENABLE, 0, 0); + if (ReCode < 0) { + JD_E("%s: Set write enable fail\n", __func__); + return ReCode; + } + + /* Erase cmd */ + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_ERASE_SECTOR, addr, 3); + if (ReCode < 0) { + JD_E("%s: Set erase cmd fail\n", __func__); + return ReCode; + } + + msleep((uint16_t)JD9366T_FLASH_RUN_TIME_ERASE_SECTOR_TIME); + + /* Read Ex-Flash status until done */ + ReCode = jd9366t_ICGetExFlashStatus(50); + if (ReCode < 0) { + JD_E("%s: Read Ex-Flash status fail\n", __func__); + } + + return ReCode; +} + +static int jd9366t_EraseBlock_32K(uint32_t addr) +{ + int ReCode; + + /* Write enable */ + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_WRITE_ENABLE, 0, 0); + if (ReCode < 0) { + JD_E("%s: Set write enable fail\n", __func__); + return ReCode; + } + + /* Erase cmd */ + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_ERASE_BLOCK_32K, addr, 3); + if (ReCode < 0) { + JD_E("%s: Set erase 32k cmd fail\n", __func__); + return ReCode; + } + + msleep((uint16_t)JD9366T_FLASH_RUN_TIME_ERASE_BLOCK_32K_TIME); + + /* Read Ex-Flash status until done */ + ReCode = jd9366t_ICGetExFlashStatus(50); + if (ReCode < 0) { + JD_E("%s: Read Ex-Flash status fail\n", __func__); + } + return ReCode; +} + +static int jd9366t_EraseBlock_64K(uint32_t addr) +{ + int ReCode; + + /* Write enable */ + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_WRITE_ENABLE, 0, 0); + if (ReCode < 0) { + JD_E("%s: Set write enable fail\n", __func__); + return ReCode; + } + + /* Erase cmd */ + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_ERASE_BLOCK_64K, addr, 3); + if (ReCode < 0) { + JD_E("%s: Set erase 64k cmd fail\n", __func__); + return ReCode; + } + + msleep((uint16_t)JD9366T_FLASH_RUN_TIME_ERASE_BLOCK_64K_TIME); + + /* Read Ex-Flash status until done */ + ReCode = jd9366t_ICGetExFlashStatus(50); + if (ReCode < 0) { + JD_E("%s: Read Ex-Flash status fail\n", __func__); + } + return ReCode; +} + +static int jd9366t_EraseChip(void) +{ + int ReCode; + + /* Write enable */ + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_WRITE_ENABLE, 0, 0); + if (ReCode < 0) { + JD_E("%s: Set write enable fail\n", __func__); + return ReCode; + } + + /* Erase cmd */ + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_ERASE_CHIP, 0, 0); + if (ReCode < 0) { + JD_E("%s: Set erase chip cmd fail\n", __func__); + return ReCode; + } + + msleep((uint16_t)JD9366T_FLASH_RUN_TIME_ERASE_CHIP_TIME); + + /* Read Ex-Flash status until done */ + ReCode = jd9366t_ICGetExFlashStatus(50); + if (ReCode < 0) { + JD_E("%s: Read Ex-Flash status fail\n", __func__); + } + return ReCode; +} + +static int jd9366t_EraseChipFlash(uint32_t addr, uint32_t len) +{ + int ReCode, i; + int sector_start = 0; + int sector_end = 0; + + if ((addr + len) > (JD9366T_SIZE_DEF_BLOCK_64K * 2)) { + ReCode = jd9366t_EraseChip(); + if (ReCode < 0) { + JD_E("%s: Erase flash timeout error\n", __func__); + return ReCode; + } + } else { + sector_start = (int)(addr >> 12); + + if (((addr + len) & 0xFFF) == 0) { + sector_end = (int)((addr + len) >> 12); + } else { + sector_end = (int)((addr + len) >> 12) + 1; + } + + for (i = sector_start; i < sector_end;/* Acc in loop */) { + if ((i == 0 || i == 16) && (sector_end - i) >= 16) { + /* 64KB BLOCK ERASE */ + ReCode = jd9366t_EraseBlock_64K((uint32_t)(i << 12)); + if (ReCode < 0) { + JD_E("%s: Erase 64KB block timeout error\n", __func__); + return ReCode; + } else { + i += 16; + JD_D("%s: EraseStart %08x\n", __func__, (uint32_t)(i << 12)); + JD_D("%s: Size 64KB\n", __func__); + JD_D("%s: Erase 64KB block finish\n", __func__); + } + } else if ((i == 0 || i == 8 || i == 16 || i == 24) && (sector_end - i) >= 8) { + /* 32KB BLOCK ERASE */ + ReCode = jd9366t_EraseBlock_32K((uint32_t)(i << 12)); + if (ReCode < 0) { + JD_E("%s: Erase 32KB block timeout error\n", __func__); + return ReCode; + } else { + i += 8; + JD_D("%s: EraseStart %08x\n", __func__, (uint32_t)(i << 12)); + JD_D("%s: Size 32KB\n", __func__); + JD_D("%s: Erase 32KB block finish\n", __func__); + } + } else { + /* SECTOR ERASE */ + ReCode = jd9366t_EraseSector((uint32_t)(i << 12)); + if (ReCode < 0) { + JD_E("%s: Erase sector timeout error\n", __func__); + return ReCode; + } else { + i++; + JD_D("%s: EraseStart %08x\n", __func__, (uint32_t)(i << 12)); + JD_D("%s: Size 4KB\n", __func__); + JD_D("%s: Erase KB block finish\n", __func__); + } + } + } + } + + return ReCode; +} + +static bool jd9366t_GetSectionFirstValueStatus(uint16_t usTimeOut) +{ + uint32_t i = 0; + uint8_t rbuf[JD_TWO_SIZE]; + bool section_first_value_status_done = false; + + do { + /* Pulling section ready == JD9366T_SECTION_INFO_READY_VALUE */ + mdelay(2); + if (jd9366t_ReadRegMulti(g_jd9366t_section_info.section_info_ready_addr, rbuf, sizeof(rbuf)) < 0) { + JD_E("%s: Read section info fail\n", __func__); + return false; + } else { + i += 2; + } + + if (((rbuf[1] << 8) + rbuf[0]) == JD9366T_SECTION_INFO_READY_VALUE) { + section_first_value_status_done = true; + } else { + section_first_value_status_done = false; + } + } while ((i < usTimeOut) && !section_first_value_status_done); + + if (i >= usTimeOut) { + JD_E("%s: Get section status timeout\n", __func__); + return false; + } + + return section_first_value_status_done; +} + +static int jd9366t_GetSectionInfo(uint32_t start_addr, uint8_t section_num, struct JD9366T_INFO_CONTENT *info_content) +{ + int ReCode, i; + uint8_t info_content_size = (uint8_t)sizeof(struct JD9366T_INFO_CONTENT); + uint8_t *rbuf = NULL; + int rbuf_len = section_num * info_content_size; + + rbuf = kzalloc(rbuf_len * sizeof(uint8_t), GFP_KERNEL); + if (rbuf == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + ReCode = jd9366t_ReadRegMulti(start_addr, rbuf, rbuf_len); + if (ReCode < 0) { + JD_E("%s: Read section info fail\n", __func__); + kfree(rbuf); + return ReCode; + } + + if (info_content_size == 8) { + for (i = 0; i < section_num; i++) { + info_content[i].info_content_addr = (uint32_t)(rbuf[i * info_content_size + 0] + + (rbuf[i * info_content_size + 1] << 8) + + (rbuf[i * info_content_size + 2] << 16) + + (rbuf[i * info_content_size + 3] << 24)); + + info_content[i].info_content_len = (uint32_t)(rbuf[i * info_content_size + 4] + + (rbuf[i * info_content_size + 5] << 8) + + (rbuf[i * info_content_size + 6] << 16) + + (rbuf[i * info_content_size + 7] << 24)); + } + } else { + JD_E("%s: info_content_size was not 8, must to check flow\n", __func__); + } + + kfree(rbuf); + return ReCode; +} + +static int jd9366t_ReadSectionInfo(bool reinit_config) +{ + int ReCode, i; + struct JD9366T_INFO_CONTENT dsram_info_content[JD9366T_MAX_DSRAM_NUM]; + struct JD9366T_INFO_CONTENT esram_info_content[JD9366T_MAX_ESRAM_NUM]; + uint8_t rbuf[JD_SIX_SIZE]; + bool reinit = false; + + /* 1. Get section ready */ + if (jd9366t_GetSectionFirstValueStatus(50) == true) { + /* 2. Get section address */ + jd9366t_GetSectionInfo(g_jd9366t_section_info.dsram_section_info_start_addr, + JD9366T_DSRAM_TEMPERATURE_CONFIG + 1, &dsram_info_content[0]); + + jd9366t_GetSectionInfo(g_jd9366t_section_info.esram_section_info_start_addr, + JD9366T_ESRAM_DDREG_DATA_BUF + 1, &esram_info_content[0]); + + /* 2.1 Dump section info */ + for (i = 0; i <= JD9366T_DSRAM_TEMPERATURE_CONFIG; i++) { + /* Mapping to enum JD9366T_DSRAM_SECTION_INFO_ORDER */ + JD_D("%s: Dsram section(%d) Address: 0x%04x, Length: %d\n", __func__, i, + dsram_info_content[i].info_content_addr, + dsram_info_content[i].info_content_len); + } + + for (i = 0; i <= JD9366T_ESRAM_DDREG_DATA_BUF; i++) { + /* Mapping to enum JD9366T_ESRAM_SECTION_INFO_ORDER */ + JD_D("%s: Esram section(%d) Address: 0x%04x, Length: %d\n", __func__, i, + esram_info_content[i].info_content_addr, + esram_info_content[i].info_content_len); + } + + /* 3.1 Set Coordinate addr. and length */ + g_jd9366t_chip_info.esram_info_content_addr.coordinate_report = + esram_info_content[JD9366T_ESRAM_COORDINATE_REPORT].info_content_addr; + pjadard_report_data->touch_data_size = esram_info_content[JD9366T_ESRAM_COORDINATE_REPORT].info_content_len; + + if (pjadard_report_data->touch_data_size > JD_TOUCH_DATA_SIZE) { + JD_E("%s: FW report packet size %d is greater than Driver %d\n", __func__, + pjadard_report_data->touch_data_size, JD_TOUCH_DATA_SIZE); + } + + /* 3.2 Set output_buf addr. */ + g_jd9366t_chip_info.esram_info_content_addr.output_buf = + esram_info_content[JD9366T_ESRAM_OUTPUT_BUF].info_content_addr; + + /* 3.3 Set ADC number and resolution */ + ReCode = jd9366t_ReadRegMulti(dsram_info_content[JD9366T_DSRAM_FW_CFG].info_content_addr, + rbuf, sizeof(rbuf)); + if (ReCode < 0) { + JD_E("%s: Update global config fail\n", __func__); + } else { + /* Update global config */ + if ((pjadard_ic_data) && (pjadard_ts_data) && (pjadard_ts_data->pdata)) { + if ((pjadard_ic_data->JD_X_NUM != rbuf[4]) || (pjadard_ic_data->JD_Y_NUM != rbuf[5])) { + /* Set adc number by FW */ + pjadard_ic_data->JD_X_NUM = rbuf[4]; + pjadard_ic_data->JD_Y_NUM = rbuf[5]; + JD_I("FW:panel-sense-num = %d, %d\n", pjadard_ic_data->JD_X_NUM, pjadard_ic_data->JD_Y_NUM); +#ifdef CONFIG_TOUCHSCREEN_JADARD_DEBUG + if (jd_diag_mutual) { + kfree(jd_diag_mutual); + jd_diag_mutual = NULL; + } + + /* Reallocate mutual data memory */ + jd_diag_mutual = kzalloc(pjadard_ic_data->JD_X_NUM * + pjadard_ic_data->JD_Y_NUM * sizeof(int), GFP_KERNEL); + if (jd_diag_mutual == NULL) { + JD_E("%s: mutual buffer allocate failed\n", __func__); + } +#endif + } + + if (reinit_config) { + pjadard_ts_data->pdata->abs_x_min = 0; + pjadard_ts_data->pdata->abs_x_max = (int)((rbuf[1] << 8) + rbuf[0]); + pjadard_ts_data->pdata->abs_y_min = 0; + pjadard_ts_data->pdata->abs_y_max = (int)((rbuf[3] << 8) + rbuf[2]); + + if (pjadard_ic_data->JD_X_RES != pjadard_ts_data->pdata->abs_x_max) { + pjadard_ic_data->JD_X_RES = pjadard_ts_data->pdata->abs_x_max; + reinit = true; + } + + if (pjadard_ic_data->JD_Y_RES != pjadard_ts_data->pdata->abs_y_max) { + pjadard_ic_data->JD_Y_RES = pjadard_ts_data->pdata->abs_y_max; + reinit = true; + } + + if (reinit) { + /* Touch input config reinit */ + input_unregister_device(pjadard_ts_data->input_dev); + + if (jadard_input_register(pjadard_ts_data)) { + JD_E("%s: Unable to register %s input device\n", + __func__, pjadard_ts_data->input_dev->name); + } + } + } + } else { + JD_E("%s: Can`t update global config, pjadard_ic_data/pjadard_ts_data/pdata was null\n", __func__); + } + + /* Record JD9366T_DSRAM_FW_CFG_INFO_ADDR */ + g_jd9366t_chip_info.dsram_fw_cfg_info_addr.fw_cid_version = + dsram_info_content[JD9366T_DSRAM_FW_CFG_INFO].info_content_addr; + g_jd9366t_chip_info.dsram_fw_cfg_info_addr.panel_maker = + dsram_info_content[JD9366T_DSRAM_FW_CFG_INFO].info_content_addr + 4; + g_jd9366t_chip_info.dsram_fw_cfg_info_addr.panel_version = + dsram_info_content[JD9366T_DSRAM_FW_CFG_INFO].info_content_addr + 5; + g_jd9366t_chip_info.dsram_fw_cfg_info_addr.fw_version = + dsram_info_content[JD9366T_DSRAM_FW_CFG_INFO].info_content_addr + 7; + /* Record JD9366T_DSRAM_HOST_ADDR */ + g_jd9366t_chip_info.dsram_host_addr.game_mode_en = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 30; + g_jd9366t_chip_info.dsram_host_addr.usb_en = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 32; + g_jd9366t_chip_info.dsram_host_addr.gesture_en = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 34; + g_jd9366t_chip_info.dsram_host_addr.high_sensitivity_en = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 36; + g_jd9366t_chip_info.dsram_host_addr.border_en = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 38; + g_jd9366t_chip_info.dsram_host_addr.proximity_en = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 44; + g_jd9366t_chip_info.dsram_host_addr.earphone_en = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 58; +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_jd9366t_chip_info.dsram_host_addr.mpap_pw = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 40; + g_jd9366t_chip_info.dsram_host_addr.mpap_handshake = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 42; + g_jd9366t_chip_info.dsram_host_addr.mpap_keep_frame = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 43; + g_jd9366t_chip_info.dsram_host_addr.mpap_skip_frame = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 52; + g_jd9366t_chip_info.dsram_host_addr.mpap_mux_switch = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 53; + g_jd9366t_chip_info.dsram_host_addr.fw_dbic_en = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 54; + g_jd9366t_chip_info.dsram_host_addr.mpap_pw_sync = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 74; + g_jd9366t_chip_info.dsram_host_addr.mpap_bypass_main = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 80; + g_jd9366t_chip_info.dsram_host_addr.mpap_error_msg = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 82; + /* Set mapa diff max/min addr */ + g_jd9366t_chip_info.dsram_host_addr.mpap_diff_max = + dsram_info_content[JD9366T_DSRAM_MPAP_DIFF_MAX].info_content_addr; + g_jd9366t_chip_info.dsram_host_addr.mpap_diff_min = + dsram_info_content[JD9366T_DSRAM_MPAP_DIFF_MIN].info_content_addr; +#else + g_jd9366t_chip_info.dsram_host_addr.mpap_pw = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 40; + g_jd9366t_chip_info.dsram_host_addr.mpap_pw_sync = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 74; +#endif + g_jd9366t_chip_info.dsram_host_addr.data_output_v2 = + dsram_info_content[JD9366T_DSRAM_HOST].info_content_addr + 86; + /* Record JD9366T_DSRAM_DEBUG_ADDR */ + g_jd9366t_chip_info.dsram_debug_addr.output_data_sel = + dsram_info_content[JD9366T_DSRAM_DEBUG].info_content_addr + 34; + g_jd9366t_chip_info.dsram_debug_addr.output_data_handshake = + dsram_info_content[JD9366T_DSRAM_DEBUG].info_content_addr + 36; + g_jd9366t_chip_info.dsram_debug_addr.freq_band = + dsram_info_content[JD9366T_DSRAM_DEBUG].info_content_addr + 40; + + pjadard_ts_data->fw_ready = true; + JD_I("%s: Section info was ready\n", __func__); + } + } else { + pjadard_ts_data->fw_ready = false; + JD_E("%s: Section info was not ready\n", __func__); + ReCode = JD_APP_START_FAIL; + } + + return ReCode; +} + +static int jd9366t_ClearSectionFirstValue(void) +{ + return jd9366t_WriteRegSingle(g_jd9366t_section_info.section_info_ready_addr, 0x00); +} + +static int jd9366t_SetCRCInitial(void) +{ + uint8_t wBuf[JD_ONE_SIZE]; + + wBuf[0] = 0x01; + return jd9366t_WriteRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_CRC_INIT, wBuf, sizeof(wBuf)); +} + +static int jd9366t_SetCRCInitialValue(void) +{ + uint8_t wBuf[JD_TWO_SIZE]; + + wBuf[(uint32_t)JD9366T_CRC_CODE_POSITION_HIGH_BYTE] = + (uint8_t)((JD9366T_CRC_INFO_CRC_INITIAL_VALUE & 0xFF00) >> 8); + wBuf[(uint32_t)JD9366T_CRC_CODE_POSITION_LOW_BYTE] = + (uint8_t)((JD9366T_CRC_INFO_CRC_INITIAL_VALUE & 0x00FF) >> 0); + + return jd9366t_WriteRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_CRC_INIT_CODE1, wBuf, sizeof(wBuf)); +} + +static int jd9366t_SetCRCEnable(bool enable) +{ + return jd9366t_WriteRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_CRC_ENABLE, enable); +} + +static int jd9366t_GetCRCResult(uint16_t *crc) +{ + int ReCode; + uint8_t rBuf[JD_TWO_SIZE]; + + ReCode = jd9366t_ReadRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_CRC_CHK1, rBuf, sizeof(rBuf)); + if (ReCode < 0) { + *crc = 0; + } else { + *crc = (uint16_t)((rBuf[(uint32_t)JD9366T_CRC_CODE_POSITION_HIGH_BYTE] << 8) + + rBuf[(uint32_t)JD9366T_CRC_CODE_POSITION_LOW_BYTE]); + } + + return ReCode; +} + +static void jd9366t_GetDataCRC16(uint8_t *buf, uint32_t buf_len, uint32_t start_index, + uint32_t len, uint16_t *crc, uint16_t PolynomialCRC16) +{ + uint32_t i, j; + uint16_t sum = *crc; + + for (i = 0; i < len; i++) { + if ((start_index + i) >= buf_len) { + sum ^= (uint16_t)(0xFF << 8); + } else { + sum ^= (uint16_t)(buf[start_index + i] << 8); + } + + for (j = 0; j < 8; j++) { + if ((sum & 0x8000) == 0x8000) + sum = (uint16_t)((sum << 1) ^ PolynomialCRC16); + else + sum <<= 1; + } + } + + *crc = sum; +} + +static uint32_t jd9366t_Pow(uint8_t base, uint32_t pow) +{ + uint32_t i; + uint32_t sum = 1; + + if (pow > 0) { + for (i = 0; i < pow; i++) { + sum *= base; + } + } + + return sum; +} + +static int jd9366t_JEDEC_ID(uint8_t *id) +{ + int ReCode; + uint8_t rdbuf[JD_THREE_SIZE]; + + ReCode = jd9366t_ICReadExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_READ_ID, 0, 0, rdbuf, sizeof(rdbuf)); + if (ReCode < 0) { + JD_E("%s: Read external flash fail\n", __func__); + return ReCode; + } + + if (id != NULL) { + *id = rdbuf[2]; + } + + JD_I("Flash RDID: 0x%02x%02x%02x\n", rdbuf[0], rdbuf[1], rdbuf[2]); + + if ((rdbuf[0] == 0x00) || (rdbuf[0] == 0xFF)) { + JD_E("%s: Flash was not exist\n", __func__); + } else { + JD_I("Flash capacity: %d KB\n", jd9366t_Pow(2, rdbuf[2] - 10)); + } + + /* Read flash status1 status*/ + ReCode = jd9366t_ICReadExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_STATUS_REGISTER1, 0, 0, rdbuf, 1); + if (ReCode < 0) { + JD_E("%s: Read external flash status1 fail\n", __func__); + return ReCode; + } + + JD_I("Flash Status1: 0x%02x\n", rdbuf[0]); + + /* Read flash status2 status*/ + ReCode = jd9366t_ICReadExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_STATUS_REGISTER2, 0, 0, rdbuf, 1); + if (ReCode < 0) { + JD_E("%s: Read external flash status2 fail\n", __func__); + return ReCode; + } + + JD_I("Flash Status2: 0x%02x\n", rdbuf[0]); + + return ReCode; +} + +static int jd9366t_CheckSize(uint8_t data, uint32_t length) +{ + int ReCode = JD_NO_ERR; + + if (jd9366t_Pow(2, data) < length) { + ReCode = JD_WRITE_OVERFLOW; + JD_E("%s: Write size was overflow\n", __func__); + } + + return ReCode; +} + +static int jd9366t_GetDMAStatus(uint16_t usTimeOut) +{ + int ReCode; + uint32_t i = 0; + uint8_t usValue = (uint8_t)JD9366T_DMA_RELATED_SETTING_DMA_BUSY; + bool dma_busy_status_done = false; + + do { + /* Pulling DMA busy = JD9366T_DMA_RELATED_SETTING_DMA_DONE */ + mdelay(2); + ReCode = jd9366t_ReadRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_DMA_BUSY_OR_START, &usValue); + + if (ReCode < 0) { + JD_E("%s: Read DMA_BUSY_OR_START register fail\n", __func__); + return ReCode; + } else { + i += 2; + } + + dma_busy_status_done = jd9366t_DoneStatusIsLow(usValue, (uint8_t)JD9366T_DMA_RELATED_SETTING_DMA_BUSY, + (uint8_t)JD9366T_DMA_RELATED_SETTING_DMA_DONE); + } while ((i < usTimeOut) && !dma_busy_status_done); + + if (i >= usTimeOut) { + JD_E("%s: Get DMA status timeout\n", __func__); + return JD_TIME_OUT; + } + + return ReCode; +} + +static int jd9366t_GetPageProgramStatus(uint16_t usTimeOut) +{ + int ReCode; + uint32_t i = 0; + uint8_t usValue = (uint8_t)JD9366T_DMA_RELATED_SETTING_PAGE_PROGRAM_FLASH; + bool dma_page_program_status_done = false; + + do { + /* Pulling DMA Page Program = JD9366T_DMA_RELATED_SETTING_PAGE_PROGRAM_DONE */ + mdelay(2); + ReCode = jd9366t_ReadRegSingle((uint32_t)JD9366T_FLASH_REG_ADDR_DMA_2WFLASHEN_1WRITE_0START, &usValue); + + if (ReCode < 0) { + JD_E("%s: Read DMA_2WFLASHEN_1WRITE_0START register fail\n", __func__); + return ReCode; + } else { + i += 2; + } + + dma_page_program_status_done = jd9366t_DoneStatusIsLow(usValue, (uint8_t)JD9366T_DMA_RELATED_SETTING_PAGE_PROGRAM_FLASH, + (uint8_t)JD9366T_DMA_RELATED_SETTING_PAGE_PROGRAM_DONE); + } while ((i < usTimeOut) && !dma_page_program_status_done); + + if (i >= usTimeOut) { + JD_E("%s: Get DMA status timeout\n", __func__); + return JD_TIME_OUT; + } + + return ReCode; +} + +/* +static void jd9366t_ReArrangePageProgramInfo(uint32_t ori_addr, uint32_t ori_len , uint32_t *page_addr , uint32_t *page_len) +{ + *page_addr = ori_addr - (ori_addr % JD9366T_SIZE_DEF_PAGE_SIZE); + *page_len = ((ori_len + (ori_addr % JD9366T_SIZE_DEF_PAGE_SIZE)) % JD9366T_SIZE_DEF_PAGE_SIZE) > 0 ? + ((((ori_len + (ori_addr % JD9366T_SIZE_DEF_PAGE_SIZE)) >> 8) + 1) << 8) : + (ori_len + (ori_addr % JD9366T_SIZE_DEF_PAGE_SIZE)); +} +*/ + +static int jd9366t_SetDMAStart(uint32_t flash_addr, uint32_t dma_size, uint32_t target_addr, uint8_t dma_cmd) +{ + int ReCode; + uint8_t wBuf[JD_SIX_SIZE + JD_SEVEN_SIZE]; + + if (dma_cmd == (uint8_t)JD9366T_DMA_RELATED_SETTING_WRITE_TO_FLASH) { + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_WRITE_ENABLE, 0, 0); + if (ReCode < 0) { + JD_E("%s: Set write enable fail\n", __func__); + return ReCode; + } + } + + if ((dma_cmd == (uint8_t)JD9366T_DMA_RELATED_SETTING_READ_FROM_FLASH) || + (dma_cmd == (uint8_t)JD9366T_DMA_RELATED_SETTING_WRITE_TO_FLASH)) { + ReCode = jd9366t_ICSetExFlashCSNOutEnable(); + if (ReCode < 0) { + JD_E("%s: Set CSN enable fail\n", __func__); + return ReCode; + } + } + + wBuf[0] = (uint8_t)((flash_addr & 0x000000FF) >> 0); /* Set flash_addr 0byte */ + wBuf[1] = (uint8_t)((flash_addr & 0x0000FF00) >> 8); /* Set flash_addr 1byte */ + wBuf[2] = (uint8_t)((flash_addr & 0x00FF0000) >> 16); /* Set flash_addr 2byte */ + wBuf[3] = (uint8_t)((flash_addr & 0xFF000000) >> 24); /* Set flash_addr 3byte */ + + wBuf[4] = (uint8_t)((dma_size & 0x000000FF) >> 0); /* Set dma_size 0byte */ + wBuf[5] = (uint8_t)((dma_size & 0x0000FF00) >> 8); /* Set dma_size 1byte */ + wBuf[6] = (uint8_t)((dma_size & 0x00FF0000) >> 16); /* Set dma_size 2byte */ + wBuf[7] = (uint8_t)((dma_size & 0xFF000000) >> 24); /* Set dma_size 3byte */ + + wBuf[8] = (uint8_t)((target_addr & 0x000000FF) >> 0); /* Set target_addr 0byte */ + wBuf[9] = (uint8_t)((target_addr & 0x0000FF00) >> 8); /* Set target_addr 1byte */ + wBuf[10] = (uint8_t)((target_addr & 0x00FF0000) >> 16); /* Set target_addr 2byte */ + wBuf[11] = (uint8_t)((target_addr & 0xFF000000) >> 24); /* Set target_addr 3byte */ + wBuf[12] = dma_cmd; /* dma_1write_0start */ + + ReCode = jd9366t_WriteRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_DMA_FLASH_ADDR0, wBuf, sizeof(wBuf)); + if (ReCode < 0) { + JD_E("%s: Set DMA parameters fail\n", __func__); + return ReCode; + } + + if (dma_cmd == (uint8_t)JD9366T_DMA_RELATED_SETTING_PAGE_PROGRAM_FLASH) { + /* Pulling DMA Page Program = JD9366T_DMA_RELATED_SETTING_PAGE_PROGRAM_DONE */ + mdelay(1); + ReCode = jd9366t_GetPageProgramStatus(50); + if (ReCode < 0) { + JD_E("%s: Get DMA page program status fail\n", __func__); + return ReCode; + } + } else { + /* Pulling DMA busy = JD9366T_DMA_RELATED_SETTING_DMA_DONE */ + ReCode = jd9366t_GetDMAStatus(50); + if (ReCode < 0) { + JD_E("%s: Get DMA status fail\n", __func__); + return ReCode; + } + } + + if ((dma_cmd == (uint8_t)JD9366T_DMA_RELATED_SETTING_READ_FROM_FLASH) || + (dma_cmd == (uint8_t)JD9366T_DMA_RELATED_SETTING_WRITE_TO_FLASH)) { + ReCode = jd9366t_ICSetExFlashCSNOutDisable(); + if (ReCode < 0) { + JD_E("%s: Set CSN disable fail\n", __func__); + } + } + + return ReCode; +} + +static int jd9366t_SetDMAByteMode(void) +{ + uint8_t wBuf[JD_ONE_SIZE]; + + wBuf[0] = (uint8_t)JD9366T_DMA_RELATED_SETTING_TRANSFER_DATA_1_BYTE_MODE; + + return jd9366t_WriteRegMulti((uint32_t)JD9366T_FLASH_REG_ADDR_DMA_BYTE_MODE, wBuf, sizeof(wBuf)); +} + +#ifdef JD_ZERO_FLASH +static uint8_t jd9366t_GetMoveInfoNumber(uint8_t *pFileData) +{ + if (pFileData[JD9366T_HW_HEADER_LEN] == 0xFF) { + return 0; + } else { + return (uint8_t)((pFileData[JD9366T_HW_HEADER_LEN] - JD9366T_HW_HEADER_CRC_NUMBER) / + JD9366T_HW_HEADER_MOVE_INFO_NUMBER); + } +} + +static void jd9366t_GetHeaderInfo(uint8_t *pFileData, struct JD9366T_MOVE_INFO *move_info, int move_info_sz) +{ + int i; + int header_shift = JD9366T_HW_HEADER_CRC_NUMBER + JD9366T_HW_HEADER_INITIAL_NUMBER; + + for (i = 0; i < move_info_sz; i++) { + move_info[i].mov_mem_cmd = + pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 0]; + + move_info[i].fl_st_addr = + (uint32_t)((pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 1] << 16) + + (pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 2] << 8) + + (pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 3] << 0)); + + move_info[i].fl_len = + (uint32_t)((pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 4] << 8) + + (pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 5] << 0) + 1); + + move_info[i].to_mem_st_addr = + (uint32_t)((pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 6] << 24) + + (pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 7] << 16) + + (pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 8] << 8) + + (pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 9] << 0)); + + move_info[i].to_mem_crc = + (uint16_t)((pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 10] << 8) + + (pFileData[header_shift + i * JD9366T_HW_HEADER_MOVE_INFO_NUMBER + 11] << 0)); + } +} + +static uint8_t jd9366t_GetHeaderPsramIndex(struct JD9366T_MOVE_INFO *move_info, int move_info_sz) +{ + int i; + uint8_t index = 0; + + for (i = 0; i < move_info_sz; i++) { + if (move_info[i].to_mem_st_addr == JD9366T_HW_HEADER_PSRAM_START_ADDR) { + index = (uint8_t)i; + break; + } + } + + JD_I("%s: Header Psram Index = %d\n", __func__, index); + return index; +} +#endif + +/* +static uint8_t jd9366t_GetMoveInfoPsramNumber(struct JD9366T_MOVE_INFO *move_info, int move_info_sz) +{ + int i; + uint8_t num = 0; + + for (i = 0; i < move_info_sz; i++) { + if (move_info[i].to_mem_st_addr <= JD9366T_PRAM_MAX_SIZE) + num++; + } + + return num; +} +*/ + +static int jd9366t_ReadFlash(uint32_t addr, uint8_t *rdata, uint32_t rlen) +{ + int ReCode; + uint16_t packsize = (uint16_t)JD9366T_FLASH_PACK_READ_SIZE; + uint32_t pos = 0; + uint16_t packlen = 0; + /* MCU aram config */ + uint16_t ramsize = 2048; + uint32_t ramaddr = 0; + uint16_t ramlen = 0; + /* DMA config */ + uint32_t flashaddr = addr; + uint32_t targetaddr = (uint32_t)JD9366T_MEMORY_ADDR_ARAM; + /* Read buf */ + uint8_t *rBuf = NULL; + + rBuf = kzalloc(packsize * sizeof(uint8_t), GFP_KERNEL); + if (rBuf == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + /* Set CRC initial value */ + ReCode = jd9366t_SetCRCInitialValue(); + if (ReCode < 0) { + JD_E("%s: Set CRC initial value fail\n", __func__); + kfree(rBuf); + return ReCode; + } + + /* Set CRC Initial */ + ReCode = jd9366t_SetCRCInitial(); + if (ReCode < 0) { + JD_E("%s: Set CRC initial fail\n", __func__); + kfree(rBuf); + return ReCode; + } + + /* Read start */ + while (rlen > 0) { + if (rlen > ramsize) + ramlen = ramsize; + else + ramlen = (uint16_t)rlen; + + /* Set next ram addr */ + rlen -= ramlen; + ramaddr = (uint32_t)JD9366T_MEMORY_ADDR_ARAM; + + /* Set DMA Start & Pulling DMA busy = JD9366T_DMA_RELATED_SETTING_DMA_DONE */ + JD_D("%s: Flash DMA start\n", __func__); + + ReCode = jd9366t_SetDMAStart(flashaddr, ramlen, targetaddr, + (uint8_t)JD9366T_DMA_RELATED_SETTING_READ_FROM_FLASH); + if (ReCode < 0) { + JD_E("%s: DMA start error\n", __func__); + kfree(rBuf); + return ReCode; + } else { + JD_D("%s: DMA start finish\n", __func__); + } + + /* Read from ram */ + while (ramlen > 0) { + if (ramlen > packsize) + packlen = packsize; + else + packlen = (uint16_t)ramlen; + + /* Read Data from ARAM */ + ReCode = jd9366t_ReadRegMulti(ramaddr, rBuf, packlen); + if (ReCode < 0) { + JD_E("%s: Read ARAM data fail\n", __func__); + kfree(rBuf); + return ReCode; + } else { + memcpy(rdata + pos, rBuf, packlen); + } + + /* Set next packet */ + ramlen -= packlen; + pos += packlen; + ramaddr += packlen; + flashaddr += packlen; + } + + JD_D("%s: Read flash data %d KB...\n", __func__, (uint16_t)((flashaddr - addr) / 1024)); + } + + kfree(rBuf); + return ReCode; +} + +static int jd9366t_WriteFlash(uint32_t addr, uint32_t wlen, uint8_t *data, uint32_t data_len) +{ + int ReCode, i; + uint16_t packsize = (uint16_t)JD9366T_FLASH_PACK_WRITE_SIZE; + uint32_t pos = addr; + uint16_t packlen = 0; + /* MCU aram config */ + uint16_t ramsize = 256; + uint32_t ramaddr = 0; + uint16_t ramlen = 0; + /* DMA config */ +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + uint32_t start_flashaddr = addr; +#endif + uint32_t flashaddr = 0; + uint16_t dmasize = 0; + uint32_t targetaddr = (uint32_t)JD9366T_MEMORY_ADDR_ARAM; + /* Write buf */ + uint8_t *wBuf = NULL; + + wBuf = kzalloc(packsize * sizeof(uint8_t), GFP_KERNEL); + if (wBuf == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + /* Set CRC initial value */ + ReCode = jd9366t_SetCRCInitialValue(); + if (ReCode < 0) { + JD_E("%s: Set CRC initial value fail\n", __func__); + kfree(wBuf); + return ReCode; + } + + /* Set CRC Initial */ + ReCode = jd9366t_SetCRCInitial(); + if (ReCode < 0) { + JD_E("%s: Set CRC initial fail\n", __func__); + kfree(wBuf); + return ReCode; + } + + /* Write start */ + while (wlen > 0) { + if (wlen > ramsize) + ramlen = ramsize; + else + ramlen = (uint16_t)wlen; + + flashaddr = addr; + dmasize = ramlen; + /* Set next ram addr */ + wlen -= ramlen; + ramaddr = (uint32_t)JD9366T_MEMORY_ADDR_ARAM; + + /* Write to ram */ + while (ramlen > 0) { + if (ramlen > packsize) + packlen = packsize; + else + packlen = (uint16_t)ramlen; + + for (i = 0; i < packlen; i++) { + if (data_len > addr) + wBuf[i] = data[pos + i]; + else + wBuf[i] = data[i]; + } + + /* Write Data to ARAM */ + ReCode = jd9366t_WriteRegMulti(ramaddr, wBuf, packlen); + if (ReCode < 0) { + JD_E("%s: Write data to ARAM fail\n", __func__); + kfree(wBuf); + return ReCode; + } + + /* Set next packet */ + ramlen -= packlen; + pos += packlen; + ramaddr += packlen; + addr += packlen; + } + + /* Set DMA Start & Pulling DMA busy = JD9366T_DMA_RELATED_SETTING_DMA_DONE */ + ReCode = jd9366t_SetDMAStart(flashaddr, dmasize, targetaddr, + (uint8_t)JD9366T_DMA_RELATED_SETTING_WRITE_TO_FLASH); + if (ReCode < 0) { + JD_E("%s: DMA start error\n", __func__); + kfree(wBuf); + return ReCode; + } else { + JD_D("%s: Flash DMA start\n", __func__); + } + + JD_D("%s: Write flash data %d KB...\n", __func__, (uint16_t)((flashaddr - start_flashaddr) / 1024)); + } + + ReCode = jd9366t_ICWriteExFlashFlow((uint8_t)JD9366T_EX_FLASH_ADDR_WRITE_DISABLE, 0, 0); + if (ReCode < 0) { + JD_E("%s: Write flash disable fail\n", __func__); + } + + kfree(wBuf); + return ReCode; +} + +static int jd9366t_CheckFlashContent(uint8_t *pFileData, uint32_t addr, uint32_t len) +{ + int ReCode, i; + uint32_t error_count = 0; + uint8_t *pData = kzalloc(len * sizeof(uint8_t), GFP_KERNEL); + + if (pData == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + ReCode = jd9366t_ReadFlash(addr, pData, len); + if (ReCode < 0) { + kfree(pData); + return ReCode; + } + + for (i = 0; i < len; i++) { + if (pFileData[addr + i] != pData[i]) { + JD_E("%s: Error data[%d]=0x%02x, Current data[%d]=0x%02x\n", __func__, i, pData[i], i, pFileData[addr + i]); + error_count++; + if (error_count > 5) { + kfree(pData); + return JD_CHECK_DATA_ERROR; + } + } + } + + kfree(pData); + return ReCode; +} + +static int jd9366t_HostReadFlash(uint32_t ReadAddr, uint8_t *pDataBuffer, uint32_t ReadLen) +{ + int ReCode; + uint16_t romid = 0; + uint16_t crc, softcrc; + + /* 1. Enter backdoor & 2. Read IC ID */ + ReCode = jd9366t_EnterBackDoor(&romid); + if (ReCode < 0) + return ReCode; + + /* 3.1 IC RTC run off */ + ReCode = jd9366t_DisableRTCRun(); + if (ReCode < 0) + return ReCode; + + /* 3.2 IC touch scan off */ + ReCode = jd9366t_DisableTouchScan(); + if (ReCode < 0) + return ReCode; + + /* 3.3 Set DMA 1-byte mode */ + ReCode = jd9366t_SetDMAByteMode(); + if (ReCode < 0) + return ReCode; + + /* 4-1. Stop WDT */ + ReCode = jd9366t_DisableWDTRun(); + if (ReCode < 0) { + return ReCode; + } + + /* 4-2. Stop MCU clock */ + ReCode = jd9366t_StopMCUClock(); + if (ReCode < 0) { + return ReCode; + } + + /* 5. Set Flash SPI speed & 6. Read Flash id */ + ReCode = jd9366t_JEDEC_ID(NULL); + if (ReCode < 0) { + return ReCode; + } + + /* 7. Read data from flash */ + JD_I("%s: Read flash start\n", __func__); + ReCode = jd9366t_ReadFlash(ReadAddr, pDataBuffer, ReadLen); + if (ReCode < 0) { + JD_E("%s: Read flash error\n", __func__); + return ReCode; + } else { + JD_I("%s: Read flash finish\n", __func__); + } + + /* 8-1. Get IC crc */ + ReCode = jd9366t_GetCRCResult(&crc); + if (ReCode < 0) { + JD_E("%s: Read flash ecc fail\n", __func__); + return ReCode; + } + + /* 8-2. Calculate software crc */ + softcrc = JD9366T_CRC_INFO_CRC_INITIAL_VALUE; + jd9366t_GetDataCRC16(pDataBuffer, ReadLen, 0, ReadLen, &softcrc, JD9366T_CRC_INFO_PolynomialCRC16); + + /* 8-3. Compare IC and software crc */ + if (softcrc != crc) { + JD_E("%s: softEcc is %04x, but read IC crc is %04x\n", __func__, softcrc, crc); + } + + /* 9.1 IC RTC run on */ + ReCode = jd9366t_EnableRTCRun(); + if (ReCode < 0) + return ReCode; + + /* 9.2 IC touch scan on */ + ReCode = jd9366t_EnableTouchScan(); + if (ReCode < 0) + return ReCode; + + /* 9.3 start MCU clock */ + ReCode = jd9366t_StartMCUClock(); + if (ReCode < 0) + return ReCode; + + return ReCode; +} + +static int jd9366t_HostWriteFlash(uint32_t WriteAddr, uint8_t *pFileData, uint32_t FileSize) +{ + int ReCode; + uint32_t WriteLen = 0; + uint16_t romid = 0; + uint16_t crc, softcrc; + uint8_t *crcbuffer = NULL; + uint8_t id; + int retry = 0; + + do { + /* 0. Check WriteAddr is a multiple of 256 */ + if (WriteAddr % JD9366T_SIZE_DEF_PAGE_SIZE != 0) { + JD_E("%s: WriteAddr: 0x%08x was not a multiple of 256\n", __func__, WriteAddr); + return JD_CHECK_DATA_ERROR; + } + + /* 1. Enter backdoor & 2. Read IC ID */ + ReCode = jd9366t_EnterBackDoor(&romid); + if (ReCode < 0) + return ReCode; + + /* 3.1 IC RTC run off */ + ReCode = jd9366t_DisableRTCRun(); + if (ReCode < 0) + return ReCode; + + /* 3.2 IC touch scan off */ + ReCode = jd9366t_DisableTouchScan(); + if (ReCode < 0) + return ReCode; + + /* 3.3 Set DMA 1-byte mode */ + ReCode = jd9366t_SetDMAByteMode(); + if (ReCode < 0) + return ReCode; + + /* 3.4 Clear section first value */ + ReCode = jd9366t_ClearSectionFirstValue(); + if (ReCode < 0) + return ReCode; + + /* 4-1. Stop WDT */ + ReCode = jd9366t_DisableWDTRun(); + if (ReCode < 0) { + return ReCode; + } + + /* 4-2. Stop MCU clock */ + ReCode = jd9366t_StopMCUClock(); + if (ReCode < 0) { + return ReCode; + } + + /* 5. Set Flash SPI speed & Read Flash id */ + ReCode = jd9366t_JEDEC_ID(&id); + if (ReCode < 0) { + return ReCode; + } + + /* 6. Check flash size is enough */ + ReCode = jd9366t_CheckSize(id, FileSize); + if (ReCode < 0) { + return ReCode; + } + + /* 7. Erase flash */ + JD_I("%s: Erase flash start, Start Address: 0x%08x, Size: %d\n", __func__, WriteAddr, FileSize); + ReCode = jd9366t_EraseChipFlash(WriteAddr, FileSize); + if (ReCode < 0) { + JD_E("%s: Flash erase fail\n", __func__); + return ReCode; + } else { + JD_I("%s: Erase Flash completed\n", __func__); + } + + /* 8. Set CRC disable */ + ReCode = jd9366t_SetCRCEnable(false); + if (ReCode < 0) { + JD_E("%s: CRC disable fail\n", __func__); + return ReCode; + } + + /* 9. Set Flash SPI speed */ + ReCode = jd9366t_SetFlashSPISpeed(pFileData[JD9366T_LOAD_CODE_SPI_FREQ]); + if (ReCode < 0) { + return ReCode; + } + + /* 10. write data to flash-1 */ + JD_I("%s: Write flash start\n", __func__); + + WriteLen = FileSize; + + ReCode = jd9366t_WriteFlash(WriteAddr, WriteLen, pFileData, FileSize); + if (ReCode < 0) { + JD_E("%s: Write flash fail\n", __func__); + return ReCode; + } else { + JD_I("%s: Write flash finish\n", __func__); + } + + if (FileSize >= WriteAddr + WriteLen) { + /* 11-1. get IC crc */ + ReCode = jd9366t_GetCRCResult(&crc); + if (ReCode < 0) { + JD_E("%s: Read flash ecc fail\n", __func__); + return ReCode; + } + + /* 11-2. calculate software crc */ + softcrc = JD9366T_CRC_INFO_CRC_INITIAL_VALUE; + crcbuffer = kzalloc(WriteLen * sizeof(uint8_t), GFP_KERNEL); + if (crcbuffer == NULL) { + JD_E("%s: Memory allocate fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + memcpy(crcbuffer, pFileData + WriteAddr, WriteLen); + jd9366t_GetDataCRC16(crcbuffer, WriteLen, 0, WriteLen, &softcrc, JD9366T_CRC_INFO_PolynomialCRC16); + kfree(crcbuffer); + + /* 11-3. check IC and software crc */ + if (softcrc != crc) { + JD_E("%s: softEcc is %04x, but read IC crc is %04x\n", __func__, softcrc, crc); + } else { + JD_I("%s: CRC check pass\n", __func__); + } + } + + /* 12. Read back Flash content [option] */ + ReCode = jd9366t_CheckFlashContent(pFileData, 0, 256); + retry = ReCode; + + /* 13-0. Clear PorInit, if upgrade succss */ + if (ReCode >= 0) { + jd9366t_PorInit(); + } + + /* 13. Reset IC touch soc */ + ReCode = jd9366t_ResetSOC(); + if (ReCode < 0) { + JD_E("%s: Reset touch soc fail\n", __func__); + } else { + JD_I("%s: Reset touch soc\n", __func__); + } + } while (retry < 0); + + /* Wait flash reload to Pram */ + msleep(100); + + /* 14. Enter back door & read IC id */ + ReCode = jd9366t_EnterBackDoor(&romid); + if (ReCode < 0) + return ReCode; + + /* 15. Set Flash SPI speed */ + ReCode = jd9366t_SetFlashSPISpeed(pFileData[JD9366T_LOAD_CODE_SPI_FREQ]); + if (ReCode < 0) { + return ReCode; + } + + /* 16. Reload section info. */ + ReCode = jd9366t_ReadSectionInfo(false); + + return ReCode; +} + +#ifdef JD_ZERO_FLASH +static int jd9366t_WritePram(uint32_t addr, uint8_t *pData, uint32_t len) +{ + int ReCode; + uint16_t packsize = (uint16_t)JD9366T_FLASH_PACK_WRITE_SIZE; + uint32_t pos = 0; + uint16_t packlen = 0; + /* MCU aram config */ + uint32_t ramaddr = addr; + uint32_t ramlen = len; + + /* Write start */ + if (len > 0) { + JD_I("%s: Start write ram addr: 0x%08x\n", __func__, ramaddr); + JD_I("%s: Write pram data %d bytes\n", __func__, ramlen); + + /* Write to ram */ + while (ramlen > 0) { + if (ramlen > packsize) + packlen = packsize; + else + packlen = (uint16_t)ramlen; + + /* Write Data to PRAM/ARAM */ + ReCode = jd9366t_WriteRegMulti(ramaddr, pData + pos, packlen); + if (ReCode < 0) { + JD_E("%s: Write data to PRAM/ARAM fail\n", __func__); + return ReCode; + } + + /* Set next packet */ + ramlen -= packlen; + pos += packlen; + ramaddr += packlen; + } + } + + /* Set CRC initial value */ + ReCode = jd9366t_SetCRCInitialValue(); + if (ReCode < 0) { + JD_E("%s: Set CRC initial value fail\n", __func__); + return ReCode; + } + + /* Set CRC Initial */ + ReCode = jd9366t_SetCRCInitial(); + if (ReCode < 0) { + JD_E("%s: Set CRC initial fail\n", __func__); + return ReCode; + } + + /* Set DMA Start & Pulling DMA busy = JD9366T_DMA_RELATED_SETTING_DMA_DONE */ + ReCode = jd9366t_SetDMAStart(addr, len, addr, (uint8_t)JD9366T_DMA_RELATED_SETTING_WRITE_TO_PRAM); + if (ReCode < 0) { + JD_E("%s: DMA start error\n", __func__); + return ReCode; + } else { + JD_I("%s: DMA start finish\n", __func__); + } + + return ReCode; +} + +static int jd9366t_HostWritePram(uint32_t WriteAddr, uint8_t *pFileData, uint32_t FileSize) +{ + int ReCode, i; + uint16_t romid = 0; + uint16_t crc, softcrc; + uint8_t MoveInfoNumber; + uint8_t MoveInfoPsramIndex = 0; + struct JD9366T_MOVE_INFO *MoveInfo = NULL; + + /* 1. Enter backdoor & 2. Read IC ID */ + ReCode = jd9366t_EnterBackDoor(&romid); + if (ReCode < 0) + return ReCode; + + /* 3.1 IC RTC run off */ + ReCode = jd9366t_DisableRTCRun(); + if (ReCode < 0) + return ReCode; + + /* 3.2 IC touch scan off */ + ReCode = jd9366t_DisableTouchScan(); + if (ReCode < 0) + return ReCode; + + /* 3.3 Set DMA 1-byte mode */ + ReCode = jd9366t_SetDMAByteMode(); + if (ReCode < 0) + return ReCode; + + /* 3.4 Clear section first value */ + ReCode = jd9366t_ClearSectionFirstValue(); + if (ReCode < 0) + return ReCode; + + /* 4-1. Stop WDT */ + ReCode = jd9366t_DisableWDTRun(); + if (ReCode < 0) { + return ReCode; + } + + /* 4-2. Stop MCU */ + ReCode = jd9366t_StopMCU(); + if (ReCode < 0) { + return ReCode; + } + + /* 5. Stop MCU clock */ + ReCode = jd9366t_StopMCUClock(); + if (ReCode < 0) { + return ReCode; + } + + /* 6. Get header info.*/ + MoveInfoNumber = jd9366t_GetMoveInfoNumber(pFileData); + MoveInfo = kzalloc(MoveInfoNumber * sizeof(struct JD9366T_MOVE_INFO), GFP_KERNEL); + + if (MoveInfo == NULL) { + JD_E("%s: Memory allocate fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + jd9366t_GetHeaderInfo(pFileData, MoveInfo, MoveInfoNumber); + MoveInfoPsramIndex = jd9366t_GetHeaderPsramIndex(MoveInfo, MoveInfoNumber); + + /* START: Check need upgrade fw */ + if (pjadard_ts_data->power_on_upgrade == false) { + /* Set CRC initial value */ + ReCode = jd9366t_SetCRCInitialValue(); + if (ReCode < 0) { + JD_E("%s: [Check ram]Set CRC initial value fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* Set CRC Initial */ + ReCode = jd9366t_SetCRCInitial(); + if (ReCode < 0) { + JD_E("%s: [Check ram]Set CRC initial fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* Set DMA Start & Pulling DMA busy = JD9366T_DMA_RELATED_SETTING_DMA_DONE */ + ReCode = jd9366t_SetDMAStart(MoveInfo[MoveInfoPsramIndex].to_mem_st_addr, MoveInfo[MoveInfoPsramIndex].fl_len, MoveInfo[MoveInfoPsramIndex].to_mem_st_addr, + (uint8_t)JD9366T_DMA_RELATED_SETTING_WRITE_TO_PRAM); + if (ReCode < 0) { + JD_E("%s: [Check ram]DMA start error\n", __func__); + kfree(MoveInfo); + return ReCode; + } else { + JD_D("%s: [Check ram]DMA start finish\n", __func__); + } + + + /* Get IC crc */ + ReCode = jd9366t_GetCRCResult(&crc); + if (ReCode < 0) { + JD_E("%s: [Check ram]Read crc fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* Check IC crc */ + if (crc != MoveInfo[MoveInfoPsramIndex].to_mem_crc) { + JD_D("%s: [Check ram]Binary crc is %04x, but read IC crc is %04x\n", __func__, MoveInfo[MoveInfoPsramIndex].to_mem_crc, crc); + } else { + JD_I("%s: [Check ram]HW CRC check pass, bypass upgrade flow\n", __func__); + goto SKIP_UPGRADE_FW; + } + } + /* END: Check need upgrade fw */ + + /* 7. Write data to PRAM/DRAM */ + JD_I("%s: Write ram start\n", __func__); + + for (i = 0; i < MoveInfoNumber; i++) { + pjadard_ts_data->power_on_upgrade = false; + + if ((MoveInfo[i].fl_st_addr + MoveInfo[i].fl_len) > FileSize) { + JD_E("%s: Write ram overflow\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + ReCode = jd9366t_WritePram(MoveInfo[i].to_mem_st_addr, pFileData + MoveInfo[i].fl_st_addr, MoveInfo[i].fl_len); + if (ReCode < 0) { + JD_E("%s: Write pram fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* 8-1. Get IC crc */ + ReCode = jd9366t_GetCRCResult(&crc); + if (ReCode < 0) { + JD_E("%s: Read crc fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* 8-2. Check IC crc */ + if (crc != MoveInfo[i].to_mem_crc) { + JD_E("%s: Binary crc is %04x, but read IC crc is %04x\n", __func__, MoveInfo[i].to_mem_crc, crc); + kfree(MoveInfo); + return ReCode; + } else { + JD_I("%s: HW CRC check pass\n", __func__); + } + + /* 8-3. Calculate software crc */ + softcrc = JD9366T_CRC_INFO_CRC_INITIAL_VALUE; + jd9366t_GetDataCRC16(pFileData + MoveInfo[i].fl_st_addr, MoveInfo[i].fl_len, 0, MoveInfo[i].fl_len, &softcrc, JD9366T_CRC_INFO_PolynomialCRC16); + + /* 8-4. check software crc */ + if (softcrc != MoveInfo[i].to_mem_crc) { + JD_E("%s: Binary crc is %04x, but soft crc is %04x\n", __func__, MoveInfo[i].to_mem_crc, softcrc); + kfree(MoveInfo); + return ReCode; + } else { + JD_I("%s: Software CRC check pass\n", __func__); + } + } + + /* 8-5. Clear PorInit */ + jd9366t_PorInit(); + +SKIP_UPGRADE_FW: + kfree(MoveInfo); + JD_I("%s: Write ram finish\n", __func__); + + /* 9. Software reset MCU */ + ReCode = jd9366t_ResetSOC(); + /* ReCode = jd9366t_ResetMCU(); */ + if (ReCode < 0) { + return ReCode; + } else { + JD_I("%s: Reset touch mcu\n", __func__); + } + + /* 10. Start MCU clock */ + ReCode = jd9366t_StartMCUClock(); + if (ReCode < 0) { + return ReCode; + } else { + JD_I("%s: Start MCU clock\n", __func__); + } + + /* 11. start MCU */ + ReCode = jd9366t_StartMCU(); + if (ReCode < 0) { + return ReCode; + } else { + JD_I("%s: Start MCU\n", __func__); + } + + /* 12. Reload section info. */ + ReCode = jd9366t_ReadSectionInfo(false); + + return ReCode; +} + +#ifdef JD_ESD_CHECK +static int jd9366t_esd_HostWritePram(uint32_t WriteAddr, uint8_t *pFileData, uint32_t FileSize) +{ + int ReCode, i; + uint16_t romid = 0; + uint16_t crc, softcrc; + uint8_t MoveInfoNumber; + uint8_t MoveInfoPsramIndex = 0; + struct JD9366T_MOVE_INFO *MoveInfo = NULL; + + ReCode = jd9366t_SetDMAByteMode(); + + /* 6. Get header info.*/ + MoveInfoNumber = jd9366t_GetMoveInfoNumber(pFileData); + MoveInfo = kzalloc(MoveInfoNumber * sizeof(struct JD9366T_MOVE_INFO), GFP_KERNEL); + + if (MoveInfo == NULL) { + JD_E("%s: Memory allocate fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + jd9366t_GetHeaderInfo(pFileData, MoveInfo, MoveInfoNumber); + MoveInfoPsramIndex = jd9366t_GetHeaderPsramIndex(MoveInfo, MoveInfoNumber); + + /* START: Check need upgrade fw */ + if (pjadard_ts_data->power_on_upgrade == false) { +JD_PRAM_CRC_RECHECK: + /* Set CRC initial value */ + ReCode = jd9366t_SetCRCInitialValue(); + if (ReCode < 0) { + JD_E("%s: [Check ram]Set CRC initial value fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* Set CRC Initial */ + ReCode = jd9366t_SetCRCInitial(); + if (ReCode < 0) { + JD_E("%s: [Check ram]Set CRC initial fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* Set DMA Start & Pulling DMA busy = JD9366T_DMA_RELATED_SETTING_DMA_DONE */ + ReCode = jd9366t_SetDMAStart(MoveInfo[MoveInfoPsramIndex].to_mem_st_addr, MoveInfo[MoveInfoPsramIndex].fl_len, MoveInfo[MoveInfoPsramIndex].to_mem_st_addr, + (uint8_t)JD9366T_DMA_RELATED_SETTING_WRITE_TO_PRAM); + if (ReCode < 0) { + JD_E("%s: [Check ram]DMA start error\n", __func__); + kfree(MoveInfo); + return ReCode; + } else { + JD_D("%s: [Check ram]DMA start finish\n", __func__); + } + + /* Get IC crc */ + ReCode = jd9366t_GetCRCResult(&crc); + if (ReCode < 0) { + JD_E("%s: [Check ram]Read crc fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* Check IC crc */ + if (crc != MoveInfo[MoveInfoPsramIndex].to_mem_crc) { + JD_I("%s: [Check ram]Binary crc is %04x, but read IC crc is %04x\n", __func__, MoveInfo[MoveInfoPsramIndex].to_mem_crc, crc); + + if (pjadard_report_data->crc_start == 1) { + if (pjadard_report_data->crc_retry >= 2) { + pjadard_report_data->crc_retry = 0; + JD_I("%s: Upgrade\n", __func__); + } else { + pjadard_report_data->crc_retry++; + JD_I("%s: Recheck CRC\n", __func__); + msleep(500); + goto JD_PRAM_CRC_RECHECK; + } + } + + jadard_int_enable(false); + } else { + JD_I("%s: [Check ram]HW CRC check pass, bypass upgrade flow\n", __func__); + + if (pjadard_report_data->crc_start == 1) { + JD_I("%s: Clear crc_retry\n", __func__); + pjadard_report_data->crc_retry = 0; + } + + kfree(MoveInfo); + return JD_PRAM_CRC_PASS; + } + } + /* END: Check need upgrade fw */ + + /* 1. Enter backdoor & 2. Read IC ID */ + ReCode = jd9366t_EnterBackDoor(&romid); + if (ReCode < 0) { + kfree(MoveInfo); + return ReCode; + } + + /* 3.1 IC RTC run off */ + ReCode = jd9366t_DisableRTCRun(); + if (ReCode < 0) { + kfree(MoveInfo); + return ReCode; + } + + /* 3.2 IC touch scan off */ + ReCode = jd9366t_DisableTouchScan(); + if (ReCode < 0) { + kfree(MoveInfo); + return ReCode; + } + + /* 3.3 Set DMA 1-byte mode */ + ReCode = jd9366t_SetDMAByteMode(); + if (ReCode < 0) { + kfree(MoveInfo); + return ReCode; + } + + /* 3.4 Clear section first value */ + ReCode = jd9366t_ClearSectionFirstValue(); + if (ReCode < 0) { + kfree(MoveInfo); + return ReCode; + } + + /* 4-1. Stop WDT */ + ReCode = jd9366t_DisableWDTRun(); + if (ReCode < 0) { + kfree(MoveInfo); + return ReCode; + } + + /* 4-2. Stop MCU */ + ReCode = jd9366t_StopMCU(); + if (ReCode < 0) { + kfree(MoveInfo); + return ReCode; + } + + /* 5. Stop MCU clock */ + ReCode = jd9366t_StopMCUClock(); + if (ReCode < 0) { + kfree(MoveInfo); + return ReCode; + } + + /* 7. Write data to PRAM/DRAM */ + JD_I("%s: Write ram start\n", __func__); + + for (i = 0; i < MoveInfoNumber; i++) { + pjadard_ts_data->power_on_upgrade = false; + + if ((MoveInfo[i].fl_st_addr + MoveInfo[i].fl_len) > FileSize) { + JD_E("%s: Write ram overflow\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + ReCode = jd9366t_WritePram(MoveInfo[i].to_mem_st_addr, pFileData + MoveInfo[i].fl_st_addr, MoveInfo[i].fl_len); + if (ReCode < 0) { + JD_E("%s: Write pram fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* 8-1. Get IC crc */ + ReCode = jd9366t_GetCRCResult(&crc); + if (ReCode < 0) { + JD_E("%s: Read crc fail\n", __func__); + kfree(MoveInfo); + return ReCode; + } + + /* 8-2. Check IC crc */ + if (crc != MoveInfo[i].to_mem_crc) { + JD_E("%s: Binary crc is %04x, but read IC crc is %04x\n", __func__, MoveInfo[i].to_mem_crc, crc); + kfree(MoveInfo); + return ReCode; + } else { + JD_I("%s: HW CRC check pass\n", __func__); + } + + /* 8-3. Calculate software crc */ + softcrc = JD9366T_CRC_INFO_CRC_INITIAL_VALUE; + jd9366t_GetDataCRC16(pFileData + MoveInfo[i].fl_st_addr, MoveInfo[i].fl_len, 0, MoveInfo[i].fl_len, &softcrc, JD9366T_CRC_INFO_PolynomialCRC16); + + /* 8-4. check software crc */ + if (softcrc != MoveInfo[i].to_mem_crc) { + JD_E("%s: Binary crc is %04x, but soft crc is %04x\n", __func__, MoveInfo[i].to_mem_crc, softcrc); + kfree(MoveInfo); + return ReCode; + } else { + JD_I("%s: Software CRC check pass\n", __func__); + } + } + + /* 8-5. Clear PorInit */ + /* jd9366t_PorInit(); */ + + kfree(MoveInfo); + JD_I("%s: Write ram finish\n", __func__); + + /* 9. Software reset MCU */ + ReCode = jd9366t_ResetSOC(); + if (ReCode < 0) { + return ReCode; + } else { + JD_I("%s: Reset touch mcu\n", __func__); + } + + /* 10. Start MCU clock */ + ReCode = jd9366t_StartMCUClock(); + if (ReCode < 0) { + return ReCode; + } else { + JD_I("%s: Start MCU clock\n", __func__); + } + + /* 11. start MCU */ + ReCode = jd9366t_StartMCU(); + if (ReCode < 0) { + return ReCode; + } else { + JD_I("%s: Start MCU\n", __func__); + } + + /* 12. Reload section info. */ + ReCode = jd9366t_ReadSectionInfo(false); + + return ReCode; +} +#endif +#endif + +static int jd9366t_ReadPram(uint32_t addr, uint8_t *pData, uint32_t len) +{ + int ReCode; + uint16_t packsize = (uint16_t)JD9366T_FLASH_PACK_READ_SIZE; + uint32_t pos = 0; + uint16_t packlen = 0; + /* MCU ram config */ + uint32_t ramaddr = addr; + uint32_t ramlen = len; + /* Read buf */ + uint8_t *rBuf = NULL; + + rBuf = kzalloc(packsize * sizeof(uint8_t), GFP_KERNEL); + if (rBuf == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + /* Read start */ + if (len > 0) { + JD_I("%s: Start read ram addr: 0x%08x\n", __func__, ramaddr); + JD_I("%s: Read ram data %d bytes\n", __func__, ramlen); + + /* Read from ram */ + while (ramlen > 0) { + if (ramlen > packsize) + packlen = packsize; + else + packlen = (uint16_t)ramlen; + + /* Read Data from ram */ + ReCode = jd9366t_ReadRegMulti(ramaddr, rBuf, packlen); + if (ReCode < 0) { + JD_E("%s: Read ram data fail\n", __func__); + kfree(rBuf); + return ReCode; + } else { + memcpy(pData + pos, rBuf, packlen); + } + + /* Set next packet */ + ramlen -= packlen; + pos += packlen; + ramaddr += packlen; + } + } + + /* Set CRC initial value */ + ReCode = jd9366t_SetCRCInitialValue(); + if (ReCode < 0) { + JD_E("%s: Set CRC initial value fail\n", __func__); + kfree(rBuf); + return ReCode; + } + + /* Set CRC Initial */ + ReCode = jd9366t_SetCRCInitial(); + if (ReCode < 0) { + JD_E("%s: Set CRC initial fail\n", __func__); + kfree(rBuf); + return ReCode; + } + + /* Set DMA Start & Pulling DMA busy = JD9366T_DMA_RELATED_SETTING_DMA_DONE */ + ReCode = jd9366t_SetDMAStart(addr, len, addr, (uint8_t)JD9366T_DMA_RELATED_SETTING_WRITE_TO_PRAM); + if (ReCode < 0) { + JD_E("%s: DMA start error\n", __func__); + kfree(rBuf); + return ReCode; + } else { + JD_I("%s: DMA start finish\n", __func__); + } + + kfree(rBuf); + return ReCode; +} + +static int jd9366t_HostReadPram(uint32_t ReadAddr, uint8_t *pFileData, uint32_t ReadLen) +{ + int ReCode; + uint16_t romid = 0; + uint16_t crc, softcrc; + + /* 1. Enter backdoor & 2. Read IC ID */ + ReCode = jd9366t_EnterBackDoor(&romid); + if (ReCode < 0) + return ReCode; + + /* 3.1 Set DMA 1-byte mode */ + ReCode = jd9366t_SetDMAByteMode(); + if (ReCode < 0) + return ReCode; + + /* 3.2 Stop MCU */ + ReCode = jd9366t_StopMCU(); + if (ReCode < 0) { + return ReCode; + } + + /* 4-1. Stop WDT */ + ReCode = jd9366t_DisableWDTRun(); + if (ReCode < 0) { + return ReCode; + } + + /* 4-2. Stop MCU clock */ + ReCode = jd9366t_StopMCUClock(); + if (ReCode < 0) { + return ReCode; + } + + /* 5. Read data from PRAM/DRAM */ + JD_I("%s: Read ram start\n", __func__); + ReCode = jd9366t_ReadPram(ReadAddr, pFileData, ReadLen); + if (ReCode < 0) { + JD_E("%s: Read ram error\n", __func__); + return ReCode; + } else { + JD_I("%s: Read ram finish\n", __func__); + } + + /* 6-1. Get IC crc */ + ReCode = jd9366t_GetCRCResult(&crc); + if (ReCode < 0) { + JD_E("%s: Read flash ecc fail\n", __func__); + return ReCode; + } + + /* 6-2. Calculate software crc */ + softcrc = JD9366T_CRC_INFO_CRC_INITIAL_VALUE; + jd9366t_GetDataCRC16(pFileData, ReadLen, ReadAddr, ReadLen, &softcrc, JD9366T_CRC_INFO_PolynomialCRC16); + + /* 6-3. Compare IC and software crc */ + if (softcrc != crc) { + JD_E("%s: softEcc is %04x, but read IC crc is %04x\n", __func__, softcrc, crc); + } + + /* 7. Start MCU clock */ + ReCode = jd9366t_StartMCUClock(); + if (ReCode >= 0) { + JD_I("%s: Start MCU clock\n", __func__); + } + + /* 8. start MCU */ + ReCode = jd9366t_StartMCU(); + if (ReCode < 0) { + return ReCode; + } else { + JD_I("%s: Start MCU\n", __func__); + } + + msleep(10); + + return ReCode; +} + +static int jd9366t_ReadTpInfoBuf(uint8_t *rdata, uint16_t rlen) +{ + return jd9366t_ReadRegMulti(g_jd9366t_chip_info.esram_info_content_addr.coordinate_report, rdata, rlen); +} + +static void module_jd9366t_chip_init(void) +{ + JD_I("%s\n", __func__); + /* Jadard: Set FW and CFG Flash Address */ + g_common_variable.FW_SIZE = JD9366T_SIZE; + g_common_variable.RAM_LEN = JD9366T_PRAM_MAX_SIZE; + jd9366t_ChipInfoInit(); + +#ifndef JD_ZERO_FLASH + /* Reload section info. */ + if (jd9366t_ReadSectionInfo(false) < 0) { + JD_E("Chip init fail\n"); + } else { + g_module_fp.fp_read_fw_ver(); + } +#endif +} + +static void module_jd9366t_EnterBackDoor(void) +{ + jd9366t_EnterBackDoor(NULL); +} + +static void module_jd9366t_ExitBackDoor(void) +{ + jd9366t_ExitBackDoor(); +} + +static void module_jd9366t_PinReset(void) +{ + jd9366t_PinReset(); +} + +static void module_jd9366t_SoftReset(void) +{ + /* Reset IC touch soc */ + if (jd9366t_ResetSOC() < 0) { + JD_E("%s: Reset touch soc fail\n", __func__); + return; + } else { + JD_I("%s: Reset touch soc\n", __func__); + } + + /* Wait flash reload to Pram, Add Flash */ + msleep(100); + + /* Enter back door */ + jd9366t_EnterBackDoor(NULL); +} + +static void module_jd9366t_ResetMCU(void) +{ + jd9366t_ResetMCU(); +} + +static void module_jd9366t_PorInit(void) +{ + jd9366t_PorInit(); +} + +static int module_jd9366t_register_read(uint32_t ReadAddr, uint8_t *ReadData, uint32_t ReadLen) +{ + int ReCode; + + if (ReadLen & 0xFFFF0000) { + ReCode = JD_READ_LEN_OVERFLOW; + } else { + ReCode = jd9366t_ReadRegMulti(ReadAddr, ReadData, (uint16_t)ReadLen); + } + + return ReCode; +} + +static uint8_t module_jd9366t_DbicReg_write(uint8_t page, uint8_t cmd, uint8_t *par, uint8_t par_len) +{ + uint8_t i; + uint8_t write_run = JD_DBIC_WRITE_RUN; + uint8_t mpap_sleep_password[JD_TWO_SIZE]; + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_Off(); + mdelay(100); +#endif + + switch (cmd) { + case 0x10: + mpap_sleep_password[0] = JD9366T_MPAP_PW_SLEEP_IN_hbyte; + mpap_sleep_password[1] = JD9366T_MPAP_PW_SLEEP_IN_lbyte; + g_module_fp.fp_set_sleep_mode(mpap_sleep_password, sizeof(mpap_sleep_password)); + break; + case 0x11: + mpap_sleep_password[0] = JD9366T_MPAP_PW_SLEEP_OUT_hbyte; + mpap_sleep_password[1] = JD9366T_MPAP_PW_SLEEP_OUT_lbyte; + g_module_fp.fp_set_sleep_mode(mpap_sleep_password, sizeof(mpap_sleep_password)); + break; + default: + /* Setup cmd & length */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_CMD, &cmd, 1); + mdelay(14); + + g_module_fp.fp_register_write((uint32_t)JD_DBIC_CMD_LEN, &par_len, 1); + mdelay(14); + + /* Enable transfer */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_SPI_RUN, &write_run, 1); + mdelay(13); + + /* Write parameter */ + for (i = 0; i < par_len; i++) { + /* Write */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_WRITE_DATA, par+i, 1); + } + break; + } + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + return JD_DBIC_READ_WRITE_SUCCESS; +} + +static uint8_t module_jd9366t_DbicReg_read(uint8_t page, uint8_t cmd, uint8_t *rpar, uint8_t rpar_len, uint32_t offset) +{ + uint8_t i; + uint8_t read_run = JD_DBIC_READ_RUN; + uint8_t irq_valid_msk = JD_DBIC_IRQ_VALID_MSK; + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_Off(); + mdelay(100); +#endif + + /* Setup cmd & length */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_CMD, &cmd, 1); + mdelay(14); + + g_module_fp.fp_register_write((uint32_t)JD_DBIC_CMD_LEN, &rpar_len, 1); + mdelay(14); + + /* Enable transfer */ + g_module_fp.fp_register_write((uint32_t)JD_DBIC_SPI_RUN, &read_run, 1); + + /* Read parameter */ + for (i = 0; i < rpar_len; i++) { + mdelay(7); + g_module_fp.fp_register_read((uint32_t)JD_DBIC_READ_DATA, rpar+i, 1); + g_module_fp.fp_register_write((uint32_t)JD_DBIC_INT_CLR, &irq_valid_msk, 1); + } + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_Fw_DBIC_On(); +#endif + return JD_DBIC_READ_WRITE_SUCCESS; +} + +static void module_jd9366t_set_sleep_mode(uint8_t *value, uint8_t value_len) +{ + jd9366t_SetMpapPwSync(0); + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.mpap_pw, value, value_len); + jd9366t_SetMpapPwSync(1); +} + +static int module_jd9366t_ram_read(uint32_t ReadAddr, uint8_t *ReadBuffer, uint32_t ReadLen) +{ + return jd9366t_HostReadPram(ReadAddr, ReadBuffer, ReadLen); +} + +#ifdef JD_ZERO_FLASH +static int module_jd9366t_ram_write(uint32_t WriteAddr, uint8_t *WriteBuffer, uint32_t WriteLen) +{ + return jd9366t_HostWritePram(WriteAddr, WriteBuffer, WriteLen); +} + +#ifdef JD_ESD_CHECK +static int module_jd9366t_esd_ram_write(uint32_t WriteAddr, uint8_t *WriteBuffer, uint32_t WriteLen) +{ + return jd9366t_esd_HostWritePram(WriteAddr, WriteBuffer, WriteLen); +} +#endif +#endif + +static int module_jd9366t_flash_read(uint32_t ReadAddr, uint8_t *ReadBuffer, uint32_t ReadLen) +{ + return jd9366t_HostReadFlash(ReadAddr, ReadBuffer, ReadLen); +} + +static int module_jd9366t_flash_write(uint32_t WriteAddr, uint8_t *WriteData, uint32_t WriteLen) +{ + return jd9366t_HostWriteFlash(WriteAddr, WriteData, WriteLen); +} + +static int module_jd9366t_flash_erase(void) +{ + return jd9366t_EraseChip(); +} + +static void module_jd9366t_read_fw_ver(void) +{ + int ReCode_cid, ReCode_ver, ReCode_maker, ReCode_panel, maker_id; + uint8_t rdata_cid[JD_FOUR_SIZE], rdata_fw[JD_THREE_SIZE], rdata_maker[JD_ONE_SIZE], rdata_panel[JD_ONE_SIZE]; + char *maker_name; + + ReCode_cid = module_jd9366t_register_read(g_jd9366t_chip_info.dsram_fw_cfg_info_addr.fw_cid_version, rdata_cid, sizeof(rdata_cid)); + ReCode_ver = module_jd9366t_register_read(g_jd9366t_chip_info.dsram_fw_cfg_info_addr.fw_version, rdata_fw, sizeof(rdata_fw)); + ReCode_maker = module_jd9366t_register_read(g_jd9366t_chip_info.dsram_fw_cfg_info_addr.panel_maker, rdata_maker, sizeof(rdata_maker)); + ReCode_panel = module_jd9366t_register_read(g_jd9366t_chip_info.dsram_fw_cfg_info_addr.panel_version, rdata_panel, sizeof(rdata_panel)); + + if ((ReCode_cid < 0) || (ReCode_ver < 0) || (ReCode_maker < 0) || (ReCode_panel < 0)) { + JD_E("%s: Read fw version fail\n", __func__); + pjadard_ic_data->fw_ver = 0; + pjadard_ic_data->fw_cid_ver = 0; + scnprintf(pjadard_ic_data->panel_maker, sizeof(pjadard_ic_data->panel_maker), "%s", jd_panel_maker_list[JD_PANEL_MAKER_NUM]); + pjadard_ic_data->panel_ver = 0; + } else { + pjadard_ic_data->fw_ver = ((rdata_fw[0] << 16) | + (rdata_fw[1] << 8) | + (rdata_fw[2])); + pjadard_ic_data->fw_cid_ver = ((rdata_cid[0] << 24) | + (rdata_cid[1] << 16) | + (rdata_cid[2] << 8) | + (rdata_cid[3])); + maker_id = (int)rdata_maker[0]; + pjadard_ic_data->panel_ver = rdata_panel[0]; + + switch (maker_id) { + case JD_PANEL_MAKER_CP: + maker_name = "CP"; + break; + case JD_PANEL_MAKER_COB: + maker_name = "COB"; + break; + default: + if (maker_id < JD_PANEL_MAKER_NUM) { + maker_name = jd_panel_maker_list[maker_id]; + } else { + maker_name = jd_panel_maker_list[JD_PANEL_MAKER_NUM]; + } + break; + } + scnprintf(pjadard_ic_data->panel_maker, sizeof(pjadard_ic_data->panel_maker), "%s", maker_name); + } + + JD_I("FW_VER: %08x\n", pjadard_ic_data->fw_ver); + JD_I("FW_CID_VER: %08x\n", pjadard_ic_data->fw_cid_ver); + JD_I("PANEL_MAKER: %s\n", pjadard_ic_data->panel_maker); + JD_I("PANEL_VER: %02x\n", pjadard_ic_data->panel_ver); +} + +#if defined(JD_AUTO_UPGRADE_FW) +static int module_jd9366t_read_fw_ver_bin(void) +{ + if (g_jadard_fw != NULL) { + JD_I("Catch fw version in bin file\n"); + g_jadard_fw_ver = ((g_jadard_fw[JD9366T_BIN_FW_VER + 0] << 16) | + (g_jadard_fw[JD9366T_BIN_FW_VER + 1] << 8) | + (g_jadard_fw[JD9366T_BIN_FW_VER + 2])); + g_jadard_fw_cid_ver = ((g_jadard_fw[JD9366T_BIN_FW_CID_VER + 0] << 24) | + (g_jadard_fw[JD9366T_BIN_FW_CID_VER + 1] << 16) | + (g_jadard_fw[JD9366T_BIN_FW_CID_VER + 2] << 8) | + (g_jadard_fw[JD9366T_BIN_FW_CID_VER + 3])); + } else { + JD_I("FW data is null\n"); + return JD_FILE_OPEN_FAIL; + } + + return JD_NO_ERR; +} +#endif + +static void module_jd9366t_mutual_data_set(uint8_t data_type) +{ + uint8_t wdata[JD_TWO_SIZE] = {0x00, 0x00}; + uint8_t status[JD_TWO_SIZE]; + + if ((data_type >= JD_DATA_TYPE_RawData) && (data_type <= JD_DATA_TYPE_RESERVE_F)) { + wdata[0] = data_type - 1; + } else { + wdata[0] = JD_DATA_TYPE_RawData - 1; + } + + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_debug_addr.output_data_sel, wdata, sizeof(wdata)); + + if (pjadard_ts_data->debug_diag_apk_enable) { + status[0] = 0x55; + status[1] = 0xAA; + jd9366t_WriteRegMulti(g_jd9366t_chip_info.dsram_host_addr.data_output_v2, status, sizeof(status)); + } else { + status[0] = 0x00; + status[1] = 0x00; + jd9366t_WriteRegMulti(g_jd9366t_chip_info.dsram_host_addr.data_output_v2, status, sizeof(status)); + /* Clear handshark status for START */ + status[0] = 0xA5; + status[1] = 0x5A; + jd9366t_WriteRegMulti(g_jd9366t_chip_info.dsram_debug_addr.output_data_handshake, status, sizeof(status)); + } +} + +static int module_jd9366t_get_mutual_data(uint8_t data_type, uint8_t *rdata, uint16_t rlen) +{ + int ReCode; + int DataCnt = 0; + uint8_t status[JD_TWO_SIZE]; + + do { + mdelay(1); + + if (DataCnt++ > JD9366T_DATA_TIMEOUT) { + JD_I("Scan data timeout, DataCnt = %d\n", DataCnt); + jd9366t_EnterBackDoor(NULL); + return JD_TIME_OUT; + } + + jd9366t_ReadRegMulti(g_jd9366t_chip_info.dsram_debug_addr.output_data_handshake, status, sizeof(status)); + } while (((status[1] << 8) + status[0]) != JD9366T_OUTPUT_DATA_HANDSHAKE_DONE); + + /* Get data from IC */ + if ((data_type >= JD_DATA_TYPE_RawData) && (data_type <= JD_DATA_TYPE_RESERVE_F)) { + ReCode = jd9366t_ReadRegMulti(g_jd9366t_chip_info.esram_info_content_addr.output_buf, rdata, rlen); + /* Clear handshark status */ + status[0] = 0xA5; + status[1] = 0x5A; + jd9366t_WriteRegMulti(g_jd9366t_chip_info.dsram_debug_addr.output_data_handshake, status, sizeof(status)); + } else { + JD_E("%s: Not support data type = %d\n", __func__, data_type); + ReCode = -EINVAL; + } + + return ReCode; +} + +static bool module_jd9366t_get_touch_data(uint8_t *rdata, uint8_t rlen) +{ + if (jd9366t_ReadTpInfoBuf(rdata, rlen) < 0) { + return false; + } else { + return true; + } +} + +static int module_jd9366t_read_mutual_data(uint8_t *rdata, uint16_t rlen) +{ + int ReCode; + + if (g_jd9366t_chip_info.esram_info_content_addr.output_buf > g_jd9366t_chip_info.esram_info_content_addr.coordinate_report) { + ReCode = jd9366t_ReadRegMulti(g_jd9366t_chip_info.esram_info_content_addr.coordinate_report, rdata, rlen); + if (ReCode >= 0) + ReCode = JD_REPORT_DATA; + } else { + ReCode = jd9366t_ReadRegMulti(g_jd9366t_chip_info.esram_info_content_addr.output_buf, rdata, rlen); + } + + return ReCode; +} + +static void module_jd9366t_set_high_sensitivity(bool enable) +{ + uint8_t wdata[JD_TWO_SIZE] = {0x00, 0x00}; + if (enable) { + wdata[0] = 0x3A; + wdata[1] = 0xA3; + } + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.high_sensitivity_en, wdata, sizeof(wdata)); +} + +static void module_jd9366t_set_rotate_border(uint16_t rotate) +{ + uint8_t wdata[JD_TWO_SIZE] = {0x00, 0x00}; + wdata[0] = (uint8_t)((rotate & 0x00FF) >> 0); + wdata[1] = (uint8_t)((rotate & 0xFF00) >> 8); + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.border_en, wdata, sizeof(wdata)); +} + +#ifdef JD_EARPHONE_DETECT +static void module_jd9366t_set_earphone_enable(uint8_t status) +{ + uint8_t wdata[JD_TWO_SIZE] = {0x00, 0x00}; + + switch (status) { + case 1: /* earphone removed */ + pjadard_ts_data->earphone_enable &= 0xFF00; + break; + case 2: /* earphone detected */ + pjadard_ts_data->earphone_enable &= 0xFF00; + pjadard_ts_data->earphone_enable |= 0x0001; + break; + case 3: /* type-c_earphone removed */ + pjadard_ts_data->earphone_enable &= 0x00FF; + break; + case 4: /* type-c_earphone detected */ + pjadard_ts_data->earphone_enable &= 0x00FF; + pjadard_ts_data->earphone_enable |= 0x0100; + break; + default: + JD_E("%s: unknown status\n", __func__); + break; + } + + wdata[0] = (uint8_t)((pjadard_ts_data->earphone_enable & 0x00FF) >> 0); + wdata[1] = (uint8_t)((pjadard_ts_data->earphone_enable & 0xFF00) >> 8); + JD_D("%s: earphone = %d, typec_earphone = %d\n", __func__, wdata[0], wdata[1]); + + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.earphone_en, wdata, sizeof(wdata)); +} +#endif + +static void module_jd9366t_set_SMWP_enable(bool enable) +{ + uint8_t wdata[JD_TWO_SIZE] = {0x00, 0x00}; + + if (enable) { + wdata[0] = 1; + } else { + wdata[0] = 0; + } + + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.gesture_en, wdata, sizeof(wdata)); +} + +static void module_jd9366t_usb_detect_set(uint8_t *usb_status) +{ + uint8_t wdata[JD_TWO_SIZE] = {0x00, 0x00}; + + wdata[0] = usb_status[1]; + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.usb_en, wdata, sizeof(wdata)); +} + +static uint8_t module_jd9366t_get_freq_band(void) +{ + uint8_t rdata[JD_TWO_SIZE]; + + module_jd9366t_register_read(g_jd9366t_chip_info.dsram_debug_addr.freq_band, rdata, sizeof(rdata)); + return rdata[0]; +} + +static void module_jd9366t_set_virtual_proximity(bool enable) +{ + uint8_t wdata[JD_TWO_SIZE] = {0x00, 0x00}; + + if (enable) { + wdata[0] = 0x3A; + wdata[1] = 0xA3; + } + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.proximity_en, wdata, sizeof(wdata)); +} + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING +static void module_jd9366t_APP_SetSortingMode(uint8_t *value, uint8_t value_len) +{ + jd9366t_SetMpapPwSync(0); + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.mpap_pw, value, value_len); + jd9366t_SetMpapPwSync(1); +} + +static void module_jd9366t_APP_ReadSortingMode(uint8_t *pValue, uint8_t pValue_len) +{ + module_jd9366t_register_read(g_jd9366t_chip_info.dsram_host_addr.mpap_pw, pValue, pValue_len); +} + +static void module_jd9366t_APP_GetLcdSleep(uint8_t *pStatus) +{ + jd9366t_ReadRegSingle((uint32_t)JD9366T_SOC_REG_ADDR_SLPOUT, pStatus); +} + +static void module_jd9366t_APP_SetSortingSkipFrame(uint8_t value) +{ + jd9366t_WriteRegSingle(g_jd9366t_chip_info.dsram_host_addr.mpap_skip_frame, value); +} + +static void module_jd9366t_APP_SetSortingKeepFrame(uint8_t value) +{ + jd9366t_WriteRegSingle(g_jd9366t_chip_info.dsram_host_addr.mpap_keep_frame, value); +} + +static bool module_jd9366t_APP_ReadSortingBusyStatus(uint8_t mpap_handshake_finish, uint8_t *pStatus) +{ + jd9366t_ReadRegSingle(g_jd9366t_chip_info.dsram_host_addr.mpap_handshake, pStatus); + + if (*pStatus == mpap_handshake_finish) + return true; + else + return false; +} + +static void module_jd9366t_GetSortingDiffDataMax(uint8_t *pValue, uint16_t pValue_len) +{ + module_jd9366t_register_read(g_jd9366t_chip_info.dsram_host_addr.mpap_diff_max, pValue, pValue_len); +} + +static void module_jd9366t_GetSortingDiffDataMin(uint8_t *pValue, uint16_t pValue_len) +{ + module_jd9366t_register_read(g_jd9366t_chip_info.dsram_host_addr.mpap_diff_min, pValue, pValue_len); +} + +static void module_jd9366t_Fw_DBIC_Off(void) +{ + uint8_t wBuf[JD_TWO_SIZE]; + + wBuf[0] = 0x24; + wBuf[1] = 0x02; + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.fw_dbic_en, wBuf, sizeof(wBuf)); +} + +static void module_jd9366t_Fw_DBIC_On(void) +{ + uint8_t wBuf[JD_TWO_SIZE]; + + wBuf[0] = 0xFF; + wBuf[1] = 0xFF; + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.fw_dbic_en, wBuf, sizeof(wBuf)); +} + +static void module_jd9366t_StartMCU(void) +{ + jd9366t_StartMCU(); +} + +static void module_jd9366t_SetMpBypassMain(void) +{ + uint8_t wBuf[JD_TWO_SIZE]; + + wBuf[0] = 0xFF; + wBuf[1] = 0xFF; + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.mpap_bypass_main, wBuf, sizeof(wBuf)); +} + +static void module_jd9366t_ClearMpBypassMain(void) +{ + uint8_t wBuf[JD_TWO_SIZE]; + + wBuf[0] = 0x00; + wBuf[1] = 0x00; + module_jd9366t_register_write(g_jd9366t_chip_info.dsram_host_addr.mpap_bypass_main, wBuf, sizeof(wBuf)); +} + +static void module_jd9366t_ReadMpapErrorMsg(uint8_t *pValue, uint8_t pValue_len) +{ + module_jd9366t_register_read(g_jd9366t_chip_info.dsram_host_addr.mpap_error_msg, pValue, pValue_len); +} +#endif + +static void jd9366t_func_reinit(void) +{ + JD_D("%s:Entering!\n", __func__); + g_module_fp.fp_EnterBackDoor = module_jd9366t_EnterBackDoor; + g_module_fp.fp_ExitBackDoor = module_jd9366t_ExitBackDoor; + g_module_fp.fp_pin_reset = module_jd9366t_PinReset; + g_module_fp.fp_soft_reset = module_jd9366t_SoftReset; + g_module_fp.fp_ResetMCU = module_jd9366t_ResetMCU; + g_module_fp.fp_PorInit = module_jd9366t_PorInit; + g_module_fp.fp_register_read = module_jd9366t_register_read; + g_module_fp.fp_register_write = module_jd9366t_register_write; + g_module_fp.fp_flash_read = module_jd9366t_flash_read; + g_module_fp.fp_flash_write = module_jd9366t_flash_write; + g_module_fp.fp_flash_erase = module_jd9366t_flash_erase; + g_module_fp.fp_ram_read = module_jd9366t_ram_read; + g_module_fp.fp_dd_register_read = module_jd9366t_DbicReg_read; + g_module_fp.fp_dd_register_write = module_jd9366t_DbicReg_write; + g_module_fp.fp_set_sleep_mode = module_jd9366t_set_sleep_mode; +#ifdef JD_ZERO_FLASH + g_module_fp.fp_ram_write = module_jd9366t_ram_write; +#ifdef JD_ESD_CHECK + g_module_fp.fp_esd_ram_write = module_jd9366t_esd_ram_write; +#endif +#endif + g_module_fp.fp_read_fw_ver = module_jd9366t_read_fw_ver; +#ifdef JD_AUTO_UPGRADE_FW + g_module_fp.fp_read_fw_ver_bin = module_jd9366t_read_fw_ver_bin; +#endif + g_module_fp.fp_mutual_data_set = module_jd9366t_mutual_data_set; + g_module_fp.fp_get_mutual_data = module_jd9366t_get_mutual_data; + g_module_fp.fp_get_touch_data = module_jd9366t_get_touch_data; + g_module_fp.fp_read_mutual_data = module_jd9366t_read_mutual_data; + g_module_fp.fp_set_high_sensitivity = module_jd9366t_set_high_sensitivity; + g_module_fp.fp_set_rotate_border = module_jd9366t_set_rotate_border; +#ifdef JD_EARPHONE_DETECT + g_module_fp.fp_set_earphone_enable = module_jd9366t_set_earphone_enable; +#endif + g_module_fp.fp_set_SMWP_enable = module_jd9366t_set_SMWP_enable; + g_module_fp.fp_usb_detect_set = module_jd9366t_usb_detect_set; + g_module_fp.fp_get_freq_band = module_jd9366t_get_freq_band; + g_module_fp.fp_set_virtual_proximity = module_jd9366t_set_virtual_proximity; +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_APP_SetSortingMode = module_jd9366t_APP_SetSortingMode; + g_module_fp.fp_APP_ReadSortingMode = module_jd9366t_APP_ReadSortingMode; + g_module_fp.fp_APP_GetLcdSleep = module_jd9366t_APP_GetLcdSleep; + g_module_fp.fp_APP_SetSortingSkipFrame = module_jd9366t_APP_SetSortingSkipFrame; + g_module_fp.fp_APP_SetSortingKeepFrame = module_jd9366t_APP_SetSortingKeepFrame; + g_module_fp.fp_APP_ReadSortingBusyStatus = module_jd9366t_APP_ReadSortingBusyStatus; + /* + * Using new function g_module_fp.fp_GetSortingDiffDataMax & + * g_module_fp.fp_GetSortingDiffDataMin + * when g_module_fp.fp_GetSortingDiffData = NULL + */ + g_module_fp.fp_GetSortingDiffData = NULL; + g_module_fp.fp_GetSortingDiffDataMax = module_jd9366t_GetSortingDiffDataMax; + g_module_fp.fp_GetSortingDiffDataMin = module_jd9366t_GetSortingDiffDataMin; + g_module_fp.fp_Fw_DBIC_Off = module_jd9366t_Fw_DBIC_Off; + g_module_fp.fp_Fw_DBIC_On = module_jd9366t_Fw_DBIC_On; + g_module_fp.fp_StartMCU = module_jd9366t_StartMCU; + g_module_fp.fp_SetMpBypassMain = module_jd9366t_SetMpBypassMain; + g_module_fp.fp_ClearMpBypassMain = module_jd9366t_ClearMpBypassMain; + g_module_fp.fp_ReadMpapErrorMsg = module_jd9366t_ReadMpapErrorMsg; +#endif +} + +static bool module_jd9366t_chip_detect(void) +{ + int i = 0; + bool ret = false; + uint16_t romid = 0; + uint16_t CHIP_ID = JD9366T_ID; + + g_common_variable.dbi_dd_reg_mode = JD9366T_DDREG_MODE; + if (g_common_variable.dbi_dd_reg_mode != JD_DDREG_MODE_0) { + JD_E("%s:Don't support this mode ,dbi_dd_reg_mode %02X not equal %02X\n", + __func__, g_common_variable.dbi_dd_reg_mode, JD_DDREG_MODE_0); + return false; + } + + do { + /* EnterBackDoor get IC ID */ + jd9366t_EnterBackDoor(&romid); + + if (romid == CHIP_ID) { + JD_I("%s: detect IC %s successfully\n", __func__, JD9366T_OUTER_ID); + scnprintf(pjadard_ic_data->chip_id, sizeof(pjadard_ic_data->chip_id), JD9366T_OUTER_ID); + jd9366t_func_reinit(); + ret = true; + } else { + JD_E("%s:Read driver ID %04X not equal %04X\n", __func__, romid, CHIP_ID); + msleep(500); + } + } while ((++i < 3) && (ret == false)); + + return ret; +} + +#ifdef CONFIG_CHIP_DTCFG +static int jadard_jd9366t_probe(struct platform_device *pdev) +{ + struct jadard_support_chip *pChip = NULL; + struct jadard_support_chip *ptr = NULL; + + JD_I("%s:Enter\n", __func__); + + pChip = kzalloc(sizeof(struct jadard_support_chip), GFP_KERNEL); + if (pChip == NULL) { + JD_E("%s: allocate jadard_ts_data failed\n", __func__); + return -ENOMEM; + } + + /* Store chip init and detect funtion */ + pChip->chip_init = module_jd9366t_chip_init; + pChip->chip_detect = module_jd9366t_chip_detect; + pChip->next = NULL; + + if (g_module_fp.head_support_chip == NULL) { + g_module_fp.head_support_chip = pChip; + } else { + ptr = g_module_fp.head_support_chip; + /* Find the last one */ + while (ptr->next != NULL) { + ptr = ptr->next; + } + /* Link to the last */ + ptr->next = pChip; + } + + return 0; +} + +static int jadard_jd9366t_remove(struct platform_device *pdev) +{ + struct jadard_support_chip *ptr = g_module_fp.head_support_chip; + struct jadard_support_chip *pre_ptr = NULL; + + while (ptr != NULL) { + if ((ptr->chip_init == module_jd9366t_chip_init) && + (ptr->chip_detect == module_jd9366t_chip_detect)) { + if (ptr == g_module_fp.head_support_chip) { + g_module_fp.head_support_chip = ptr->next; + } else { + pre_ptr->next = ptr->next; + } + kfree(ptr); + break; + } + + pre_ptr = ptr; + ptr = ptr->next; + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id jadard_jd9366t_mttable[] = { + { .compatible = "jadard,jd9366t"}, + { }, +}; +#else +#define jadard_jd9366t_mttable NULL +#endif + +static struct platform_driver jadard_jd9366t_driver = { + .probe = jadard_jd9366t_probe, + .remove = jadard_jd9366t_remove, + .driver = { + .name = "JADARD_JD9366T", + .owner = THIS_MODULE, + .of_match_table = jadard_jd9366t_mttable, + }, +}; + +static int __init jadard_jd9366t_init(void) +{ + JD_I("%s\n", __func__); + platform_driver_register(&jadard_jd9366t_driver); + + return 0; +} + +static void __exit jadard_jd9366t_exit(void) +{ + platform_driver_unregister(&jadard_jd9366t_driver); +} + +#else +static int jadard_jd9366t_probe(void) +{ + struct jadard_support_chip *pChip = NULL; + struct jadard_support_chip *ptr = NULL; + + JD_I("%s:Enter\n", __func__); + + pChip = kzalloc(sizeof(struct jadard_support_chip), GFP_KERNEL); + if (pChip == NULL) { + JD_E("%s: allocate jadard_ts_data failed\n", __func__); + return -ENOMEM; + } + + /* Store chip init and detect funtion */ + pChip->chip_init = module_jd9366t_chip_init; + pChip->chip_detect = module_jd9366t_chip_detect; + pChip->next = NULL; + + if (g_module_fp.head_support_chip == NULL) { + g_module_fp.head_support_chip = pChip; + } else { + ptr = g_module_fp.head_support_chip; + /* Find the last one */ + while (ptr->next != NULL) { + ptr = ptr->next; + } + /* Link to the last */ + ptr->next = pChip; + } + + return 0; +} + +static int jadard_jd9366t_remove(void) +{ + struct jadard_support_chip *ptr = g_module_fp.head_support_chip; + struct jadard_support_chip *pre_ptr = NULL; + + while (ptr != NULL) { + if ((ptr->chip_init == module_jd9366t_chip_init) && + (ptr->chip_detect == module_jd9366t_chip_detect)) { + if (ptr == g_module_fp.head_support_chip) { + g_module_fp.head_support_chip = ptr->next; + } else { + pre_ptr->next = ptr->next; + } + kfree(ptr); + break; + } + + pre_ptr = ptr; + ptr = ptr->next; + } + + return 0; +} + +static int __init jadard_jd9366t_init(void) +{ + JD_I("%s\n", __func__); + jadard_jd9366t_probe(); +#if defined(__JADARD_KMODULE__) + jadard_common_init(); +#endif + + return 0; +} + +static void __exit jadard_jd9366t_exit(void) +{ + jadard_jd9366t_remove(); +#if defined(__JADARD_KMODULE__) + jadard_common_exit(); +#endif +} +#endif + +module_init(jadard_jd9366t_init); +module_exit(jadard_jd9366t_exit); + +MODULE_DESCRIPTION("JADARD JD9366T touch driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/jdchipset/jadard_ic_JD9366T.h b/drivers/input/touchscreen/jdchipset/jadard_ic_JD9366T.h new file mode 100644 index 0000000000000..ce06b87c8010a --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_ic_JD9366T.h @@ -0,0 +1,350 @@ +#ifndef JADARD_JD9366T_H +#define JADARD_JD9366T_H + +static int jd9366t_EnterBackDoor(uint16_t *pRomID); +static int jd9366t_ExitBackDoor(void); + +#define JD9366T_ID (0x9032) +#define JD9366T_OUTER_ID "JD9366T" +#define JD9366T_MEMORY_ADDR_PRAM (0x00000000) +#define JD9366T_MEMORY_ADDR_DRAM (0x20000000) +#define JD9366T_MEMORY_ADDR_ARAM (0x20020000) +#define JD9366T_MEMORY_ADDR_ERAM (0x20021000) +#define JD9366T_MAX_DSRAM_NUM (25) +#define JD9366T_MAX_ESRAM_NUM (10) +#define JD9366T_SECTION_INFO_READY_VALUE (0xA55A) +#define JD9366T_OUTPUT_DATA_HANDSHAKE_DONE (0xA55A) +#define JD9366T_SIZE (80 * 1024) +#define JD9366T_PRAM_MAX_SIZE (0x10000) +/* Set BIN_FW_CID_VER & BIN_FW_VER address */ +#define JD9366T_BIN_FW_HEADER_SIZE (0x200) +/* Please reference .flash_2_fw_cfg_info of FW */ +#define JD9366T_BIN_FW_CFG_INFO_ADDR (JD9366T_BIN_FW_HEADER_SIZE + 0x10000) +#define JD9366T_BIN_FW_CID_VER (JD9366T_BIN_FW_CFG_INFO_ADDR + 0) +#define JD9366T_BIN_FW_VER (JD9366T_BIN_FW_CFG_INFO_ADDR + 7) +#define JD9366T_DATA_TIMEOUT (5000) +#define JD9366T_DD_PASSWORD_CODE1 (0x49) +#define JD9366T_DD_PASSWORD_CODE2 (0x61) +#define JD9366T_DD_PASSWORD_CODE3 (0x02) +#define JD9366T_DD_PASSWORD_CODE4 (0x00) +#define JD9366T_DDREG_MODE (JD_DDREG_MODE_0) + +struct JD9366T_MOVE_INFO { + uint8_t mov_mem_cmd; + uint32_t fl_st_addr; + uint32_t fl_len; + uint32_t to_mem_st_addr; + uint16_t to_mem_crc; +}; + +struct JD9366T_INFO_CONTENT { + uint32_t info_content_addr; + uint32_t info_content_len; +}; + +struct JD9366T_DSRAM_FW_CFG_INFO_ADDR { + uint32_t fw_cid_version; + uint32_t panel_maker; + uint32_t panel_version; + uint32_t fw_version; +}; + +struct JD9366T_DSRAM_HOST_ADDR { + uint32_t fw_cid_version; + uint32_t fw_version; + uint32_t game_mode_en; + uint32_t usb_en; + uint32_t gesture_en; + uint32_t high_sensitivity_en; + uint32_t border_en; + uint32_t proximity_en; + uint32_t panel_maker; + uint32_t panel_version; + uint32_t earphone_en; +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + uint32_t mpap_pw; + uint32_t mpap_handshake; + uint32_t mpap_keep_frame; + uint32_t mpap_skip_frame; + uint32_t mpap_mux_switch; + uint32_t fw_dbic_en; + uint32_t mpap_diff_max; + uint32_t mpap_diff_min; + uint32_t mpap_pw_sync; + uint32_t mpap_bypass_main; + uint32_t mpap_error_msg; +#else + uint32_t mpap_pw; + uint32_t mpap_pw_sync; +#endif + uint32_t data_output_v2; +}; + +struct JD9366T_DSRAM_DEBUG_ADDR { + uint32_t output_data_addr; + uint32_t output_data_sel; + uint32_t output_data_handshake; + uint32_t freq_band; +}; + +struct JD9366T_ESRAM_INFO_CONTENT_ADDR { + uint32_t coordinate_report; + uint32_t output_buf; +}; + +struct JD9366T_CHIP_INFO { + bool back_door_mode; + struct JD9366T_DSRAM_FW_CFG_INFO_ADDR dsram_fw_cfg_info_addr; + struct JD9366T_DSRAM_HOST_ADDR dsram_host_addr; + struct JD9366T_DSRAM_DEBUG_ADDR dsram_debug_addr; + struct JD9366T_ESRAM_INFO_CONTENT_ADDR esram_info_content_addr; +} g_jd9366t_chip_info; + +struct JD9366T_SECTION_INFO { + bool section_info_ready; + uint32_t section_info_ready_addr; + /* Dsram section */ + uint32_t dsram_num_start_addr; + uint32_t dsram_section_info_start_addr; + /* Esram section */ + uint32_t esram_num_start_addr; + uint32_t esram_section_info_start_addr; +} g_jd9366t_section_info; + +enum JD9366T_DSRAM_SECTION_INFO_ORDER { + JD9366T_DSRAM_FW_CFG_INFO = 0, + JD9366T_DSRAM_FW_CFG, + JD9366T_DSRAM_FW_CFG_SORTING, + JD9366T_DSRAM_HOST, + JD9366T_DSRAM_DEBUG, + JD9366T_DSRAM_ADC_MAPPING_TABLE, + JD9366T_DSRAM_AFE_CONFIG, + JD9366T_DSRAM_FW_PAYLOAD, + JD9366T_DSRAM_INTERNAL_INFO, + JD9366T_DSRAM_CB_1CYC, + JD9366T_DSRAM_CB_F0, + JD9366T_DSRAM_CB_F1, + JD9366T_DSRAM_CB_F2, + JD9366T_DSRAM_CB_LPWUG_1CYC, + JD9366T_DSRAM_CB_LPWUG_F0, + JD9366T_DSRAM_MPAP_DIFF_MAX, + JD9366T_DSRAM_MPAP_DIFF_MIN, + JD9366T_DSRAM_DD_INITIAL_CODE, + JD9366T_DSRAM_TEMPERATURE_CONFIG, +}; + +enum JD9366T_ESRAM_SECTION_INFO_ORDER { + JD9366T_ESRAM_ALL_SECTION_INFO = 0, + JD9366T_ESRAM_COORDINATE_REPORT, + JD9366T_ESRAM_OUTPUT_BUF, + JD9366T_ESRAM_DEBUG_BUF, + JD9366T_ESRAM_FLASH_DATA_BUF, + JD9366T_ESRAM_DDREG_DATA_BUF, +}; + +enum JD9366T_HEADER_INFO { + JD9366T_HW_HEADER_MAX_SIZE = JD9366T_BIN_FW_HEADER_SIZE, + JD9366T_HW_HEADER_CRC_NUMBER = 2, + JD9366T_HW_HEADER_INITIAL_NUMBER = 3, + JD9366T_HW_HEADER_MOVE_INFO_NUMBER = 12, + JD9366T_HW_HEADER_PSRAM_START_ADDR = JD9366T_MEMORY_ADDR_PRAM, +}; + +enum JD9366T_HEADER_POSITION { + JD9366T_HW_HEADER_CRC_H = 0, + JD9366T_HW_HEADER_CRC_L, + JD9366T_CRC_FAIL_RETRY_TIMES, + JD9366T_HW_HEADER_LEN, + JD9366T_LOAD_CODE_SPI_FREQ, +}; + +enum JD9366T_CRC_INFO { + JD9366T_CRC_INFO_PolynomialCRC16 = 0x8005, + JD9366T_CRC_INFO_CRC_INITIAL_VALUE = 0xFFFF, +}; + +enum JD9366T_SIZE_DEF { + JD9366T_SIZE_DEF_PAGE_SIZE = 0x100, + JD9366T_SIZE_DEF_SECTOR_SIZE = 0x1000, + JD9366T_SIZE_DEF_BLOCK_32K = 0x8000, + JD9366T_SIZE_DEF_BLOCK_64K = 0x10000, +}; + +enum JD9366T_FLASH_RUN_TIME { + /* unit: ms */ + JD9366T_FLASH_RUN_TIME_PAGE_WRITE_WAIT_TIME = 3, + JD9366T_FLASH_RUN_TIME_PAGE_WRITE_TIME = 50, + JD9366T_FLASH_RUN_TIME_ERASE_SECTOR_TIME = 75, + JD9366T_FLASH_RUN_TIME_ERASE_BLOCK_32K_TIME = 200, + JD9366T_FLASH_RUN_TIME_ERASE_BLOCK_64K_TIME = 350, + JD9366T_FLASH_RUN_TIME_ERASE_CHIP_TIME = 2300, +}; + +enum JD9366T_FLASH_PACK { + JD9366T_FLASH_PACK_READ_SIZE = 2048, + JD9366T_FLASH_PACK_WRITE_SIZE = 2048, +}; + +enum JD9366T_TIMER_REG_ADDR { + JD9366T_TIMER_BASE_ADDR = 0x400000, + JD9366T_TIMER_REG_ADDR_WDT_CONFIG = (JD9366T_TIMER_BASE_ADDR << 8) + 0x32, + JD9366T_TIMER_REG_ADDR_RTC_CONFIG = (JD9366T_TIMER_BASE_ADDR << 8) + 0x42, +}; + +enum JD9366T_TIMER_RELATED_SETTING { + /* 0x32[0] */ + JD9366T_TIMER_RELATED_SETTING_WDT_STOP = 0x02, + + /* 0x42[0] */ + JD9366T_TIMER_RELATED_SETTING_DISABLE_RTC_RUN = 0x00, + JD9366T_TIMER_RELATED_SETTING_ENABLE_RTC_RUN = 0x01, +}; + +enum JD9366T_EX_FLASH_ADDR { + JD9366T_EX_FLASH_ADDR_READ = 0x03, + JD9366T_EX_FLASH_ADDR_STATUS_REGISTER1 = 0x05, + JD9366T_EX_FLASH_ADDR_WRITE_ENABLE = 0x06, + JD9366T_EX_FLASH_ADDR_WRITE_DISABLE = 0x04, + JD9366T_EX_FLASH_ADDR_ERASE_SECTOR = 0x20, + JD9366T_EX_FLASH_ADDR_STATUS_REGISTER2 = 0x35, + JD9366T_EX_FLASH_ADDR_ERASE_BLOCK_32K = 0x52, + JD9366T_EX_FLASH_ADDR_ERASE_BLOCK_64K = 0xD8, + JD9366T_EX_FLASH_ADDR_ERASE_CHIP = 0xC7, + JD9366T_EX_FLASH_ADDR_READ_ID = 0x9F, +}; + +enum JD9366T_DMA_RELATED_SETTING { + /* 0x0C[4:0] */ + JD9366T_DMA_RELATED_SETTING_READ_FROM_FLASH = 0x01, + JD9366T_DMA_RELATED_SETTING_WRITE_TO_PRAM = 0x03, + JD9366T_DMA_RELATED_SETTING_WRITE_TO_FLASH = 0x07, + JD9366T_DMA_RELATED_SETTING_READ_FLASH_STATUS = 0x08, + JD9366T_DMA_RELATED_SETTING_PAGE_PROGRAM_FLASH = 0x10, + /* 0x0C[4] */ + JD9366T_DMA_RELATED_SETTING_PAGE_PROGRAM_DONE = 0x00, + /* 0x0E[1:0] */ + JD9366T_DMA_RELATED_SETTING_TRANSFER_DATA_1_BYTE_MODE = 0x00, + JD9366T_DMA_RELATED_SETTING_TRANSFER_DATA_2_BYTE_MODE = 0x01, + JD9366T_DMA_RELATED_SETTING_TRANSFER_DATA_4_BYTE_MODE = 0x02, + /* 0x1D[0] */ + JD9366T_DMA_RELATED_SETTING_DMA_DONE = 0x00, + JD9366T_DMA_RELATED_SETTING_DMA_BUSY = 0x01, +}; + +enum JD9366T_MASTER_SPI_RELATED_SETTING { + /* 0x11[2:0] */ + JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_24MHz = 0x00, + JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_12MHz = 0x01, + JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_6MHz = 0x02, + JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_3MHz = 0x03, + JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_1500KHz = 0x04, + JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_750KHz = 0x05, + JD9366T_MASTER_SPI_RELATED_SETTING_SPEED_375KHz = 0x06, + /* 0x12[0] */ + JD9366T_MASTER_SPI_RELATED_SETTING_CSN_H = 0x00, + JD9366T_MASTER_SPI_RELATED_SETTING_CSN_L = 0x01, + /* 0x15[7] */ + JD9366T_MASTER_SPI_RELATED_SETTING_SPIF_BUSY = 0x00, + JD9366T_MASTER_SPI_RELATED_SETTING_SPIF_DONE = 0x80, + /* 0x1D[4] */ + JD9366T_MASTER_SPI_RELATED_SETTING_FLASH_DONE = 0x00, + JD9366T_MASTER_SPI_RELATED_SETTING_FLASH_BUSY = 0x10, +}; + +enum JD9366T_CRC_CODE_POSITION { + JD9366T_CRC_CODE_POSITION_LOW_BYTE = 0, + JD9366T_CRC_CODE_POSITION_HIGH_BYTE, +}; + +enum JD9366T_FLASH_REG_ADDR { + JD9366T_FLASH_BASE_ADDR = 0x400002, + JD9366T_FLASH_REG_ADDR_DMA_FLASH_ADDR0 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x00, + JD9366T_FLASH_REG_ADDR_DMA_FLASH_ADDR1 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x01, + JD9366T_FLASH_REG_ADDR_DMA_FLASH_ADDR2 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x02, + JD9366T_FLASH_REG_ADDR_DMA_FLASH_ADDR3 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x03, + JD9366T_FLASH_REG_ADDR_DMA_SIZE0 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x04, + JD9366T_FLASH_REG_ADDR_DMA_SIZE1 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x05, + JD9366T_FLASH_REG_ADDR_DMA_SIZE2 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x06, + JD9366T_FLASH_REG_ADDR_DMA_SIZE3 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x07, + JD9366T_FLASH_REG_ADDR_DMA_TARGET_ADDR0 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x08, + JD9366T_FLASH_REG_ADDR_DMA_TARGET_ADDR1 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x09, + JD9366T_FLASH_REG_ADDR_DMA_TARGET_ADDR2 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x0A, + JD9366T_FLASH_REG_ADDR_DMA_TARGET_ADDR3 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x0B, + JD9366T_FLASH_REG_ADDR_DMA_2WFLASHEN_1WRITE_0START = (JD9366T_FLASH_BASE_ADDR << 8) + 0x0C, + JD9366T_FLASH_REG_ADDR_DMA_BYTE_MODE = (JD9366T_FLASH_BASE_ADDR << 8) + 0x0E, + JD9366T_FLASH_REG_ADDR_SPI_BAUD_RATE = (JD9366T_FLASH_BASE_ADDR << 8) + 0x11, + JD9366T_FLASH_REG_ADDR_SPI_CSN_OUT = (JD9366T_FLASH_BASE_ADDR << 8) + 0x12, + JD9366T_FLASH_REG_ADDR_SPI_2CPHA_1CPOL_0SPEN = (JD9366T_FLASH_BASE_ADDR << 8) + 0x13, + JD9366T_FLASH_REG_ADDR_SPI_WDATA = (JD9366T_FLASH_BASE_ADDR << 8) + 0x14, + JD9366T_FLASH_REG_ADDR_SPI_STATUS = (JD9366T_FLASH_BASE_ADDR << 8) + 0x15, + JD9366T_FLASH_REG_ADDR_SPI_RDATA = (JD9366T_FLASH_BASE_ADDR << 8) + 0x16, + JD9366T_FLASH_REG_ADDR_CRC_INIT = (JD9366T_FLASH_BASE_ADDR << 8) + 0x17, + JD9366T_FLASH_REG_ADDR_CRC_INIT_CODE1 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x18, + JD9366T_FLASH_REG_ADDR_CRC_INIT_CODE0 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x19, + JD9366T_FLASH_REG_ADDR_CRC_CHK1 = (JD9366T_FLASH_BASE_ADDR << 8) + 0x1A, + JD9366T_FLASH_REG_ADDR_CRC_CHK0 = (JD9366T_FLASH_BASE_ADDR << 8) + 0X1B, + JD9366T_FLASH_REG_ADDR_CRC_ENABLE = (JD9366T_FLASH_BASE_ADDR << 8) + 0x1C, + JD9366T_FLASH_REG_ADDR_DMA_BUSY_OR_START = (JD9366T_FLASH_BASE_ADDR << 8) + 0x1D, +}; + +enum JD9366T_SOC_REG_ADDR { + JD9366T_SOC_BASE_ADDR = 0x400080, + JD9366T_SOC_REG_ADDR_RGU_0 = (JD9366T_SOC_BASE_ADDR << 8) + 0x04, + JD9366T_SOC_REG_ADDR_CPU_SOFT_RESET = (JD9366T_SOC_BASE_ADDR << 8) + 0x12, + JD9366T_SOC_REG_ADDR_CPU_STATUS = (JD9366T_SOC_BASE_ADDR << 8) + 0x13, + JD9366T_SOC_REG_ADDR_PRAM_PROG = (JD9366T_SOC_BASE_ADDR << 8) + 0x14, + JD9366T_SOC_REG_ADDR_CPU_CLK_STOP = (JD9366T_SOC_BASE_ADDR << 8) + 0x16, + JD9366T_SOC_REG_ADDR_SLPOUT = (JD9366T_SOC_BASE_ADDR << 8) + 0x45, + JD9366T_SOC_REG_ADDR_SLPOUT_INT_EN = (JD9366T_SOC_BASE_ADDR << 8) + 0x44, + JD9366T_SOC_REG_ADDR_CHIP_ID0 = (JD9366T_SOC_BASE_ADDR << 8) + 0x74, + JD9366T_SOC_REG_ADDR_CHIP_ID1 = (JD9366T_SOC_BASE_ADDR << 8) + 0x75, + JD9366T_SOC_REG_ADDR_CHIP_ID2 = (JD9366T_SOC_BASE_ADDR << 8) + 0x76, + JD9366T_SOC_REG_ADDR_CHIP_ID3 = (JD9366T_SOC_BASE_ADDR << 8) + 0x77, + JD9366T_SOC_REG_ADDR_POR_INIT = (JD9366T_SOC_BASE_ADDR << 8) + 0x81, +}; + +enum JD9366T_SOC_PASSWORD { + JD9366T_SOC_PASSWORD_SOC_RESET = 0xA5, + JD9366T_SOC_PASSWORD_MCU_RESET = 0xA5, + JD9366T_SOC_PASSWORD_STOP_MCU = 0x00, + JD9366T_SOC_PASSWORD_START_MCU = 0xF1, + JD9366T_SOC_PASSWORD_STOP_MCU_CLOCK = 0x5A, + JD9366T_SOC_PASSWORD_START_MCU_CLOCK = 0xA5, + JD9366T_SOC_PASSWORD_POR_CLEAR = 0x00, +}; + +enum JD9366T_STC1_REG_ADDR { + JD9366T_STC1_BASE_ADDR = 0x400081, + JD9366T_STC1_REG_ADDR_XSI_IF_EN = (JD9366T_STC1_BASE_ADDR << 8) + 0x00, + JD9366T_STC1_REG_ADDR_XSI_ADDR = (JD9366T_STC1_BASE_ADDR << 8) + 0x01, + JD9366T_STC1_REG_ADDR_XSI_WDATA = (JD9366T_STC1_BASE_ADDR << 8) + 0x02, + JD9366T_STC1_REG_ADDR_XSI_CMD = (JD9366T_STC1_BASE_ADDR << 8) + 0x03, + JD9366T_STC1_REG_ADDR_XSI_RDATA_L = (JD9366T_STC1_BASE_ADDR << 8) + 0x04, + JD9366T_STC1_REG_ADDR_XSI_RDATA_R = (JD9366T_STC1_BASE_ADDR << 8) + 0x05, + JD9366T_STC1_REG_ADDR_XSI_INT_CLR = (JD9366T_STC1_BASE_ADDR << 8) + 0x08, + JD9366T_STC1_REG_ADDR_XSI_INT_FLAG = (JD9366T_STC1_BASE_ADDR << 8) + 0x09, + JD9366T_STC1_REG_ADDR_AFE_SCAN_CTRL = (JD9366T_STC1_BASE_ADDR << 8) + 0x0D, + JD9366T_STC1_REG_ADDR_SCAN_STATUS = (JD9366T_STC1_BASE_ADDR << 8) + 0x52, +}; + +enum JD9366T_STC1_RELATED_SETTING { + /* 0x00[0] */ + JD9366T_STC1_RELATED_SETTING_STC_CLOCK_DISABLE = 0x00, + JD9366T_STC1_RELATED_SETTING_STC_CLOCK_ENABLE = 0x01, + /* 0x0D[0] */ + JD9366T_STC1_RELATED_SETTING_STC_SCAN_DISABLE = 0x00, + JD9366T_STC1_RELATED_SETTING_STC_SCAN_ENABLE = 0x01, + /* 0xCF[0] */ + JD9366T_STC1_RELATED_SETTING_SCAN_DONE = 0x00, + JD9366T_STC1_RELATED_SETTING_SCAN_BUSY = 0x01, +}; + +enum JD9366T_SLEEP_MODE_PASSWORD { + JD9366T_MPAP_PW_SLEEP_IN_hbyte = 0x01, + JD9366T_MPAP_PW_SLEEP_IN_lbyte = 0xFE, + + JD9366T_MPAP_PW_SLEEP_OUT_hbyte = 0x01, + JD9366T_MPAP_PW_SLEEP_OUT_lbyte = 0xFF, +}; + +#endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_module.c b/drivers/input/touchscreen/jdchipset/jadard_module.c new file mode 100644 index 0000000000000..967b116b6e054 --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_module.c @@ -0,0 +1,626 @@ +#include "jadard_common.h" +#include "jadard_platform.h" +#include "jadard_module.h" + +extern struct jadard_module_fp g_module_fp; +extern struct jadard_ts_data *pjadard_ts_data; +extern struct jadard_ic_data *pjadard_ic_data; +struct jadard_common_variable g_common_variable; + +#if defined(JD_AUTO_UPGRADE_FW) || defined(JD_ZERO_FLASH) +#ifdef JD_UPGRADE_FW_ARRAY +extern uint8_t jd_i_firmware[]; +extern uint32_t jd_fw_size; +#endif +extern char *jd_i_CTPM_firmware_name; +#if defined(JD_ZERO_FLASH) +bool jd_g_f_0f_update = false; +#endif +#endif + +const char *jadard_bit_map[16] = { + [0] = "0000", [1] = "0001", [2] = "0010", [3] = "0011", + [4] = "0100", [5] = "0101", [6] = "0110", [7] = "0111", + [8] = "1000", [9] = "1001", [10] = "1010", [11] = "1011", + [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111", +}; + +static int jadard_mcu_register_read(uint32_t ReadAddr, uint8_t *ReadData, uint32_t ReadLen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} + +static int jadard_mcu_register_write(uint32_t WriteAddr, uint8_t *WriteData, uint32_t WriteLen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} + +static uint8_t jadard_mcu_dd_register_write(uint8_t page, uint8_t cmd, uint8_t *par, uint8_t par_len) +{ + uint8_t page_en; + + if (g_common_variable.dbi_dd_reg_mode == JD_DDREG_MODE_1) { + return jadard_DbiWriteDDReg(page, cmd, par, par_len); + } else { + page_en = g_module_fp.fp_ReadDbicPageEn(); + if (page_en != 0xFF) { + if ((cmd == 0xDE) && (page_en > 0)) { + g_module_fp.fp_SetDbicPage(par[0]); + return JD_DBIC_READ_WRITE_SUCCESS; + } else { + return jadard_DbicWriteDDReg(cmd, par, par_len); + } + } else { + return jadard_DbicWriteDDReg(cmd, par, par_len); + } + } +} + +static uint8_t jadard_mcu_dd_register_read(uint8_t page, uint8_t cmd, uint8_t *par, uint8_t par_len, uint32_t offset) +{ + if (g_common_variable.dbi_dd_reg_mode == JD_DDREG_MODE_1) { + return jadard_DbiReadDDReg(page, cmd, par, par_len, offset); + } else { + return jadard_DbicReadDDReg(cmd, par, par_len); + } +} + +static void jadard_mcu_set_sleep_mode(uint8_t *value, uint8_t value_len) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_read_fw_ver(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_mutual_data_set(uint8_t data_type) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static int jadard_mcu_get_mutual_data(uint8_t data_type, uint8_t *rdata, uint16_t rlen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} + +static bool jadard_mcu_get_touch_data(uint8_t *buf, uint8_t length) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return false; +} + +static int jadard_mcu_read_mutual_data(uint8_t *rdata, uint16_t rlen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return false; +} + +static void jadard_mcu_report_points(struct jadard_ts_data *ts) +{ + jadard_report_points(ts); +} + +static int jadard_mcu_parse_report_data(struct jadard_ts_data *ts, int irq_event, int ts_status) +{ + return jadard_parse_report_data(ts, irq_event, ts_status); +} + +static int jadard_mcu_distribute_touch_data(struct jadard_ts_data *ts, uint8_t *buf, int irq_event, int ts_status) +{ + return jadard_distribute_touch_data(ts, buf, irq_event, ts_status); +} + +static int jadard_mcu_flash_read(uint32_t start_addr, uint8_t *rdata, uint32_t rlen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} + +static int jadard_mcu_flash_write(uint32_t start_addr, uint8_t *wdata, uint32_t wlen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} + +static int jadard_mcu_flash_erase(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} + +static void jadard_mcu_EnterBackDoor(void) +{ + JD_I("%s: not support enter backdoor cmd\n", __func__); +} + +static void jadard_mcu_ExitBackDoor(void) +{ + JD_I("%s: not support exit backdoor cmd\n", __func__); +} + +static void jadard_mcu_PinReset(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_SoftReset(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_ResetMCU(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_PorInit(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +#ifdef JD_RST_PIN_FUNC +/* + * Parameter signification: + * reloadcfg int_off_on + * true true : Reload config & HW reset & INT off->on + * true false: Reload config & HW reset + * false true : HW reset & INT off->on + * false false: HW reset +*/ +static void jadard_mcu_ic_reset(bool reload_cfg, bool int_off_on) +{ + JD_I("%s: reload_cfg = %d, int_off_on = %d\n", __func__, reload_cfg, int_off_on); + pjadard_ts_data->rst_active = true; + + if (pjadard_ts_data->rst_gpio >= 0) { + if (int_off_on) { + jadard_int_enable(false); + } + + g_module_fp.fp_pin_reset(); + + if (reload_cfg) { + g_module_fp.fp_report_data_reinit(); + } + + if (int_off_on) { + jadard_int_enable(true); + } + } +} +#endif + +static void jadard_mcu_ic_soft_reset(void) +{ + pjadard_ts_data->rst_active = true; + jadard_int_enable(false); + g_module_fp.fp_soft_reset(); + jadard_int_enable(true); +} + +static void jadard_mcu_touch_info_set(void) +{ + pjadard_ic_data->JD_STYLUS_ID_EN = 0; + pjadard_ic_data->JD_STYLUS_RATIO = 1; + + /* Data set by jadard_parse_dt() */ + JD_I("%s: JD_X_NUM = %d, JD_Y_NUM = %d, JD_MAX_PT = %d\n", __func__, + pjadard_ic_data->JD_X_NUM, pjadard_ic_data->JD_Y_NUM, pjadard_ic_data->JD_MAX_PT); + JD_I("%s: JD_X_RES = %d, JD_Y_RES = %d\n", __func__, pjadard_ic_data->JD_X_RES, pjadard_ic_data->JD_Y_RES); + JD_I("%s: JD_INT_EDGE = %d\n", __func__, pjadard_ic_data->JD_INT_EDGE); + JD_I("%s: JD_STYLUS_EN = %d, JD_STYLUS_ID_EN = %d, JD_STYLUS_RATIO = %d\n", __func__, + pjadard_ic_data->JD_STYLUS_EN, pjadard_ic_data->JD_STYLUS_ID_EN, pjadard_ic_data->JD_STYLUS_RATIO); +} + +static void jadard_mcu_report_data_reinit(void) +{ + if (jadard_report_data_init()) { + JD_E("%s: allocate data fail\n", __func__); + } +} + +static void jadard_mcu_usb_detect_set(uint8_t *usb_status) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static uint8_t jadard_mcu_get_freq_band(void) +{ + JD_I("%s: not support get freq band cmd\n", __func__); + return 0xFF; +} + +static uint8_t jadard_mcu_ReadDbicPageEn(void) +{ + JD_I("%s: not support read dbic page\n", __func__); + return 0xFF; +} + +static int jadard_mcu_SetDbicPage(uint8_t page) +{ + JD_I("%s: not support set dbic page\n", __func__); + return JD_NO_ERR; +} + +static void jadard_mcu_log_touch_state(void) +{ + jadard_log_touch_state(jadard_bit_map); +} + +#if defined(JD_SMART_WAKEUP) || defined(JD_USB_DETECT_GLOBAL) || defined(JD_USB_DETECT_CALLBACK) ||\ + defined(JD_HIGH_SENSITIVITY) || defined(JD_ROTATE_BORDER) || defined(JD_EARPHONE_DETECT) +static void jadard_mcu_resume_set_func(bool suspended) +{ +#ifdef JD_SMART_WAKEUP + g_module_fp.fp_set_SMWP_enable(pjadard_ts_data->SMWP_enable); +#endif +#ifdef JD_USB_DETECT_GLOBAL + jadard_cable_detect(true); +#endif +#ifdef JD_USB_DETECT_CALLBACK + jadard_usb_status(pjadard_ts_data->usb_connected, true); +#endif +#ifdef JD_HIGH_SENSITIVITY + g_module_fp.fp_set_high_sensitivity(pjadard_ts_data->high_sensitivity_enable); +#endif +#ifdef JD_ROTATE_BORDER + g_module_fp.fp_set_rotate_border(pjadard_ts_data->rotate_border); +#endif +#ifdef JD_EARPHONE_DETECT + g_module_fp.fp_set_earphone_enable(pjadard_ts_data->earphone_enable); +#endif +} +#endif + +static void jadard_mcu_set_high_sensitivity(bool enable) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_set_rotate_border(uint16_t rotate) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +#ifdef JD_EARPHONE_DETECT +static void jadard_mcu_set_earphone_enable(uint8_t status) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} +#endif + +static void jadard_mcu_set_SMWP_enable(bool enable) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_set_virtual_proximity(bool enable) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +#if defined(JD_AUTO_UPGRADE_FW) +static int jadard_mcu_read_fw_ver_bin(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} +#endif + +static int jadard_mcu_ram_read(uint32_t start_addr, uint8_t *rdata, uint32_t rlen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} + +#ifdef JD_ZERO_FLASH +static int jadard_mcu_ram_write(uint32_t start_addr, uint8_t *wdata, uint32_t wlen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} + +static int jadard_mcu_0f_upgrade_fw(char *file_name) +{ + int err = JD_NO_ERR; +#ifdef JD_UPGRADE_FW_ARRAY + const uint8_t *fw_data = jd_i_firmware; + JD_I("file name = %s\n", jd_i_CTPM_firmware_name); +#else + int RetryCnt; + const struct firmware *fw = NULL; + + JD_I("file name = %s\n", file_name); + + for (RetryCnt = 0; RetryCnt < JD_UPGRADE_FW_RETRY_TIME; RetryCnt++) { + err = request_firmware(&fw, file_name, pjadard_ts_data->dev); + if (err < 0) { + JD_E("%s: Open file fail(ret:%d), RetryCnt = %d\n", __func__, err, RetryCnt); + mdelay(1000); + } else { + break; + } + } + + if (RetryCnt == JD_UPGRADE_FW_RETRY_TIME) { + JD_E("%s: Open file fail retry over %d\n", __func__, JD_UPGRADE_FW_RETRY_TIME); + return JD_FILE_OPEN_FAIL; + } +#endif + if (jd_g_f_0f_update) { + JD_W("%s: Other thread is upgrade now\n", __func__); + err = JD_UPGRADE_CONFLICT; + } else { + JD_I("%s: Entering upgrade Flow\n", __func__); + jadard_int_enable(false); + jd_g_f_0f_update = true; + +#ifdef JD_UPGRADE_FW_ARRAY + JD_I("FW size = %d\n", (int)jd_fw_size); + err = g_module_fp.fp_ram_write(0, (uint8_t *)fw_data, jd_fw_size); +#else + JD_I("FW size = %d\n", (int)fw->size); + err = g_module_fp.fp_ram_write(0, (uint8_t *)fw->data, fw->size); + release_firmware(fw); +#endif + jd_g_f_0f_update = false; + + if (err >= 0) { + pjadard_ts_data->fw_ready = true; + } else { + pjadard_ts_data->fw_ready = false; + } + } + + return err; +} + +#ifdef JD_ESD_CHECK +static int jadard_mcu_0f_esd_upgrade_fw(char *file_name) +{ + int err = JD_NO_ERR; +#ifdef JD_UPGRADE_FW_ARRAY + const uint8_t *fw_data = jd_i_firmware; + JD_I("file name = %s\n", jd_i_CTPM_firmware_name); +#else + int RetryCnt; + const struct firmware *fw = NULL; + + JD_I("file name = %s\n", file_name); + + for (RetryCnt = 0; RetryCnt < JD_UPGRADE_FW_RETRY_TIME; RetryCnt++) { + err = request_firmware(&fw, file_name, pjadard_ts_data->dev); + if (err < 0) { + JD_E("%s: Open file fail(ret:%d), RetryCnt = %d\n", __func__, err, RetryCnt); + mdelay(1000); + } else { + break; + } + } + + if (RetryCnt == JD_UPGRADE_FW_RETRY_TIME) { + JD_E("%s: Open file fail retry over %d\n", __func__, JD_UPGRADE_FW_RETRY_TIME); + return JD_FILE_OPEN_FAIL; + } +#endif + if (jd_g_f_0f_update) { + JD_W("%s: Other thread is upgrade now\n", __func__); + err = JD_UPGRADE_CONFLICT; + } else { + JD_I("%s: Entering upgrade Flow\n", __func__); + jd_g_f_0f_update = true; + +#ifdef JD_UPGRADE_FW_ARRAY + JD_I("FW size = %d\n", (int)jd_fw_size); + err = g_module_fp.fp_esd_ram_write(0, (uint8_t *)fw_data, jd_fw_size); +#else + JD_I("FW size = %d\n", (int)fw->size); + err = g_module_fp.fp_esd_ram_write(0, (uint8_t *)fw->data, fw->size); + release_firmware(fw); +#endif + jd_g_f_0f_update = false; + + if ((err >= 0) || (err == JD_PRAM_CRC_PASS)) { + pjadard_ts_data->fw_ready = true; + } + } + + return err; +} + +static int jadard_mcu_esd_ram_write(uint32_t start_addr, uint8_t *wdata, uint32_t wlen) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return JD_NO_ERR; +} +#endif + +static void jadard_mcu_0f_operation(struct work_struct *work) +{ + int err = g_module_fp.fp_0f_upgrade_fw(jd_i_CTPM_firmware_name); + + if (err >= 0) { + g_module_fp.fp_read_fw_ver(); + jadard_int_enable(true); + } +} +#endif + +static int jadard_mcu_sorting_test(char *json_buf, size_t len) +{ + JD_I("%s: not support ITO test\n", __func__); + return JD_NO_ERR; +} + +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING +static void jadard_mcu_APP_SetSortingMode(uint8_t *value, uint8_t value_len) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_APP_ReadSortingMode(uint8_t *pValue, uint8_t pValue_len) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_APP_GetLcdSleep(uint8_t *pStatus) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_APP_SetSortingSkipFrame(uint8_t value) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_APP_SetSortingKeepFrame(uint8_t value) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static bool jadard_mcu_APP_ReadSortingBusyStatus(uint8_t mpap_handshake_finish, uint8_t *pStatus) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); + return false; +} + +static void jadard_mcu_GetSortingDiffData(uint8_t *pValue, uint16_t pValue_len) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_GetSortingDiffDataMax(uint8_t *pValue, uint16_t pValue_len) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_GetSortingDiffDataMin(uint8_t *pValue, uint16_t pValue_len) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_Fw_DBIC_Off(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_Fw_DBIC_On(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_StartMCU(void) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_SetMpBypassMain(void) +{ + JD_D("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_ClearMpBypassMain(void) +{ + JD_D("%s: nothing to do, only for function pointer initial\n", __func__); +} + +static void jadard_mcu_ReadMpapErrorMsg(uint8_t *pValue, uint8_t pValue_len) +{ + JD_I("%s: nothing to do, only for function pointer initial\n", __func__); +} +#endif + +static void jadard_mcu_fp_init(void) +{ + g_module_fp.fp_register_read = jadard_mcu_register_read; + g_module_fp.fp_register_write = jadard_mcu_register_write; + g_module_fp.fp_dd_register_read = jadard_mcu_dd_register_read; + g_module_fp.fp_dd_register_write = jadard_mcu_dd_register_write; + g_module_fp.fp_set_sleep_mode = jadard_mcu_set_sleep_mode; + g_module_fp.fp_read_fw_ver = jadard_mcu_read_fw_ver; + g_module_fp.fp_mutual_data_set = jadard_mcu_mutual_data_set; + g_module_fp.fp_get_mutual_data = jadard_mcu_get_mutual_data; + g_module_fp.fp_get_touch_data = jadard_mcu_get_touch_data; + g_module_fp.fp_read_mutual_data = jadard_mcu_read_mutual_data; + g_module_fp.fp_report_points = jadard_mcu_report_points; + g_module_fp.fp_parse_report_data = jadard_mcu_parse_report_data; + g_module_fp.fp_distribute_touch_data = jadard_mcu_distribute_touch_data; + g_module_fp.fp_flash_read = jadard_mcu_flash_read; + g_module_fp.fp_flash_write = jadard_mcu_flash_write; + g_module_fp.fp_flash_erase = jadard_mcu_flash_erase; + g_module_fp.fp_EnterBackDoor = jadard_mcu_EnterBackDoor; + g_module_fp.fp_ExitBackDoor = jadard_mcu_ExitBackDoor; + g_module_fp.fp_pin_reset = jadard_mcu_PinReset; + g_module_fp.fp_soft_reset = jadard_mcu_SoftReset; + g_module_fp.fp_ResetMCU = jadard_mcu_ResetMCU; + g_module_fp.fp_PorInit = jadard_mcu_PorInit; +#ifdef JD_RST_PIN_FUNC + g_module_fp.fp_ic_reset = jadard_mcu_ic_reset; +#endif + + g_module_fp.fp_ic_soft_reset = jadard_mcu_ic_soft_reset; + g_module_fp.fp_touch_info_set = jadard_mcu_touch_info_set; + g_module_fp.fp_report_data_reinit = jadard_mcu_report_data_reinit; + g_module_fp.fp_usb_detect_set = jadard_mcu_usb_detect_set; + g_module_fp.fp_get_freq_band = jadard_mcu_get_freq_band; + g_module_fp.fp_ReadDbicPageEn = jadard_mcu_ReadDbicPageEn; + g_module_fp.fp_SetDbicPage = jadard_mcu_SetDbicPage; + g_module_fp.fp_log_touch_state = jadard_mcu_log_touch_state; +#if defined(JD_SMART_WAKEUP) || defined(JD_USB_DETECT_GLOBAL) || defined(JD_USB_DETECT_CALLBACK) ||\ + defined(JD_HIGH_SENSITIVITY) || defined(JD_ROTATE_BORDER) || defined(JD_EARPHONE_DETECT) + g_module_fp.fp_resume_set_func = jadard_mcu_resume_set_func; +#endif + + g_module_fp.fp_set_high_sensitivity = jadard_mcu_set_high_sensitivity; + g_module_fp.fp_set_rotate_border = jadard_mcu_set_rotate_border; +#ifdef JD_EARPHONE_DETECT + g_module_fp.fp_set_earphone_enable = jadard_mcu_set_earphone_enable; +#endif + g_module_fp.fp_set_SMWP_enable = jadard_mcu_set_SMWP_enable; + g_module_fp.fp_set_virtual_proximity = jadard_mcu_set_virtual_proximity; +#ifdef JD_AUTO_UPGRADE_FW + g_module_fp.fp_read_fw_ver_bin = jadard_mcu_read_fw_ver_bin; +#endif + + g_module_fp.fp_ram_read = jadard_mcu_ram_read; +#ifdef JD_ZERO_FLASH + g_module_fp.fp_ram_write = jadard_mcu_ram_write; + g_module_fp.fp_0f_upgrade_fw = jadard_mcu_0f_upgrade_fw; +#ifdef JD_ESD_CHECK + g_module_fp.fp_0f_esd_upgrade_fw = jadard_mcu_0f_esd_upgrade_fw; + g_module_fp.fp_esd_ram_write = jadard_mcu_esd_ram_write; +#endif + g_module_fp.fp_0f_operation = jadard_mcu_0f_operation; +#endif + + g_module_fp.fp_sorting_test = jadard_mcu_sorting_test; +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + g_module_fp.fp_APP_SetSortingMode = jadard_mcu_APP_SetSortingMode; + g_module_fp.fp_APP_ReadSortingMode = jadard_mcu_APP_ReadSortingMode; + g_module_fp.fp_APP_GetLcdSleep = jadard_mcu_APP_GetLcdSleep; + g_module_fp.fp_APP_SetSortingSkipFrame = jadard_mcu_APP_SetSortingSkipFrame; + g_module_fp.fp_APP_SetSortingKeepFrame = jadard_mcu_APP_SetSortingKeepFrame; + g_module_fp.fp_APP_ReadSortingBusyStatus = jadard_mcu_APP_ReadSortingBusyStatus; + g_module_fp.fp_GetSortingDiffData = jadard_mcu_GetSortingDiffData; + g_module_fp.fp_GetSortingDiffDataMax = jadard_mcu_GetSortingDiffDataMax; + g_module_fp.fp_GetSortingDiffDataMin = jadard_mcu_GetSortingDiffDataMin; + g_module_fp.fp_Fw_DBIC_Off = jadard_mcu_Fw_DBIC_Off; + g_module_fp.fp_Fw_DBIC_On = jadard_mcu_Fw_DBIC_On; + g_module_fp.fp_StartMCU = jadard_mcu_StartMCU; + g_module_fp.fp_SetMpBypassMain = jadard_mcu_SetMpBypassMain; + g_module_fp.fp_ClearMpBypassMain = jadard_mcu_ClearMpBypassMain; + g_module_fp.fp_ReadMpapErrorMsg = jadard_mcu_ReadMpapErrorMsg; +#endif +} + +void jadard_mcu_cmd_struct_init(void) +{ + JD_D("%s: Entering!\n", __func__); + + jadard_mcu_fp_init(); +} diff --git a/drivers/input/touchscreen/jdchipset/jadard_module.h b/drivers/input/touchscreen/jdchipset/jadard_module.h new file mode 100644 index 0000000000000..639d7adb8bc6e --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_module.h @@ -0,0 +1,112 @@ +#ifndef JADARD_MODULE_H +#define JADARD_MODULE_H + +#define JD_ONE_SIZE 1 +#define JD_TWO_SIZE 2 +#define JD_THREE_SIZE 3 +#define JD_FOUR_SIZE 4 +#define JD_FIVE_SIZE 5 +#define JD_SIX_SIZE 6 +#define JD_SEVEN_SIZE 7 +#define JD_EIGHT_SIZE 8 + +struct jadard_common_variable { + uint32_t FW_SIZE; + uint32_t RAM_LEN; + uint8_t dbi_dd_reg_mode; +}; + +struct jadard_support_chip { + void (*chip_init)(void); + bool (*chip_detect)(void); + struct jadard_support_chip *next; +}; + +struct jadard_module_fp { + /* Support multiple chip */ + struct jadard_support_chip *head_support_chip; + + int (*fp_register_read)(uint32_t ReadAddr, uint8_t *ReadData, uint32_t ReadLen); + int (*fp_register_write)(uint32_t WriteAddr, uint8_t *WriteData, uint32_t WriteLen); + uint8_t (*fp_dd_register_read)(uint8_t page, uint8_t cmd, uint8_t *rpar, uint8_t rpar_len, uint32_t offset); + uint8_t (*fp_dd_register_write)(uint8_t page, uint8_t cmd, uint8_t *par, uint8_t par_len); + void (*fp_set_sleep_mode)(uint8_t *value, uint8_t value_len); + void (*fp_read_fw_ver)(void); + void (*fp_mutual_data_set)(uint8_t data_type); + int (*fp_get_mutual_data)(uint8_t data_type, uint8_t *rdata, uint16_t rlen); + bool (*fp_get_touch_data)(uint8_t *buf, uint8_t length); + int (*fp_read_mutual_data)(uint8_t *rdata, uint16_t rlen); + void (*fp_report_points)(struct jadard_ts_data *ts); + int (*fp_parse_report_data)(struct jadard_ts_data *ts, int irq_event, int ts_status); + int (*fp_distribute_touch_data)(struct jadard_ts_data *ts, uint8_t *buf, int irq_event, int ts_status); + int (*fp_flash_read)(uint32_t start_addr, uint8_t *rdata, uint32_t rlen); + int (*fp_flash_write)(uint32_t start_addr, uint8_t *wdata, uint32_t wlen); + int (*fp_flash_erase)(void); + void (*fp_EnterBackDoor)(void); + void (*fp_ExitBackDoor)(void); + void (*fp_pin_reset)(void); + void (*fp_soft_reset)(void); + void (*fp_ResetMCU)(void); + void (*fp_PorInit)(void); +#ifdef JD_RST_PIN_FUNC + void (*fp_ic_reset)(bool reload_cfg, bool int_off_on); +#endif + + void (*fp_ic_soft_reset)(void); + void (*fp_touch_info_set)(void); + void (*fp_report_data_reinit)(void); + void (*fp_usb_detect_set)(uint8_t *usb_status); + uint8_t (*fp_get_freq_band)(void); + uint8_t (*fp_ReadDbicPageEn)(void); + int (*fp_SetDbicPage)(uint8_t page); + void (*fp_log_touch_state)(void); +#if defined(JD_SMART_WAKEUP) || defined(JD_USB_DETECT_GLOBAL) || defined(JD_USB_DETECT_CALLBACK) ||\ + defined(JD_HIGH_SENSITIVITY) || defined(JD_ROTATE_BORDER) || defined(JD_EARPHONE_DETECT) + void (*fp_resume_set_func)(bool suspended); +#endif + + void (*fp_set_high_sensitivity)(bool enable); + void (*fp_set_rotate_border)(uint16_t rotate); +#ifdef JD_EARPHONE_DETECT + void (*fp_set_earphone_enable)(uint8_t status); +#endif + void (*fp_set_SMWP_enable)(bool enable); + void (*fp_set_virtual_proximity)(bool enable); +#ifdef JD_AUTO_UPGRADE_FW + int (*fp_read_fw_ver_bin)(void); +#endif + + int (*fp_ram_read)(uint32_t start_addr, uint8_t *rdata, uint32_t rlen); +#ifdef JD_ZERO_FLASH + int (*fp_ram_write)(uint32_t start_addr, uint8_t *wdata, uint32_t wlen); + int (*fp_0f_upgrade_fw)(char *file_name); +#ifdef JD_ESD_CHECK + int (*fp_0f_esd_upgrade_fw)(char *file_name); + int (*fp_esd_ram_write)(uint32_t start_addr, uint8_t *wdata, uint32_t wlen); +#endif + void (*fp_0f_operation)(struct work_struct *work); +#endif + + int (*fp_sorting_test)(char *json_buf, size_t len); +#ifdef CONFIG_TOUCHSCREEN_JADARD_SORTING + void (*fp_APP_SetSortingMode)(uint8_t *value, uint8_t value_len); + void (*fp_APP_ReadSortingMode)(uint8_t *pValue, uint8_t pValue_len); + void (*fp_APP_GetLcdSleep)(uint8_t *pStatus); + void (*fp_APP_SetSortingSkipFrame)(uint8_t value); + void (*fp_APP_SetSortingKeepFrame)(uint8_t value); + bool (*fp_APP_ReadSortingBusyStatus)(uint8_t mpap_handshake_finish, uint8_t *pStatus); + void (*fp_GetSortingDiffData)(uint8_t *pValue, uint16_t pValue_len); + void (*fp_GetSortingDiffDataMax)(uint8_t *pValue, uint16_t pValue_len); + void (*fp_GetSortingDiffDataMin)(uint8_t *pValue, uint16_t pValue_len); + void (*fp_Fw_DBIC_Off)(void); + void (*fp_Fw_DBIC_On)(void); + void (*fp_StartMCU)(void); + void (*fp_SetMpBypassMain)(void); + void (*fp_ClearMpBypassMain)(void); + void (*fp_ReadMpapErrorMsg)(uint8_t *pValue, uint8_t pValue_len); +#endif +}; + +void jadard_mcu_cmd_struct_init(void); + +#endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_platform.c b/drivers/input/touchscreen/jdchipset/jadard_platform.c new file mode 100644 index 0000000000000..944abd9effb2e --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_platform.c @@ -0,0 +1,898 @@ +#include "jadard_platform.h" + +extern struct jadard_ts_data *pjadard_ts_data; +extern struct jadard_ic_data *pjadard_ic_data; + +#ifdef CONFIG_JD_HID +extern struct jadard_i2c_hid *ihid; +#endif + +int jadard_dev_set(struct jadard_ts_data *ts) +{ + ts->input_dev = input_allocate_device(); + + if (ts->input_dev == NULL) { + JD_E("%s: Failed to allocate input device\n", __func__); + return -ENOMEM; + } + ts->input_dev->name = "jadard-touchscreen"; + + if (pjadard_ic_data->JD_STYLUS_EN) { + ts->stylus_dev = input_allocate_device(); + + if (ts->stylus_dev == NULL) { + JD_E("%s: Failed to allocate input stylus_dev\n", __func__); + input_free_device(ts->input_dev); + return -ENOMEM; + } + ts->stylus_dev->name = "jadard-stylus"; + } + + return 0; +} + +int jadard_input_register_device(struct input_dev *input_dev) +{ + return input_register_device(input_dev); +} + +int jadard_parse_dt(struct jadard_ts_data *ts, + struct jadard_platform_data *pdata) +{ + int coords_size = 0; + uint32_t coords[4] = {0}; + uint32_t ret, data; + struct property *prop = NULL; + struct device_node *dt = pjadard_ts_data->client->dev.of_node; + + ret = of_property_read_u32(dt, "jadard,panel-max-points", &data); + pjadard_ic_data->JD_MAX_PT = (!ret ? data : 10); + ret = of_property_read_u32(dt, "jadard,int-is-edge", &data); + pjadard_ic_data->JD_INT_EDGE = (!ret ? (data > 0 ? true : false) : true); + ret = of_property_read_u32(dt, "jadard,stylus", &data); + pjadard_ic_data->JD_STYLUS_EN = (!ret ? (data > 0 ? true : false) : false); + + JD_I("DT:MAX_PT = %d, INT_IS_EDGE = %d, STYLUS_EN = %d\n", pjadard_ic_data->JD_MAX_PT, + pjadard_ic_data->JD_INT_EDGE, pjadard_ic_data->JD_STYLUS_EN); + + prop = of_find_property(dt, "jadard,panel-sense-nums", NULL); + if (prop) { + coords_size = prop->length / sizeof(uint32_t); + + if (coords_size != 2) { + JD_E("%s:Invalid panel sense number size %d\n", __func__, coords_size); + return -EINVAL; + } + } + + if (of_property_read_u32_array(dt, "jadard,panel-sense-nums", coords, coords_size) == 0) { + pjadard_ic_data->JD_X_NUM = coords[0]; + pjadard_ic_data->JD_Y_NUM = coords[1]; + JD_I("DT:panel-sense-num = %d, %d\n", + pjadard_ic_data->JD_X_NUM, pjadard_ic_data->JD_Y_NUM); + } + + prop = of_find_property(dt, "jadard,panel-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(uint32_t); + + if (coords_size != 4) { + JD_E("%s:Invalid panel coords size %d\n", __func__, coords_size); + return -EINVAL; + } + } + + if (of_property_read_u32_array(dt, "jadard,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]; + pjadard_ic_data->JD_X_RES = pdata->abs_x_max; + pjadard_ic_data->JD_Y_RES = pdata->abs_y_max; + + JD_I("DT:panel-coords = %d, %d, %d, %d\n", pdata->abs_x_min, + pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); + } + + pdata->gpio_irq = of_get_named_gpio(dt, "jadard,irq-gpio", 0); + if (!gpio_is_valid(pdata->gpio_irq)) { + JD_I("DT:gpio_irq value is not valid\n"); + } + + pdata->gpio_reset = of_get_named_gpio(dt, "jadard,rst-gpio", 0); + if (!gpio_is_valid(pdata->gpio_reset)) { + JD_I("DT:gpio_rst value is not valid\n"); + } + + JD_I("DT:gpio_irq = %d, gpio_rst = %d\n", pdata->gpio_irq, pdata->gpio_reset); + + return 0; +} + +#ifdef CONFIG_JD_HID +int jadard_bus_read_single(uint8_t *data, uint16_t data_len, uint8_t toRetry) +{ + int retry; + struct i2c_client *client = pjadard_ts_data->client; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = client->flags & I2C_M_TEN, + .flags = client->flags | I2C_M_RD, + .len = data_len, + .buf = data, + } + }; + + mutex_lock(&pjadard_ts_data->rw_lock); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + + msleep(20); + } + + if (retry == toRetry) { + JD_E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&pjadard_ts_data->rw_lock); + return -EIO; + } + + mutex_unlock(&pjadard_ts_data->rw_lock); + return 0; +} +#endif + +int jadard_bus_read(uint8_t *cmd, uint8_t cmd_len, uint8_t *data, uint32_t data_len, uint8_t toRetry) +{ + int retry; + struct i2c_client *client = pjadard_ts_data->client; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = cmd_len, + .buf = cmd, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = data_len, + .buf = data, + } + }; + + mutex_lock(&pjadard_ts_data->rw_lock); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) + break; + + msleep(20); + } + + if (retry == toRetry) { + JD_E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + mutex_unlock(&pjadard_ts_data->rw_lock); + return -EIO; + } + + mutex_unlock(&pjadard_ts_data->rw_lock); + return 0; +} + +int jadard_bus_write(uint8_t *cmd, uint8_t cmd_len, uint8_t *data, uint32_t data_len, uint8_t toRetry) +{ + int retry; + uint8_t *buf = NULL; + struct i2c_client *client = pjadard_ts_data->client; + struct i2c_msg msg; + + mutex_lock(&pjadard_ts_data->rw_lock); + + buf = kzalloc((cmd_len + data_len) * sizeof(uint8_t), GFP_KERNEL); + if (buf == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + mutex_unlock(&pjadard_ts_data->rw_lock); + return -ENOMEM; + } + + memset(&msg, 0, sizeof(struct i2c_msg)); + /* Set I2C packet info. */ + msg.addr = client->addr; + msg.flags = 0; + msg.len = cmd_len + data_len; + msg.buf = buf; + + memcpy(buf, cmd, cmd_len); + memcpy(buf + cmd_len, data, data_len); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, &msg, 1) == 1) + break; + + msleep(20); + } + + if (retry == toRetry) { + JD_E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + kfree(buf); + mutex_unlock(&pjadard_ts_data->rw_lock); + return -EIO; + } + + kfree(buf); + mutex_unlock(&pjadard_ts_data->rw_lock); + return 0; +} + +void jadard_int_enable(bool enable) +{ + int irqnum = pjadard_ts_data->client->irq; + unsigned long irqflags = 0; + + spin_lock_irqsave(&pjadard_ts_data->irq_active, irqflags); + + if (enable && (pjadard_ts_data->irq_enabled == 0)) { + enable_irq(irqnum); + pjadard_ts_data->irq_enabled = 1; + } else if ((!enable) && (pjadard_ts_data->irq_enabled == 1)) { + disable_irq_nosync(irqnum); + pjadard_ts_data->irq_enabled = 0; + } + + JD_I("irq_enable = %d\n", pjadard_ts_data->irq_enabled); + spin_unlock_irqrestore(&pjadard_ts_data->irq_active, irqflags); +} + +#ifdef JD_RST_PIN_FUNC +void jadard_gpio_set_value(int pin_num, uint8_t value) +{ + gpio_set_value(pin_num, value); +} +#endif + +#if defined(CONFIG_JD_DB) +static int jadard_regulator_configure(struct jadard_platform_data *pdata) +{ + int retval; + struct i2c_client *client = pjadard_ts_data->client; + pdata->vcc_dig = regulator_get(&client->dev, "vdd"); + + if (IS_ERR(pdata->vcc_dig)) { + JD_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)) { + JD_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 jadard_power_on(struct jadard_platform_data *pdata, bool on) +{ + int retval; + + if (on) { + retval = regulator_enable(pdata->vcc_dig); + + if (retval) { + JD_E("%s: Failed to enable regulator vdd\n", + __func__); + return retval; + } + + msleep(100); + retval = regulator_enable(pdata->vcc_ana); + + if (retval) { + JD_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 jadard_gpio_power_config(struct jadard_platform_data *pdata) +{ + int error; + struct i2c_client *client = pjadard_ts_data->client; + + error = jadard_regulator_configure(pdata); + if (error) { + JD_E("Failed to intialize hardware\n"); + goto err_regulator_not_on; + } + +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_request(pdata->gpio_reset, "jadard_reset_gpio"); + + if (error) { + JD_E("unable to request rst-gpio [%d]\n", pdata->gpio_reset); + goto err_regulator_on; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + JD_E("unable to set direction for rst-gpio [%d]\n", pdata->gpio_reset); + goto err_gpio_reset_req; + } + } else { + JD_E("rst-gpio [%d] is not valid\n", pdata->gpio_reset); + goto err_regulator_on; + } +#endif + + error = jadard_power_on(pdata, true); + if (error) { + JD_E("Failed to power on hardware\n"); + goto err_gpio_reset_req; + } + + if (gpio_is_valid(pdata->gpio_irq)) { + error = gpio_request(pdata->gpio_irq, "jadard_gpio_irq"); + + if (error) { + JD_E("unable to request irq-gpio [%d]\n", pdata->gpio_irq); + goto err_power_on; + } + + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + JD_E("unable to set direction for irq-gpio [%d]\n", pdata->gpio_irq); + goto err_gpio_irq_req; + } + + client->irq = gpio_to_irq(pdata->gpio_irq); + pjadard_ts_data->jd_irq = (int)client->irq; + } else { + JD_E("irq-gpio [%d] is not valid\n", pdata->gpio_irq); + goto err_power_on; + } + + msleep(20); +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + + if (error) { + JD_E("unable to set direction for rst-gpio [%d]\n", pdata->gpio_reset); + goto err_gpio_irq_req; + } + gpio_free(pdata->gpio_reset); + } else { + JD_E("rst-gpio [%d] is not valid\n", pdata->gpio_reset); + goto err_gpio_irq_req; + } +#endif + + return 0; + +err_gpio_irq_req: + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); + +err_power_on: + jadard_power_on(pdata, false); +err_gpio_reset_req: +#ifdef JD_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; +} + +void jadard_gpio_power_deconfig(struct jadard_platform_data *pdata) +{ + /* Only QCOM DB platform using */ +} + +#else +int jadard_gpio_power_config(struct jadard_platform_data *pdata) +{ + int error = 0; + struct i2c_client *client = pjadard_ts_data->client; + +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_request(pdata->gpio_reset, "jadard_reset_gpio"); + + if (error) { + JD_E("unable to request rst-gpio [%d]\n", pdata->gpio_reset); + return error; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + JD_E("unable to set direction for rst-gpio [%d]\n", pdata->gpio_reset); + gpio_free(pdata->gpio_reset); + return error; + } + } else { + JD_E("rst-gpio [%d] is not valid\n", pdata->gpio_reset); + return error; + } +#endif + + if (gpio_is_valid(pdata->gpio_irq)) { + error = gpio_request(pdata->gpio_irq, "jadard_gpio_irq"); + + if (error) { + JD_E("unable to request irq-gpio [%d]\n", pdata->gpio_irq); +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + gpio_free(pdata->gpio_reset); + } +#endif + return error; + } + + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + JD_E("unable to set direction for irq-gpio [%d]\n", pdata->gpio_irq); + gpio_free(pdata->gpio_irq); +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + gpio_free(pdata->gpio_reset); + } +#endif + return error; + } + + client->irq = gpio_to_irq(pdata->gpio_irq); + pjadard_ts_data->jd_irq = client->irq; + } else { + JD_E("irq-gpio [%d] is not valid\n", pdata->gpio_irq); +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + gpio_free(pdata->gpio_reset); + } +#endif + return error; + } + + msleep(20); +#ifdef JD_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + + if (error) { + JD_E("unable to set direction for rst-gpio [%d]\n", pdata->gpio_reset); + gpio_free(pdata->gpio_reset); + if (gpio_is_valid(pdata->gpio_irq)) { + gpio_free(pdata->gpio_irq); + } + return error; + } + gpio_free(pdata->gpio_reset); + } else { + JD_E("rst-gpio [%d] is not valid\n", pdata->gpio_reset); + if (gpio_is_valid(pdata->gpio_irq)) { + gpio_free(pdata->gpio_irq); + } + return error; + } +#endif + + return error; +} + +void jadard_gpio_power_deconfig(struct jadard_platform_data *pdata) +{ + /* Only MTK plateform using */ +} + +#endif + +irqreturn_t jadard_ts_isr_func(int irq, void *ptr) +{ +#ifndef CONFIG_JD_HID +#ifdef JD_ZERO_FLASH + if (pjadard_ts_data->fw_ready == true) { + jadard_ts_work((struct jadard_ts_data *)ptr); + } +#else + jadard_ts_work((struct jadard_ts_data *)ptr); +#endif +#else + if (ihid->ready) { + jadard_i2c_hid_work((struct jadard_i2c_hid *)ptr); + } +#endif + return IRQ_HANDLED; +} + +int jadard_int_register_trigger(void) +{ + int ret = JD_NO_ERR; + struct i2c_client *client = pjadard_ts_data->client; + +#ifndef CONFIG_JD_HID + struct jadard_ts_data *ts = pjadard_ts_data; + + if (pjadard_ic_data->JD_INT_EDGE) { + JD_I("%s edge triiger\n", __func__); + ret = request_threaded_irq(client->irq, NULL, jadard_ts_isr_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); + } else { + JD_I("%s level trigger\n", __func__); + ret = request_threaded_irq(client->irq, NULL, jadard_ts_isr_func, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); + } +#else + if (pjadard_ic_data->JD_INT_EDGE) { + JD_I("%s edge triiger\n", __func__); + ret = request_threaded_irq(client->irq, NULL, jadard_ts_isr_func, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ihid); + } else { + JD_I("%s level trigger\n", __func__); + ret = request_threaded_irq(client->irq, NULL, jadard_ts_isr_func, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ihid); + } +#endif + return ret; +} + +void jadard_int_en_set(bool enable) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + if (enable) { + if (jadard_int_register_trigger() == 0) { + ts->irq_enabled = 1; + } + } else { + jadard_int_enable(false); + free_irq(ts->client->irq, ts); + } +} + +int jadard_ts_register_interrupt(void) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + struct i2c_client *client = pjadard_ts_data->client; + int ret = 0; + ts->irq_enabled = 0; + + if (client->irq) { + ret = jadard_int_register_trigger(); + + if (ret == 0) { + ts->irq_enabled = 1; + JD_I("%s: irq enabled at IRQ: %d\n", __func__, client->irq); + } else { + JD_E("%s: request_irq failed\n", __func__); + } + } else { + JD_I("%s: client->irq is empty.\n", __func__); + } + + return ret; +} + +void jadard_ts_free_interrupt(void) +{ + struct jadard_ts_data *ts = pjadard_ts_data; + + free_irq(ts->client->irq, ts); +} + +static int jadard_common_suspend(struct device *dev) +{ + struct jadard_ts_data *ts = dev_get_drvdata(dev); + + jadard_chip_common_suspend(ts); + + return 0; +} + +static int jadard_common_resume(struct device *dev) +{ + struct jadard_ts_data *ts = dev_get_drvdata(dev); + + jadard_chip_common_resume(ts); + + return 0; +} + +#if defined(JD_CONFIG_FB) +#ifdef JD_CONFIG_DRM +int jadard_drm_check_dt(struct jadard_ts_data *ts) +{ + struct device_node *dt = ts->dev->of_node; + struct device_node *node = NULL; + struct drm_panel *panel = NULL; + int i = 0; + int count = 0; + + count = of_count_phandle_with_args(dt, "panel", NULL); + if (count <= 0) { + JD_I("%s: find drm_panel count(%d) fail\n", __func__, count); + return 0; + } + JD_I("%s: find drm_panel count(%d)\n", __func__, count); + for (i = 0; i < count; i++) { + node = of_parse_phandle(dt, "panel", i); + JD_I("DRM:node = %p\n", node); + panel = of_drm_find_panel(node); + JD_I("DRM:panel = %p\n", panel); + + of_node_put(node); + if (!IS_ERR(panel)) { + JD_I("%s: find drm_panel successfully\n", __func__); + ts->active_panel = panel; + return 0; + } + } + + JD_E("%s: no find drm_panel\n", __func__); + + return 0; +} + +int jadard_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct drm_panel_notifier *evdata = data; + int *blank; + struct jadard_ts_data *ts = + container_of(self, struct jadard_ts_data, fb_notif); + JD_I("DRM: %s\n", __func__); + + if (evdata && evdata->data && + ((event == DRM_PANEL_EARLY_EVENT_BLANK) || (event == DRM_PANEL_EVENT_BLANK)) && + ts != NULL && ts->dev != NULL) { + blank = evdata->data; + JD_I("DRM event:%lu, blank:%d\n", event, *blank); + + switch (*blank) { + case DRM_PANEL_BLANK_UNBLANK: + if (DRM_PANEL_EARLY_EVENT_BLANK == event) { + JD_I("resume: event = %lu, Skipped\n", event); + } else if (DRM_PANEL_EVENT_BLANK == event) { + JD_I("resume: event = %lu, TP_RESUME\n", event); + jadard_common_resume(ts->dev); + } + break; + + case DRM_PANEL_BLANK_POWERDOWN: + if (DRM_PANEL_EARLY_EVENT_BLANK == event) { + JD_I("suspend: event = %lu, TP_SUSPEND\n", event); + jadard_common_suspend(ts->dev); + } else if (DRM_PANEL_EVENT_BLANK == event) { + JD_I("suspend: event = %lu, Skipped\n", event); + } + break; + } + } + + return 0; +} +#else +#ifdef JD_CONFIG_DRM_MSM +int jadard_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct jadard_ts_data *ts = + container_of(self, struct jadard_ts_data, fb_notif); + JD_I("MSM_DRM: %s\n", __func__); + + if (evdata && evdata->data && + ((event == MSM_DRM_EARLY_EVENT_BLANK) || (event == MSM_DRM_EVENT_BLANK)) && + ts != NULL && ts->dev != NULL) { + blank = evdata->data; + JD_I("MSM_DRM event:%lu, blank:%d\n", event, *blank); + + switch (*blank) { + case MSM_DRM_BLANK_UNBLANK: + if (MSM_DRM_EARLY_EVENT_BLANK == event) { + JD_I("resume: event = %lu, Skipped\n", event); + } else if (MSM_DRM_EVENT_BLANK == event) { + JD_I("resume: event = %lu, TP_RESUME\n", event); + jadard_common_resume(ts->dev); + } + break; + + case MSM_DRM_BLANK_POWERDOWN: + if (MSM_DRM_EARLY_EVENT_BLANK == event) { + JD_I("suspend: event = %lu, TP_SUSPEND\n", event); + jadard_common_suspend(ts->dev); + } else if (MSM_DRM_EVENT_BLANK == event) { + JD_I("suspend: event = %lu, Skipped\n", event); + } + break; + } + } + + return 0; +} +#else +int jadard_fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct jadard_ts_data *ts = + container_of(self, struct jadard_ts_data, fb_notif); + JD_I("FB: %s\n", __func__); + + if (evdata && evdata->data && + ((event == FB_EARLY_EVENT_BLANK) || (event == FB_EVENT_BLANK)) && + ts != NULL && ts->dev != NULL) { + blank = evdata->data; + JD_I("FB event:%lu, blank:%d\n", event, *blank); + + switch (*blank) { + case FB_BLANK_UNBLANK: + if (FB_EARLY_EVENT_BLANK == event) { + JD_I("resume: event = %lu, Skipped\n", event); + } else if (FB_EVENT_BLANK == event) { + JD_I("resume: event = %lu, TP_RESUME\n", event); + jadard_common_resume(ts->dev); + } + break; + + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + if (FB_EARLY_EVENT_BLANK == event) { + JD_I("suspend: event = %lu, TP_SUSPEND\n", event); + jadard_common_suspend(ts->dev); + } else if (FB_EVENT_BLANK == event) { + JD_I("suspend: event = %lu, Skipped\n", event); + } + break; + } + } + + return 0; +} +#endif /* JD_CONFIG_DRM_MSM */ +#endif /* JD_CONFIG_DRM */ +#endif /* defined(JD_CONFIG_FB) */ + +int jadard_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct jadard_ts_data *ts = NULL; + + JD_I("%s:Enter \n", __func__); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + JD_E("%s: i2c check functionality error\n", __func__); + return -ENODEV; + } + + ts = kzalloc(sizeof(struct jadard_ts_data), GFP_KERNEL); + if (ts == NULL) { + JD_E("%s: allocate jadard_ts_data failed\n", __func__); + return -ENOMEM; + } + + ts->client = client; + ts->dev = &client->dev; + ts->spi = NULL; + i2c_set_clientdata(client, ts); + + mutex_init(&ts->rw_lock); + pjadard_ts_data = ts; + spin_lock_init(&ts->irq_active); + + return jadard_chip_common_init(); +} + +void jadard_chip_common_remove(struct i2c_client *client) +{ + jadard_chip_common_deinit(); +} + +static const struct i2c_device_id jadard_common_ts_id[] = { + {JADARD_common_NAME, 0 }, + {} +}; + +static const struct dev_pm_ops jadard_common_pm_ops = { +#if (!defined(JD_CONFIG_FB)) && (!defined(JD_CONFIG_DRM)) + .suspend = jadard_common_suspend, + .resume = jadard_common_resume, +#endif +}; + +#ifdef CONFIG_OF +static struct of_device_id jadard_match_table[] = { + {.compatible = "jadard,jdcommon" }, + {}, +}; +#else +#define jadard_match_table NULL +#endif + +static struct i2c_driver jadard_common_driver = { + .id_table = jadard_common_ts_id, + .probe = jadard_chip_common_probe, + .remove = jadard_chip_common_remove, + .driver = { + .name = JADARD_common_NAME, + .owner = THIS_MODULE, + .of_match_table = jadard_match_table, +/* #ifdef CONFIG_PM + .pm = &jadard_common_pm_ops, +#endif */ + }, +}; + +#if defined(__JADARD_KMODULE__) +int jadard_common_init(void) +{ + JD_I("I2C Jadard kmodule common touch panel driver init\n"); + + i2c_add_driver(&jadard_common_driver); + + return 0; +} + +void jadard_common_exit(void) +{ + i2c_del_driver(&jadard_common_driver); +} + +#else +static int __init jadard_common_init(void) +{ + JD_I("I2C Jadard common touch panel driver init\n"); + +#ifndef CONFIG_JD_DB + i2c_add_driver(&jadard_common_driver); +#endif + + return 0; +} + +#if defined(CONFIG_JD_DB) +void jadard_workarround_init(void) +{ + JD_I("I2C jadard_workarround_init by Driver\n"); + + i2c_add_driver(&jadard_common_driver); +} +#endif + +static void __exit jadard_common_exit(void) +{ + i2c_del_driver(&jadard_common_driver); +} + +module_init(jadard_common_init); +module_exit(jadard_common_exit); + +MODULE_DESCRIPTION("Jadard_common driver"); +MODULE_LICENSE("GPL"); + +#endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_platform.h b/drivers/input/touchscreen/jdchipset/jadard_platform.h new file mode 100644 index 0000000000000..dfd9315267ba9 --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_platform.h @@ -0,0 +1,75 @@ +#ifndef JADARD_PLATFORM_H +#define JADARD_PLATFORM_H + +#include "jadard_common.h" + +#ifdef CONFIG_JD_HID +#include "jadard_hid.h" +#endif + +#if defined(CONFIG_JD_DB) +#include +#endif + +#define JADARD_common_NAME "jadard_tp" +#define JADARD_BUS_RETRY_TIMES 10 + +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) +extern bool jd_g_dbg_enable; +extern bool jd_g_esd_check_enable; +#define JD_I(x...) \ +do { if (!jd_g_esd_check_enable) printk("[JDTP] " x); } while (0) +#define JD_W(x...) printk("[JDTP][WARNING] " x) +#define JD_E(x...) printk("[JDTP][ERROR] " x) +#define JD_D(x...) \ +do { if (jd_g_dbg_enable) printk("[JDTP][DEBUG] " x); } while (0) +#else +#define JD_I(x...) +#define JD_W(x...) +#define JD_E(x...) +#define JD_D(x...) +#endif + +struct jadard_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; + uint8_t usb_status[2]; + int gpio_irq; + int gpio_reset; + +#if defined(CONFIG_JD_DB) + struct regulator *vcc_ana; /* For Dragon Board */ + struct regulator *vcc_dig; /* For Dragon Board */ +#endif +}; + +#ifdef CONFIG_JD_HID +int jadard_bus_read_single(uint8_t *data, uint16_t data_len, uint8_t toRetry); +#endif +int jadard_bus_read(uint8_t *cmd, uint8_t cmd_len, uint8_t *data, uint32_t data_len, uint8_t toRetry); +int jadard_bus_write(uint8_t *cmd, uint8_t cmd_len, uint8_t *data, uint32_t data_len, uint8_t toRetry); +void jadard_int_en_set(bool enable); +void jadard_int_enable(bool enable); +int jadard_ts_register_interrupt(void); +void jadard_ts_free_interrupt(void); +int jadard_gpio_power_config(struct jadard_platform_data *pdata); +void jadard_gpio_power_deconfig(struct jadard_platform_data *pdata); + +#if defined(JD_CONFIG_FB) +int jadard_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +#endif + +#ifdef JD_RST_PIN_FUNC +void jadard_gpio_set_value(int pin_num, uint8_t value); +#endif + +#endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_sorting.c b/drivers/input/touchscreen/jdchipset/jadard_sorting.c new file mode 100644 index 0000000000000..201cd4c9a1935 --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_sorting.c @@ -0,0 +1,2402 @@ +#include "jadard_common.h" +#include "jadard_module.h" +#include "jadard_sorting.h" +extern struct jadard_module_fp g_module_fp; +extern struct jadard_ts_data *pjadard_ts_data; +extern struct jadard_ic_data *pjadard_ic_data; +extern struct jadard_common_variable g_common_variable; +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) +extern bool jd_g_dbg_enable; +#endif +void jadard_sorting_init(void); + +static uint8_t LCD_Status = JD_LCD_STATUS_DISPLAY_ON; +static int Soc_Debug_Number; +static bool SocReset_Flag; +static int ModeEnter_Flag; +static bool Switch_Mode_Timeout_Flag; +static int PST_GetFrameOfRawData_Number; +static uint16_t MP_Recb_Timeout; +static uint32_t jd_g_rslt_data_len; + +/* { + * {Skip_OpenData_Frame_Number, Get_OpenData_Frame_Number, Test or not}, + * {Skip_ShortData_Frame_Number, Get_ShortData_Frame_Number, Test or not}, + * {Skip_NormalSBDev_Frame_Number, Get_NormalSBDev_Frame_Number, Test or not}, + * {Skip_NormalActiveNoise_Frame_Number, Get_NormalActiveNoise_Frame_Number, Test or not}, + * {Skip_NormalIdleData_Frame_Number, Get_NormalIdleData_Frame_Number, Test or not}, + * {Skip_NormalIdleNoise_Frame_Number, Get_NormalIdleNoise_Frame_Number, Test or not}, + * {Skip_LpwugSBDev_Frame_Number, Get_LpwugSBDev_Frame_Number, Test or not}, + * {Skip_LpwugActiveNoise_Frame_Number, Get_LpwugActiveNoise_Frame_Number, Test or not}, + * {Skip_LpwugIdleData_Frame_Number, Get_LpwugIdleData_Frame_Number, Test or not}, + * {Skip_LpwugIdleNoise_Frame_Number, Get_LpwugIdleNoise_Frame_Number, Test or not} + * } + */ +uint16_t jd_pst_global_variable[JD_SORTING_ACTIVE_ITEM][3] = { + {3, 3, 0}, + {3, 3, 0}, + {3, 3, 0}, + {3, 50, 0}, + {3, 3, 0}, + {3, 50, 0}, + {3, 3, 0}, + {3, 50, 0}, + {3, 3, 0}, + {3, 50, 0} +}; + +static int jd_test_data_pop_out(char *rslt_buf, char *filepath, int result) +{ +#if defined(__JADARD_GKI__) + JD_I("Cancel write result file for GKI\n"); + return JD_SORTING_OK; +#else + struct file *raw_file = NULL; + loff_t pos = 0; + int ret_val = JD_SORTING_OK; + + if (result == 0) { + scnprintf(filepath, 64, "%s_Pass.txt", filepath); + } else { + scnprintf(filepath, 64, "%s_Fail.txt", filepath); + } + + JD_D("%s: Entering!\n", __func__); + JD_I("data size=0x%04X\n", jd_g_rslt_data_len); + JD_I("Ouput result to %s\n", filepath); + + + raw_file = filp_open(filepath, O_TRUNC|O_CREAT|O_RDWR, 0660); + if (IS_ERR(raw_file)) { + JD_E("%s open file failed = %ld\n", __func__, PTR_ERR(raw_file)); + ret_val = -EIO; + goto SAVE_DATA_ERR; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0) + kernel_write(raw_file, rslt_buf, jd_g_rslt_data_len, &pos); +#else + kernel_write(raw_file, rslt_buf, jd_g_rslt_data_len, pos); +#endif + if (raw_file != NULL) { + filp_close(raw_file, NULL); + } + +SAVE_DATA_ERR: + JD_D("%s: End!\n", __func__); + + return ret_val; +#endif +} + +static void jadard_sorting_data_deinit(void) +{ + int i = 0; + + if (jd_g_sorting_threshold) { + for (i = 0; i < JD_READ_THRESHOLD_SIZE; i++) { + if (jd_g_sorting_threshold[i]) { + vfree(jd_g_sorting_threshold[i]); + jd_g_sorting_threshold[i] = NULL; + } + } + vfree(jd_g_sorting_threshold); + jd_g_sorting_threshold = NULL; + JD_I("Free the jd_g_sorting_threshold\n"); + } + + if (jd_g_json_data) { + vfree(jd_g_json_data); + jd_g_json_data = NULL; + } + + if (jd_g_file_path) { + vfree(jd_g_file_path); + jd_g_file_path = NULL; + } + + if (jd_g_rslt_data) { + vfree(jd_g_rslt_data); + jd_g_rslt_data = NULL; + } + + if (GET_RAWDATA) { + vfree(GET_RAWDATA); + GET_RAWDATA = NULL; + } +} + +static void jadard_pst_enter_normal_mode(void) +{ + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + os_test_mode_password[0] = JD_MPAP_PW_NORMAL_ACTIVE_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_NORMAL_ACTIVE_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); +} + +#if (JD_PRODUCT_TYPE == 1) +static void jadard_pst_enter_slpin_mode_bymppw(void) +{ + int retry = 100; + uint8_t mpap_sleep_password[JD_TWO_SIZE]; + + JD_I("Start to Enter Sleep In\n"); + + mpap_sleep_password[0] = JD_MPAP_PW_SLEEP_IN_hbyte; + mpap_sleep_password[1] = JD_MPAP_PW_SLEEP_IN_lbyte; + g_module_fp.fp_set_sleep_mode(mpap_sleep_password, sizeof(mpap_sleep_password)); + + do { + mdelay(10); + g_module_fp.fp_APP_GetLcdSleep(&LCD_Status); + } while ((--retry > 0) && (LCD_Status == JD_LCD_STATUS_SLEEP_OUT)); + + if (LCD_Status != JD_LCD_STATUS_SLEEP_IN) { + JD_I("Enter Sleep In Fail\n"); + } else { + JD_I("Enter Sleep In Finished\n"); + } + + jadard_pst_enter_normal_mode(); +} +#else +static void jadard_pst_enter_slpin_mode(void) +{ + int retry = 20; + + JD_I("Start to Enter Sleep In\n"); + + jadard_pst_enter_normal_mode(); + g_module_fp.fp_APP_GetLcdSleep(&LCD_Status); + + if (LCD_Status != JD_LCD_STATUS_SLEEP_IN) { + g_module_fp.fp_dd_register_write(0x00, 0x28, NULL, 0); + g_module_fp.fp_dd_register_write(0x00, 0x10, NULL, 0); + } + + do { + mdelay(100); + g_module_fp.fp_APP_GetLcdSleep(&LCD_Status); + } while ((--retry > 0) && (LCD_Status == JD_LCD_STATUS_SLEEP_OUT)); + + /* Retry */ + if (LCD_Status != JD_LCD_STATUS_SLEEP_IN) { + retry = 20; + g_module_fp.fp_dd_register_write(0x00, 0x28, NULL, 0); + g_module_fp.fp_dd_register_write(0x00, 0x10, NULL, 0); + + do { + mdelay(100); + g_module_fp.fp_APP_GetLcdSleep(&LCD_Status); + } while ((--retry > 0) && (LCD_Status == JD_LCD_STATUS_SLEEP_OUT)); + } + + if (LCD_Status != JD_LCD_STATUS_SLEEP_IN) { + JD_I("Enter Sleep In Fail\n"); + } else { + JD_I("Enter Sleep In Finished\n"); + } +} +#endif + +#if (JD_PRODUCT_TYPE == 1) +static void jadard_pst_enter_slpout_mode_bymppw(void) +{ + int retry = 100; + uint8_t mpap_sleep_password[JD_TWO_SIZE]; + + JD_I("Start to Enter Sleep Out\n"); + + mpap_sleep_password[0] = JD_MPAP_PW_SLEEP_OUT_hbyte; + mpap_sleep_password[1] = JD_MPAP_PW_SLEEP_OUT_lbyte; + g_module_fp.fp_set_sleep_mode(mpap_sleep_password, sizeof(mpap_sleep_password)); + + do { + mdelay(10); + g_module_fp.fp_APP_GetLcdSleep(&LCD_Status); + } while ((--retry > 0) && (LCD_Status == JD_LCD_STATUS_SLEEP_IN)); + + if (LCD_Status != JD_LCD_STATUS_SLEEP_OUT) { + JD_I("Enter Sleep Out Fail\n"); + } else { + JD_I("Enter Sleep Out Finished\n"); + } + + jadard_pst_enter_normal_mode(); +} +#else +static void jadard_pst_enter_slpout_mode(void) +{ + int retry = 20; + + JD_I("Start to Enter Sleep Out\n"); + + jadard_pst_enter_normal_mode(); + g_module_fp.fp_APP_GetLcdSleep(&LCD_Status); + + if (LCD_Status != JD_LCD_STATUS_SLEEP_OUT) { + g_module_fp.fp_dd_register_write(0x00, 0x11, NULL, 0); + g_module_fp.fp_dd_register_write(0x00, 0x29, NULL, 0); + } + + do { + mdelay(100); + g_module_fp.fp_APP_GetLcdSleep(&LCD_Status); + } while ((--retry > 0) && (LCD_Status == JD_LCD_STATUS_SLEEP_IN)); + + if (LCD_Status != JD_LCD_STATUS_SLEEP_OUT) { + retry = 20; + g_module_fp.fp_dd_register_write(0x00, 0x11, NULL, 0); + g_module_fp.fp_dd_register_write(0x00, 0x29, NULL, 0); + + do { + mdelay(100); + g_module_fp.fp_APP_GetLcdSleep(&LCD_Status); + } while ((--retry > 0) && (LCD_Status == JD_LCD_STATUS_SLEEP_IN)); + } + + if (LCD_Status != JD_LCD_STATUS_SLEEP_OUT) { + JD_I("Enter Sleep Out Fail\n"); + } else { + JD_I("Enter Sleep Out Finished\n"); + } +} +#endif + +static void jadard_PST_Enter_LpwugIdle_Diff_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_LPWUG_IDLE_DIFF_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_LPWUG_IDLE_DIFF_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_PST_Enter_LpwugIdle_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_LPWUG_IDLE_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_LPWUG_IDLE_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_PST_Enter_LpwugActive_Diff_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_LPWUG_ACTIVE_DIFF_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_LPWUG_ACTIVE_DIFF_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_PST_Enter_LpwugActive_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_LPWUG_ACTIVE_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_LPWUG_ACTIVE_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_PST_Enter_NormalIdle_Diff_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_NORMAL_IDLE_DIFF_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_NORMAL_IDLE_DIFF_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_PST_Enter_NormalIdle_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_NORMAL_IDLE_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_NORMAL_IDLE_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_PST_Enter_NormalActive_Diff_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_NORMAL_ACTIVE_DIFF_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_NORMAL_ACTIVE_DIFF_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_PST_Enter_NormalActive_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_NORMAL_ACTIVE_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_NORMAL_ACTIVE_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_pst_enter_short_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_SHORT_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_SHORT_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static void jadard_pst_enter_open_mode(void) +{ + int retry = 0; + uint8_t os_test_mode_password[JD_TWO_SIZE]; + + do { + if (retry != 0) + mdelay(50); + + os_test_mode_password[0] = JD_MPAP_PW_MP_OPEN_START_hbyte; + os_test_mode_password[1] = JD_MPAP_PW_MP_OPEN_START_lbyte; + g_module_fp.fp_APP_SetSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + + /* Check pssword */ + g_module_fp.fp_APP_ReadSortingMode(os_test_mode_password, sizeof(os_test_mode_password)); + } while ((os_test_mode_password[0] == 0xFF) && (os_test_mode_password[1] == 0xFF) && (retry++ < 3)); +} + +static uint16_t jadard_ReadSortingMode(int *PST_MP_Mode_Index) +{ + uint8_t OS_TEST_MODE_PASSWORD[JD_TWO_SIZE]; + + *PST_MP_Mode_Index = -1; + OS_TEST_MODE_PASSWORD[0] = 0x00; + OS_TEST_MODE_PASSWORD[1] = 0x00; + + g_module_fp.fp_APP_ReadSortingMode(OS_TEST_MODE_PASSWORD, sizeof(OS_TEST_MODE_PASSWORD)); + JD_D("MP_PW=0x%02X%02X\n", OS_TEST_MODE_PASSWORD[1], OS_TEST_MODE_PASSWORD[0]); + + if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_SORTING_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_SORTING_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_Sorting; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_SHORT_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_SHORT_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_Short; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_OPEN_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_OPEN_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_Open; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_NORMAL_ACTIVE_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_NORMAL_ACTIVE_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_MP_Normal_Active; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_NORMAL_ACTIVE_DIFF_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_NORMAL_ACTIVE_DIFF_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_MP_Normal_Active_Diff; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_NORMAL_IDLE_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_NORMAL_IDLE_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_MP_Normal_Idle; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_NORMAL_IDLE_DIFF_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_NORMAL_IDLE_DIFF_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_MP_Normal_Idle_Diff; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_LPWUG_ACTIVE_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_LPWUG_ACTIVE_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_MP_LPWUG_Active; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_LPWUG_ACTIVE_DIFF_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_LPWUG_ACTIVE_DIFF_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_MP_LPWUG_Active_Diff; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_LPWUG_IDLE_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_LPWUG_IDLE_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_MP_LPWUG_Idle; + } else if ((OS_TEST_MODE_PASSWORD[0] == JD_MPAP_PW_MP_LPWUG_IDLE_DIFF_FINISH_hbyte) && (OS_TEST_MODE_PASSWORD[1] == JD_MPAP_PW_MP_LPWUG_IDLE_DIFF_FINISH_lbyte)) { + *PST_MP_Mode_Index = JD_PST_MP_Mode_MP_LPWUG_Idle_Diff; + } + /* Read reCb timeout flag */ + g_module_fp.fp_ReadMpapErrorMsg(OS_TEST_MODE_PASSWORD, sizeof(OS_TEST_MODE_PASSWORD)); + + return (OS_TEST_MODE_PASSWORD[1] << 8) + OS_TEST_MODE_PASSWORD[0]; +} + +static void jadard_PST_SwitchSortMode_Check(int *enter_flag, int PST_MP_Mode_Index, bool *switch_mode_timeout_flag) +{ + int counter = 0; + *enter_flag = -1; + *switch_mode_timeout_flag = false; + + while (*enter_flag != PST_MP_Mode_Index) { + mdelay(50); + MP_Recb_Timeout = jadard_ReadSortingMode(enter_flag); + + if (counter++ > 50) { + *switch_mode_timeout_flag = true; +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Switch SortMode Fail\n"); +#endif + JD_I("Switch SortMode Check: %d, not equal %d\n", *enter_flag, PST_MP_Mode_Index); + *enter_flag = JD_PST_MP_Mode_Null; + return; + } + } +} + +static void jadard_PST_LpwugIdle_Diff_Mode(void) +{ + JD_I("Start to Enter LPWUG Idle Diff Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[9][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[9][1]; + /* Setting Keep Frame */ + if (PST_GetFrameOfRawData_Number < 3) + PST_GetFrameOfRawData_Number = 3; + g_module_fp.fp_APP_SetSortingKeepFrame(PST_GetFrameOfRawData_Number); + + jadard_PST_Enter_LpwugIdle_Diff_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_MP_LPWUG_Idle_Diff, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter LPWUG Idle Diff Mode Fail\n"); +#endif + JD_I("Retry LPWUG Idle Diff Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter LPWUG Idle Diff Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_LpwugIdle_Mode(void) +{ + JD_I("Start to Enter LPWUG Idle Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[8][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[8][1]; + + jadard_PST_Enter_LpwugIdle_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_MP_LPWUG_Idle, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter LPWUG Idle Mode Fail\n"); +#endif + JD_I("Retry LPWUG Idle Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter LPWUG Idle Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_LpwugActive_Diff_Mode(void) +{ + JD_I("Start to LPWUG Active Diff Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[7][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[7][1]; + /* Setting Keep Frame */ + if (PST_GetFrameOfRawData_Number < 3) + PST_GetFrameOfRawData_Number = 3; + g_module_fp.fp_APP_SetSortingKeepFrame(PST_GetFrameOfRawData_Number); + + jadard_PST_Enter_LpwugActive_Diff_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_MP_LPWUG_Active_Diff, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter LPWUG Active Diff Mode Fail\n"); +#endif + JD_I("Retry LPWUG Active Diff Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter LPWUG Active Diff Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_LpwugActive_Mode(void) +{ + JD_I("Start to LPWUG Active Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[6][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[6][1]; + + jadard_PST_Enter_LpwugActive_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_MP_LPWUG_Active, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter LPWUG Active Mode Fail\n"); +#endif + JD_I("Retry LPWUG Active Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter LPWUG Active Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_NormalIdle_Diff_Mode(void) +{ + JD_I("Start to Enter Normal Idle Diff Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[5][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[5][1]; + /* Setting Keep Frame */ + if (PST_GetFrameOfRawData_Number < 3) + PST_GetFrameOfRawData_Number = 3; + g_module_fp.fp_APP_SetSortingKeepFrame(PST_GetFrameOfRawData_Number); + + jadard_PST_Enter_NormalIdle_Diff_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_MP_Normal_Idle_Diff, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter Normal Idle Diff Mode Fail\n"); +#endif + JD_I("Retry Normal Idle Diff Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter Normal Idle Diff Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_NormalIdle_Mode(void) +{ + JD_I("Start to Enter Normal Idle Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[4][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[4][1]; + + jadard_PST_Enter_NormalIdle_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_MP_Normal_Idle, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter Normal Idle Mode Fail\n"); +#endif + JD_I("Retry Normal Idle Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter Normal Idle Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_NormalActive_Diff_Mode(void) +{ + JD_I("Start to Enter Normal Active Diff Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[3][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[3][1]; + /* Setting Keep Frame */ + if (PST_GetFrameOfRawData_Number < 3) + PST_GetFrameOfRawData_Number = 3; + g_module_fp.fp_APP_SetSortingKeepFrame(PST_GetFrameOfRawData_Number); + + jadard_PST_Enter_NormalActive_Diff_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_MP_Normal_Active_Diff, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter Normal Active Diff Mode Fail\n"); +#endif + JD_I("Retry Normal Active Diff Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter Normal Active Diff Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_NormalActive_Mode(void) +{ + JD_I("Start to Enter Normal Active Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[2][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[2][1]; + + jadard_PST_Enter_NormalActive_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_MP_Normal_Active, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter Normal Active Mode Fail\n"); +#endif + JD_I("Retry Normal Active Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter Normal Active Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_Short_Mode(void) +{ + JD_I("Start to Enter Short Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[1][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[1][1]; + + jadard_pst_enter_short_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_Short, &Switch_Mode_Timeout_Flag); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter Short Mode Fail\n"); +#endif + JD_I("Retry Short Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter Short Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_Open_Mode(void) +{ + JD_I("Start to Enter Open Mode\n"); + + g_module_fp.fp_SetMpBypassMain(); + g_module_fp.fp_APP_SetSortingSkipFrame((uint8_t)jd_pst_global_variable[0][0]); + PST_GetFrameOfRawData_Number = jd_pst_global_variable[0][1]; + + jadard_pst_enter_open_mode(); + jadard_PST_SwitchSortMode_Check(&ModeEnter_Flag, JD_PST_MP_Mode_Open, &Switch_Mode_Timeout_Flag); + + JD_I("MP_Recb_Timeout = 0x%04x\n", MP_Recb_Timeout); + + if ((ModeEnter_Flag == JD_PST_MP_Mode_Null) && (Switch_Mode_Timeout_Flag == true)) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Enter Open Mode Fail\n"); +#endif + JD_I("Retry Open Mode Switching\n"); + SocReset_Flag = true; + } else { + JD_I("Enter Open Mode Finished\n"); + } + g_module_fp.fp_ClearMpBypassMain(); +} + +static void jadard_PST_Enter_Diff_Type_Mode(void) +{ + JD_I("Start to Enter Diff Type Mode\n"); + g_module_fp.fp_mutual_data_set(JD_DATA_TYPE_Difference); + JD_I("Enter Diff Type Finished\n"); +} + +static void jadard_PST_Enter_RawData_Type_Mode(void) +{ + JD_I("Start to Enter RawData Type Mode\n"); + g_module_fp.fp_mutual_data_set(JD_DATA_TYPE_RawData); + JD_I("Enter RawData Type Finished\n"); +} + +static void jadard_CPST_GetDataRun(void) +{ + uint16_t rdata_size = pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM * sizeof(uint16_t); + int i = 0; + + do { + if (g_module_fp.fp_get_mutual_data(JD_DATA_TYPE_RawData, GET_RAWDATA, rdata_size) < 0) { + SocReset_Flag = true; + break; + } + } while (i++ < PST_GetFrameOfRawData_Number); +} + +static void jadard_Sorting_BusyStatus_Check(void) +{ + int counter = 0; + uint8_t pStatus = 0; + + JD_I("Start Sorting_BusyStatus_Check\n"); + + while (g_module_fp.fp_APP_ReadSortingBusyStatus(JD_MPAP_HANDSHAKE_FINISH, &pStatus) == false) { + mdelay(50); + + if (counter++ > 200) { + SocReset_Flag = true; +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("MPAP HandShake Fail\n"); +#endif + JD_I("MPAP_HandShake_Status: 0x%02X\n", pStatus); + return; + } else { + SocReset_Flag = false; + } + } + + JD_I("Sorting_BusyStatus_Check Pass\n"); +} + +static void jadard_Start_to_Get_DiffData_Function(void) +{ + int half_rawdata_len = pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM * sizeof(uint8_t); + + JD_I("Start to Get Diff Data\n"); + memset(GET_RAWDATA, 0x00, half_rawdata_len * 2); + + jadard_Sorting_BusyStatus_Check(); + if (SocReset_Flag == true) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Get Diff Data Fail\n"); +#endif + JD_I("Retry Diff Data Reading\n"); + } else { + if (g_module_fp.fp_GetSortingDiffData) { + g_module_fp.fp_GetSortingDiffData(GET_RAWDATA, half_rawdata_len * 2); + } else { +#if JD_SORTING_NOISE_DIFF_MIN + if (g_module_fp.fp_GetSortingDiffDataMax && g_module_fp.fp_GetSortingDiffDataMin) { + g_module_fp.fp_GetSortingDiffDataMax(GET_RAWDATA, half_rawdata_len); + g_module_fp.fp_GetSortingDiffDataMin(GET_RAWDATA + half_rawdata_len, half_rawdata_len); +#else + if (g_module_fp.fp_GetSortingDiffDataMax) { + g_module_fp.fp_GetSortingDiffDataMax(GET_RAWDATA, half_rawdata_len * 2); +#endif + } else { + JD_E("Get Diff Data function does not exist\n"); + } + } + JD_I("Get Diff Data Finished\n"); + } +} + +static void jadard_Start_to_Get_RawData_Function(void) +{ + JD_I("Start to Get Raw Data\n"); + memset(GET_RAWDATA, 0x00, pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM * sizeof(uint16_t)); + + if (PST_GetFrameOfRawData_Number < 3) { + PST_GetFrameOfRawData_Number = 3; + } + + jadard_CPST_GetDataRun(); + + if (SocReset_Flag == true) { +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + if (jd_g_dbg_enable) + JD_E("Get Raw Data Fail\n"); +#endif + JD_I("Retry Raw Data Reading\n"); + } else { + JD_I("Get Raw Data Finished\n"); + } +} + +static void jd_test_data_get(uint8_t *RAW, char *start_log, char *result, char *cnt_log, int now_item) +{ + uint32_t i; + int raw_data; + uint32_t index = 0; + ssize_t len = 0; + char *testdata = NULL; + uint32_t SZ_SIZE = JD_OUTPUT_BUFFER_SIZE; + int max_data, min_data; + + JD_D("%s: Entering, Now type=%s!\n", __func__, jd_action_item_name[now_item]); + + testdata = vmalloc(sizeof(char) * SZ_SIZE); + if (testdata == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + return; + } else { + memset(testdata, 0x00, sizeof(char) * SZ_SIZE); + } + + if (pjadard_ts_data->rawdata_little_endian) { + max_data = (((uint8_t)RAW[index + 1] << 8) | RAW[index]); + min_data = (((uint8_t)RAW[index + 1] << 8) | RAW[index]); + } else { + max_data = (((uint8_t)RAW[index] << 8) | RAW[index + 1]); + min_data = (((uint8_t)RAW[index] << 8) | RAW[index + 1]); + } + + len += scnprintf((testdata + len), SZ_SIZE - len, "%s", start_log); + for (i = 0; i < pjadard_ic_data->JD_Y_NUM*pjadard_ic_data->JD_X_NUM; i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)RAW[index + 1] << 8) | RAW[index]); + } else { + raw_data = (((uint8_t)RAW[index] << 8) | RAW[index + 1]); + } + + if (max_data < raw_data) { + max_data = raw_data; + } else if (min_data > raw_data) { + min_data = raw_data; + } + + #if (JD_PRODUCT_TYPE == 2) + if (i > 1 && ((i + 1) % pjadard_ic_data->JD_Y_NUM) == 0) { + len += scnprintf((testdata + len), SZ_SIZE - len, "%6d,\n", raw_data); + } else { + len += scnprintf((testdata + len), SZ_SIZE - len, "%6d,", raw_data); + } + #else + if (i > 1 && ((i + 1) % pjadard_ic_data->JD_Y_NUM) == 0) { + len += scnprintf((testdata + len), SZ_SIZE - len, "%5d,\n", raw_data); + } else { + len += scnprintf((testdata + len), SZ_SIZE - len, "%5d,", raw_data); + } + #endif + + index += 2; + } + len += scnprintf((testdata + len), SZ_SIZE - len, "%s", result); + len += scnprintf((testdata + len), SZ_SIZE - len, "%s%d%s%s%d\n", "Max: ", max_data, ", ", "Min: ", min_data); + len += scnprintf((testdata + len), SZ_SIZE - len, "%s", cnt_log); + + memcpy(jd_g_rslt_data + jd_g_rslt_data_len, testdata, len); + + /* dbg */ + /* for(i = 0; i < len; i++) + { + JD_I("0x%04X, ", jd_g_rslt_data[i + jd_g_rslt_data_len]); + if(i > 0 && (i % 16 == 15)) + printk("\n"); + } */ + + jd_g_rslt_data_len += len; + vfree(testdata); + JD_D("%s: End!\n", __func__); +} + +static uint32_t jadard_Item_Test_Function(uint8_t checktype) +{ + int i; + int raw_data; + uint32_t index = 0; + char *rslt_log = NULL; + char *start_log = NULL; + char *cnt_log = NULL; + int ret_val = JD_SORTING_OK; + int fail_data_cnt = 0; + + rslt_log = kzalloc(256 * sizeof(char), GFP_KERNEL); + if (rslt_log == NULL) { + JD_E("%s: rslt_log memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + start_log = kzalloc(256 * sizeof(char), GFP_KERNEL); + if (start_log == NULL) { + JD_E("%s: start_log memory alloc fail\n", __func__); + kfree(rslt_log); + return JD_MEM_ALLOC_FAIL; + } + + cnt_log = kzalloc(64 * sizeof(char), GFP_KERNEL); + if (cnt_log == NULL) { + JD_E("%s: cnt_log memory alloc fail\n", __func__); + kfree(rslt_log); + kfree(start_log); + return JD_MEM_ALLOC_FAIL; + } + + if (checktype >= JD_SORTING_OPEN_CHECK) { + if (checktype == JD_SORTING_OPEN_CHECK) { + snprintf(start_log, 256, "\nMP_Recb_Timeout = 0x%04x\n%s%s\n", MP_Recb_Timeout, + jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK], ": data as follow!\n"); + } else { + snprintf(start_log, 256, "\n%s%s\n", jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK], ": data as follow!\n"); + } + } + + switch (checktype) { + case JD_SORTING_OPEN_CHECK: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[0][i]) || (raw_data > jd_g_sorting_threshold[1][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: open check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_OPEN_CHECK_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_SHORT_CHECK: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[2][i]) || (raw_data > jd_g_sorting_threshold[3][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: short check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_SHORT_CHECK_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_NORMALACTIVE_SB_DEV: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[4][i]) || (raw_data > jd_g_sorting_threshold[5][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: Normal Active SB_DEV check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_NORMALACTIVE_SB_DEV_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_NORMALACTIVE_NOISE: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[6][i]) || (raw_data > jd_g_sorting_threshold[7][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: Normal Active noise check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_NORMALACTIVE_NOISE_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_NORMALIDLE_RAWDATA_CHECK: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[8][i]) || (raw_data > jd_g_sorting_threshold[9][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: Normal Idle Rawdata check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_NORMALIDLE_RAWDATA_CHECK_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_NORMALIDLE_NOISE: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[10][i]) || (raw_data > jd_g_sorting_threshold[11][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: Normal Idle noise check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_NORMALIDLE_NOISE_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_LPWUGACTIVE_SB_DEV: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[12][i]) || (raw_data > jd_g_sorting_threshold[13][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: LPWUG Active SB_DEV check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_LPWUGACTIVE_SB_DEV_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_LPWUGACTIVE_NOISE: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[14][i]) || (raw_data > jd_g_sorting_threshold[15][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: LPWUG Active noise check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_LPWUGACTIVE_NOISE_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_LPWUGIDLE_RAWDATA_CHECK: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[16][i]) || (raw_data > jd_g_sorting_threshold[17][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: LPWUG Idle Rawdata check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_LPWUGIDLE_RAWDATA_CHECK_ERR; + } + + index += 2; + } + break; + + case JD_SORTING_LPWUGIDLE_NOISE: + for (i = 0; i < (pjadard_ic_data->JD_Y_NUM * pjadard_ic_data->JD_X_NUM); i++) { + if (pjadard_ts_data->rawdata_little_endian) { + raw_data = (((uint8_t)GET_RAWDATA[index + 1] << 8) | GET_RAWDATA[index]); + } else { + raw_data = (((uint8_t)GET_RAWDATA[index] << 8) | GET_RAWDATA[index + 1]); + } + + if ((raw_data < jd_g_sorting_threshold[18][i]) || (raw_data > jd_g_sorting_threshold[19][i])) { + if (fail_data_cnt == 0) { + JD_E("%s: LPWUG Idle noise check FAIL\n", __func__); + } + fail_data_cnt++; + ret_val = JD_SORTING_LPWUGIDLE_NOISE_ERR; + } + + index += 2; + } + break; + + default: + JD_E("Wrong type=%d\n", checktype); + break; + } + + if (fail_data_cnt) { + scnprintf(rslt_log, 256, "\n%s%s\n", jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK], " Test Fail!"); + scnprintf(cnt_log, 64, "%s%d\n", "Fail_Data_Count: ", fail_data_cnt); + JD_I("%s Test Fail!\n", jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK]); + jd_g_json_len += scnprintf((jd_g_json_data + jd_g_json_len), JD_JASON_BUFFER_SIZE - jd_g_json_len, + "\"%s\":\"NG\",", jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK]); + } else { + JD_I("%s: %s PASS\n", __func__, jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK]); + scnprintf(rslt_log, 256, "\n%s%s\n", jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK], " Test Pass!"); + scnprintf(cnt_log, 64, "%s%d\n", "Fail_Data_Count: ", fail_data_cnt); + JD_I("%s Test Pass!\n", jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK]); + jd_g_json_len += scnprintf((jd_g_json_data + jd_g_json_len), JD_JASON_BUFFER_SIZE - jd_g_json_len, + "\"%s\":\"PASS\",", jd_action_item_name[checktype - JD_SORTING_OPEN_CHECK]); + } + + jd_test_data_get(GET_RAWDATA, start_log, rslt_log, cnt_log, checktype - JD_SORTING_OPEN_CHECK); + + if (start_log) { + kfree(start_log); + start_log = NULL; + } + + if (rslt_log) { + kfree(rslt_log); + rslt_log = NULL; + } + + if (cnt_log) { + kfree(cnt_log); + cnt_log = NULL; + } + + return ret_val; +} + +static uint32_t jadard_TestItem_Select(uint8_t sorting_item, bool retry_flag) +{ + SocReset_Flag = false; + + /* SoC reset before retry */ + if (retry_flag) + g_module_fp.fp_soft_reset(); + + switch (sorting_item) { + case JD_SORTING_SLEEP_IN: + #if (JD_PRODUCT_TYPE == 1) + jadard_pst_enter_slpin_mode_bymppw(); + mdelay(1000); + g_module_fp.fp_soft_reset(); + #else + jadard_pst_enter_slpin_mode(); + mdelay(1000); + #endif + break; + + case JD_SORTING_SLEEP_OUT: + #if (JD_PRODUCT_TYPE == 1) + jadard_pst_enter_slpout_mode_bymppw(); + #else + jadard_pst_enter_slpout_mode(); + #endif + mdelay(500); + break; + + case JD_SORTING_OPEN_CHECK: + jadard_PST_Open_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_RawData_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_RawData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_OPEN_CHECK) != JD_SORTING_OK) + return JD_SORTING_OPEN_CHECK_ERR; + break; + + case JD_SORTING_SHORT_CHECK: + jadard_PST_Short_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_RawData_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_RawData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_SHORT_CHECK) != JD_SORTING_OK) + return JD_SORTING_SHORT_CHECK_ERR; + break; + + case JD_SORTING_NORMALACTIVE_SB_DEV: + jadard_PST_NormalActive_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_RawData_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_RawData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_NORMALACTIVE_SB_DEV) != JD_SORTING_OK) + return JD_SORTING_NORMALACTIVE_SB_DEV_ERR; + break; + + case JD_SORTING_NORMALACTIVE_NOISE: + jadard_PST_NormalActive_Diff_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_Diff_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_DiffData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_NORMALACTIVE_NOISE) != JD_SORTING_OK) + return JD_SORTING_NORMALACTIVE_NOISE_ERR; + break; + + case JD_SORTING_NORMALIDLE_RAWDATA_CHECK: + jadard_PST_NormalIdle_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_RawData_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_RawData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_NORMALIDLE_RAWDATA_CHECK) != JD_SORTING_OK) + return JD_SORTING_NORMALIDLE_RAWDATA_CHECK_ERR; + break; + + case JD_SORTING_NORMALIDLE_NOISE: + jadard_PST_NormalIdle_Diff_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_Diff_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_DiffData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_NORMALIDLE_NOISE) != JD_SORTING_OK) + return JD_SORTING_NORMALIDLE_NOISE_ERR; + break; + + case JD_SORTING_LPWUGACTIVE_SB_DEV: + jadard_PST_LpwugActive_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_RawData_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_RawData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_LPWUGACTIVE_SB_DEV) != JD_SORTING_OK) + return JD_SORTING_LPWUGACTIVE_SB_DEV_ERR; + break; + + case JD_SORTING_LPWUGACTIVE_NOISE: + jadard_PST_LpwugActive_Diff_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_Diff_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_DiffData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_LPWUGACTIVE_NOISE) != JD_SORTING_OK) + return JD_SORTING_LPWUGACTIVE_NOISE_ERR; + break; + + case JD_SORTING_LPWUGIDLE_RAWDATA_CHECK: + jadard_PST_LpwugIdle_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_RawData_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_RawData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_LPWUGIDLE_RAWDATA_CHECK) != JD_SORTING_OK) + return JD_SORTING_LPWUGIDLE_RAWDATA_CHECK_ERR; + break; + + case JD_SORTING_LPWUGIDLE_NOISE: + jadard_PST_LpwugIdle_Diff_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_PST_Enter_Diff_Type_Mode(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + jadard_Start_to_Get_DiffData_Function(); + if (SocReset_Flag == true) { + if (retry_flag == false) { + return jadard_TestItem_Select(sorting_item, true); + } else { + Soc_Debug_Number++; + return JD_SORTING_SOC_ERR; + } + } + if (jadard_Item_Test_Function(JD_SORTING_LPWUGIDLE_NOISE) != JD_SORTING_OK) + return JD_SORTING_LPWUGIDLE_NOISE_ERR; + break; + + default: + break; + } + + return JD_SORTING_OK; +} + +static int jadard_power_cal(int pow, int number) +{ + int i = 0; + int result = 1; + + for (i = 0; i < pow; i++) + result *= 10; + result = result * number; + + return result; +} + +static int jadard_str2int(char *str) +{ + int i = 0; + int temp_cal = 0; + int result = 0; + int str_len = strlen(str); + int negtive_flag = 0; + + for (i = 0; i < strlen(str); i++) { + if (str[i] == '-') { + negtive_flag = 1; + continue; + } + temp_cal = str[i] - '0'; + result += jadard_power_cal(str_len - i - 1, temp_cal); + } + + if (negtive_flag == 1) { + result = 0 - result; + } + + return result; +} + +static int jadard_string_search(char *str1, char *str2) +{ + const char *cur; + const char *last; + int str1_len = strlen(str1); + int str2_len = strlen(str2) - 1; + int result = -1; + + last = str2 + str2_len - str1_len; + + for (cur = str2; cur <= last; ++cur) { + if (cur[0] == str1[0] && memcmp(cur, str1, str1_len) == 0) { + JD_D("%s: match item %s\n", __func__, str1); + return 0; + } + } + + return result; +} + +static int jadard_set_global_variable(char *str, int *val_parsed) +{ + int count = 0; + int comma_count = 0; + int i, item_num, var_val, var_len, *comma_position = NULL; + char value[5]; + + for (item_num = 0; item_num < JD_SORTING_ACTIVE_ITEM; item_num++) { + if (val_parsed[item_num]) { + continue; + } + + if (jadard_string_search(jd_action_item_name[item_num], str) == 0) { + comma_position = kzalloc(sizeof(int) * JD_COMMA_NUMBER, GFP_KERNEL); + if (comma_position == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + /* Find all comma's position */ + while (str[count] != ASCII_LF) { + if (str[count] == ASCII_COMMA) { + comma_position[comma_count++] = count; + } + count++; + } + + if (comma_count == JD_COMMA_NUMBER) { + var_len = comma_position[5] - comma_position[4] - 1; /* skip frame number char length */ + memset(value, 0x00, sizeof(value)); + for (i = 0; i < var_len; i++) + value[i] = str[comma_position[4] + 1 + i]; + var_val = jadard_str2int(value); + jd_pst_global_variable[item_num][0] = var_val; /* set skip frame number */ + JD_D("%s: Set skip frame number for item %s: %d\n", __func__, jd_action_item_name[item_num], var_val); + + var_len = count - comma_position[5] - 1; /* get frame number char length */ + memset(value, 0x00, sizeof(value)); + for (i = 0; i < var_len; i++) + value[i] = str[comma_position[5] + 1 + i]; + var_val = jadard_str2int(value); + jd_pst_global_variable[item_num][1] = var_val; /* set get frame number */ + JD_D("%s: Set get frame number for item %s: %d\n", __func__, jd_action_item_name[item_num], var_val); + + val_parsed[item_num] = 1; + } + + kfree(comma_position); + break; + } + } + + return 0; +} + +static int jadard_set_sorting_threshold(char **result, int data_lines) +{ + int err = JD_SORTING_OK; + int i, j, k, item_num, *th_parsed = NULL; + int count_type = -1; + int count_data = 0; +#if (JD_PRODUCT_TYPE == 2) + char data[6]; +#else + char data[5]; +#endif + bool item_found = false; + int count_size = pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM; + + th_parsed = kzalloc(sizeof(int) * JD_SORTING_ACTIVE_ITEM, GFP_KERNEL); + if (th_parsed == NULL) { + JD_E("%s: Memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + for (i = 0; i < data_lines; i++) { + if (!item_found) { + /* Sorting action name */ + for (item_num = 0; item_num < JD_SORTING_ACTIVE_ITEM; item_num++) { + if (th_parsed[item_num]) + continue; + + if (jadard_string_search(jd_action_item_name[item_num], result[i]) == 0) { + count_type = item_num; + count_data = 0; + item_found = true; + th_parsed[item_num] = 1; + break; + } + } + } else { + /* Sorting threshold */ + j = 0; + k = 0; + memset(data, 0x00, sizeof(data)); + + while (result[i][j] != ASCII_LF) { + if (result[i][j] == ACSII_COLON) { + /* Sorting min threshold */ + jd_g_sorting_threshold[count_type * 2][count_data] = jadard_str2int(data); + k = 0; + memset(data, 0x00, sizeof(data)); + } else if (result[i][j] == ASCII_COMMA) { + /* Sorting max threshold */ + jd_g_sorting_threshold[count_type * 2 + 1][count_data] = jadard_str2int(data); + k = 0; + count_data++; + memset(data, 0x00, sizeof(data)); + } else { + if (k < sizeof(data) - 1) { + /* Get threshold data */ + data[k++] = result[i][j]; + } else { + JD_E("data buffer was overflow!\n"); + break; + } + } + j++; + } + + if (count_data == count_size) + item_found = false; + else if ((count_data % pjadard_ic_data->JD_Y_NUM) != 0) { + JD_E("X/Y threshold number is not equal to %d/%d of driver\n", + pjadard_ic_data->JD_X_NUM, pjadard_ic_data->JD_Y_NUM); + err = JD_CHECK_DATA_ERROR; + break; + } + } + } + + for (item_num = 0; item_num < JD_SORTING_ACTIVE_ITEM; item_num++) { + if (!th_parsed[item_num]) { + jd_pst_global_variable[item_num][2] = 0; + JD_D("Sorting threshold not found for item %s(%d)\n", jd_action_item_name[item_num], jd_pst_global_variable[item_num][2]); + } else { + if (jd_pst_global_variable[item_num][2]) { + jd_pst_global_variable[item_num][2] = 1; + } else { + jd_pst_global_variable[item_num][2] = 0; + } + JD_D("Sorting threshold found item %s(%d)\n", jd_action_item_name[item_num], jd_pst_global_variable[item_num][2]); + } + } + kfree(th_parsed); + + return err; +} + +static int jadard_remove_space_cr(const struct firmware *file_entry, char **result, int data_lines, int line_max_len) +{ + int count = 0; + int str_count = 0; + int char_count = 0; + int item_num, *val_parsed = NULL; + char *temp_str = NULL; + bool keep_searching = true; + /* Search Keyword Setting */ + bool keyword_found = false; + char *start_keyword = "TestItem"; + char *end_keyword = "Threshold"; + + /* Search Global Variables: start */ + val_parsed = kzalloc(sizeof(int) * JD_SORTING_ACTIVE_ITEM, GFP_KERNEL); + if (val_parsed == NULL) { + JD_E("%s: val_parsed memory alloc fail\n", __func__); + return JD_MEM_ALLOC_FAIL; + } + + do { + if (!temp_str) { + temp_str = kzalloc(line_max_len * sizeof(char), GFP_KERNEL); + if (temp_str == NULL) { + JD_E("%s: temp_str memory alloc fail\n", __func__); + kfree(val_parsed); + return JD_MEM_ALLOC_FAIL; + } + } + + switch (file_entry->data[count]) { + case ASCII_CR: + case ACSII_SPACE: + count++; + break; + case ASCII_LF: + if (char_count != 0) { + temp_str[char_count] = ASCII_LF; + /* + * 1. If find end keyword, stop search global variables by break do-while loop. + * 2. If start keyword has been found in pervious line, keep to search global variables. + * 3. Try to find start keyword. If found it, start search global variables in next line. + */ + if (jadard_string_search(end_keyword, temp_str) == 0) + keep_searching = false; + else if (keyword_found) + jadard_set_global_variable(temp_str, val_parsed); + else if (jadard_string_search(start_keyword, temp_str) == 0) + keyword_found = true; + + kfree(temp_str); + temp_str = NULL; + char_count = 0; + } + count++; + break; + default: + temp_str[char_count++] = file_entry->data[count]; + count++; + break; + } + } while ((count < file_entry->size) && keep_searching); + + for (item_num = 0; item_num < JD_SORTING_ACTIVE_ITEM; item_num++) { + if (!val_parsed[item_num]) { + jd_pst_global_variable[item_num][2] = 0; + JD_D("Gloable variable not found for item %s\n", jd_action_item_name[item_num]); + } else { + jd_pst_global_variable[item_num][2] = 1; + JD_D("Gloable variable found for item %s\n", jd_action_item_name[item_num]); + } + } + kfree(val_parsed); + val_parsed = NULL; + /* Search Global Variables: end */ + + /* (Continue to parse file) */ + + /* Search Threshold: start */ + while ((count < file_entry->size) && (str_count < data_lines)) { + switch (file_entry->data[count]) { + case ASCII_CR: + case ACSII_SPACE: + count++; + break; + case ASCII_LF: + if (char_count != 0) { + result[str_count][char_count] = ASCII_LF; + char_count = 0; + str_count++; + } + count++; + break; + default: + result[str_count][char_count++] = file_entry->data[count]; + count++; + + /* Handle no newline characters */ + if (count == file_entry->size) { + if (char_count != 0) { + result[str_count][char_count] = ASCII_LF; + } + } + break; + } + } + /* Search Threshold: end */ + + return 0; +} + +static int jadard_parse_sorting_threshold_file(void) +{ + int err = JD_SORTING_OK, i; +#ifndef JD_SORTING_THRES_BUILT_IN + const struct firmware *file_entry = NULL; + char *file_name = "jd_sorting_threshold.txt"; +#else + struct firmware jd_file_entry; + struct firmware *file_entry = &jd_file_entry; + char *file_name = "jadard_sorting_threshold.h"; +#endif + char **result = NULL; + int data_lines = (pjadard_ic_data->JD_X_NUM + 1) * JD_SORTING_ACTIVE_ITEM; +#if (JD_PRODUCT_TYPE == 2) + int line_max_len = pjadard_ic_data->JD_Y_NUM * 14 + 4; +#else + int line_max_len = pjadard_ic_data->JD_Y_NUM * 12 + 4; +#endif + + JD_D("%s,Entering \n", __func__); + JD_I("sorting threshold file name = %s\n", file_name); + +#ifndef JD_SORTING_THRES_BUILT_IN + err = request_firmware(&file_entry, file_name, pjadard_ts_data->dev); + if (err < 0) { + JD_E("%s: Open file fail(err:%d)\n", __func__, err); + err = JD_FILE_OPEN_FAIL; + goto END_FILE_OPEN_FAIL; + } +#else + file_entry->data = jd_sorting_threshold; + file_entry->size = strlen(jd_sorting_threshold); +#endif + result = vmalloc(data_lines * sizeof(char *)); + if (result == NULL) { + JD_E("%s: result memory alloc fail\n", __func__); +#ifndef JD_SORTING_THRES_BUILT_IN + release_firmware(file_entry); +#endif + return JD_MEM_ALLOC_FAIL; + } else { + memset(result, 0x00, data_lines * sizeof(char *)); + } + + for (i = 0 ; i < data_lines; i++) { + result[i] = vmalloc(line_max_len * sizeof(char)); + if (result[i] == NULL) { + JD_E("%s: result[%d] memory alloc fail\n", __func__, i); + goto END_FUNC; + } else { + /* Set end character for strlen */ + memset(result[i], 0x00, line_max_len * sizeof(char)); + } + } + + JD_I("data_lines=%d ,line_max_len=%d\n", data_lines, line_max_len); + JD_I("file_size=%d\n", (int)file_entry->size); + + err = jadard_remove_space_cr(file_entry, result, data_lines, line_max_len); + if (err != JD_SORTING_OK) { + JD_E("%s: Find threshold section/global variables from file fail, go end!\n", __func__); + goto END_FUNC; + } + + err = jadard_set_sorting_threshold(result, data_lines); + if (err != JD_SORTING_OK) { + JD_E("%s: Load criteria from file fail, go end!\n", __func__); + goto END_FUNC; + } + +END_FUNC: + for (i = 0 ; i < data_lines; i++) { + if (result[i]) { + vfree(result[i]); + } + } + vfree(result); +#ifndef JD_SORTING_THRES_BUILT_IN + release_firmware(file_entry); + +END_FILE_OPEN_FAIL: +#endif + JD_I("%s end\n", __func__); + + return err; +} + +static char *get_date_time_str(void) +{ + struct timespec64 now_time; + struct rtc_time rtc_now_time; + static char time_data_buf[128] = { 0 }; + + ktime_get_ts64(&now_time); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) + rtc_time64_to_tm(now_time.tv_sec, &rtc_now_time); +#else + rtc_time_to_tm(now_time.tv_sec, &rtc_now_time); +#endif + scnprintf(time_data_buf, sizeof(time_data_buf), "%04d%02d%02d-%02d%02d%02d", + (rtc_now_time.tm_year + 1900), rtc_now_time.tm_mon + 1, + rtc_now_time.tm_mday, rtc_now_time.tm_hour, rtc_now_time.tm_min, + rtc_now_time.tm_sec); + + return time_data_buf; +} + +static int jadard_read_sorting_threshold(void) +{ + int ret = JD_SORTING_OK; + int i; +#if JD_SORTING_THRESHOLD_DBG + int j; +#endif + + JD_READ_THRESHOLD_SIZE = (JD_SORTING_ACTIVE_ITEM)*2; + + JD_I("JD_SORTING_ACTIVE_ITEM(%d) JD_READ_THRESHOLD_SIZE(%d)\n", JD_SORTING_ACTIVE_ITEM, JD_READ_THRESHOLD_SIZE); + + jd_g_sorting_threshold = vmalloc(sizeof(int *) * JD_READ_THRESHOLD_SIZE); + if (jd_g_sorting_threshold == NULL) { + JD_E("jd_g_sorting_threshold memory alloc fail\n"); + return JD_MEM_ALLOC_FAIL; + } else { + memset(jd_g_sorting_threshold, 0x00, sizeof(int *) * JD_READ_THRESHOLD_SIZE); + } + + for (i = 0; i < JD_READ_THRESHOLD_SIZE; i++) { + jd_g_sorting_threshold[i] = vmalloc(sizeof(int) * (pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM)); + if (jd_g_sorting_threshold[i] == NULL) { + JD_E("jd_g_sorting_threshold[%d] memory alloc fail\n", i); + return JD_MEM_ALLOC_FAIL; + } else { + memset(jd_g_sorting_threshold[i], 0x00, sizeof(int) * (pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM)); + } + } + ret = jadard_parse_sorting_threshold_file(); + + jd_g_json_data = vmalloc(JD_JASON_BUFFER_SIZE * sizeof(char)); + if (jd_g_json_data == NULL) { + JD_E("jd_g_json_data memory alloc fail\n"); + return JD_MEM_ALLOC_FAIL; + } else { + memset(jd_g_json_data, 0x00, JD_JASON_BUFFER_SIZE * sizeof(char)); + jd_g_json_len = 0; + } + + jd_g_file_path = vmalloc(64 * sizeof(char)); + if (jd_g_file_path == NULL) { + JD_E("jd_g_file_path memory alloc fail\n"); + return JD_MEM_ALLOC_FAIL; + } else { + memset(jd_g_file_path, 0x00, 64 * sizeof(char)); + } + + jd_g_rslt_data = vmalloc(JD_OUTPUT_BUFFER_SIZE * JD_SORTING_ACTIVE_ITEM * sizeof(char)); + if (jd_g_rslt_data == NULL) { + JD_E("jd_g_rslt_data memory alloc fail\n"); + return JD_MEM_ALLOC_FAIL; + } else { + memset(jd_g_rslt_data, 0x00, JD_OUTPUT_BUFFER_SIZE * JD_SORTING_ACTIVE_ITEM * sizeof(char)); + jd_g_rslt_data_len = 0; + } + + GET_RAWDATA = vmalloc(pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM * sizeof(uint16_t)); + if (GET_RAWDATA == NULL) { + JD_E("GET_RAWDATA memory alloc fail\n"); + return JD_MEM_ALLOC_FAIL; + } else { + memset(GET_RAWDATA, 0x00, pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM * sizeof(uint16_t)); + } + + scnprintf(jd_g_file_path, 64, "%s%s%s", JD_RSLT_OUT_PATH, JD_RSLT_OUT_FILE, get_date_time_str()); + +#if JD_SORTING_THRESHOLD_DBG + for (i = 0; i < JD_READ_THRESHOLD_SIZE; i = i + 2) { + JD_I("[%d]", i); + for (j = 0; j < pjadard_ic_data->JD_X_NUM * pjadard_ic_data->JD_Y_NUM; j++) { + if (j % pjadard_ic_data->JD_Y_NUM == 0) { + JD_I("\n"); + } else { + JD_I("%d:%d ", jd_g_sorting_threshold[i][j], jd_g_sorting_threshold[i + 1][j]); + } + } + } +#endif + + return ret; +} + +static int jadard_sorting_test(char *json_buf, size_t len) +{ + uint32_t ret = JD_SORTING_OK; + bool res = false; + +#ifdef JD_UPGRADE_ITO_FW + uint32_t fw_ret = 0; + char *fileName = "Jadard_ito_firmware.bin"; +#ifndef JD_ZERO_FLASH + const struct firmware *fw = NULL; +#endif +#endif + + JD_I("%s: enter\n", __func__); + + if (pjadard_ts_data->fw_ready == false) { + JD_E("%s: FW was not ready, can`t running ITO test\n", __func__); + return JD_SORTING_UPGRADE_FW_ERR; + } + + pjadard_ts_data->ito_sorting_active = true; + mutex_lock(&(pjadard_ts_data->sorting_active)); + /* Disable ATTN */ + jadard_int_enable(false); + +#ifdef JD_ESD_CHECK + if (pjadard_ts_data->esd_check_running == true) { + JD_I("Stop esd check in ITO\n"); + pjadard_ts_data->esd_check_running = false; + cancel_delayed_work_sync(&pjadard_ts_data->work_esd_check); + } +#endif + +#ifdef JD_UPGRADE_ITO_FW + JD_I("%s: Bin file name(%s)\n", __func__, fileName); + +#ifdef JD_ZERO_FLASH + JD_I("Running Zero flash upgrade\n"); + + fw_ret = g_module_fp.fp_0f_upgrade_fw(fileName); + if (fw_ret < 0) { + JD_E("Zero flash upgrade fail\n"); + jadard_int_enable(true); + mutex_unlock(&(pjadard_ts_data->sorting_active)); + pjadard_ts_data->ito_sorting_active = false; + return JD_SORTING_UPGRADE_FW_ERR; + } else { + JD_I("Zero flash upgrade success\n"); + } +#else + JD_I("Running flash upgrade\n"); + + fw_ret = request_firmware(&fw, fileName, pjadard_ts_data->dev); + if (fw_ret < 0) { + JD_E("Fail to open file: %s (fw_ret: %d)\n", fileName, fw_ret); + jadard_int_enable(true); + mutex_unlock(&(pjadard_ts_data->sorting_active)); + pjadard_ts_data->ito_sorting_active = false; + return JD_SORTING_UPGRADE_FW_ERR; + } + + JD_I("ITO FW size is %d Bytes\n", (int)fw->size); + + if (g_module_fp.fp_flash_write(0, (uint8_t *)fw->data, fw->size) < 0) { + JD_E("%s: TP upgrade fail\n", __func__); + release_firmware(fw); + jadard_int_enable(true); + mutex_unlock(&(pjadard_ts_data->sorting_active)); + pjadard_ts_data->ito_sorting_active = false; + return JD_SORTING_UPGRADE_FW_ERR; + } else { + JD_I("%s: TP upgrade success\n", __func__); + } + + release_firmware(fw); +#endif + + g_module_fp.fp_read_fw_ver(); +#endif + + /* START ReCB */ + g_module_fp.fp_PorInit(); +#if (JD_PRODUCT_TYPE == 2) + g_module_fp.fp_soft_reset(); + msleep(800); /* 6*4*2*16.6=796.8 */ +#else + g_module_fp.fp_ResetMCU(); + msleep(300); /* 4*4*1*16.6=265.6 */ +#endif + /* END ReCB */ + g_module_fp.fp_Fw_DBIC_Off(); + Soc_Debug_Number = 0; + + ret = jadard_read_sorting_threshold(); + if (ret != JD_SORTING_OK) { + JD_E("jadard_read_sorting_threshold fail!\n"); + goto END_SORTING_TEST; + } + +#if (JD_PRODUCT_TYPE == 1) + g_module_fp.fp_SetMpBypassMain(); +#endif + +#if JD_SORTING_LPWUG_CHECK + /* 0.Sleep in/out */ + JD_I("[JD_SORTING_SLEEP_IN]\n"); + ret += jadard_TestItem_Select(JD_SORTING_SLEEP_IN, false); + JD_I("JD_SORTING_SLEEP_IN: End %d\n\n", ret); + + JD_I("[JD_SORTING_SLEEP_OUT]\n"); + ret += jadard_TestItem_Select(JD_SORTING_SLEEP_OUT, false); + JD_I("JD_SORTING_SLEEP_OUT: End %d\n\n", ret); +#endif + + if (jd_pst_global_variable[0][2] == 1) { + /* 1.Open Test */ + JD_I("[JD_SORTING_OPEN_CHECK]\n"); + ret += jadard_TestItem_Select(JD_SORTING_OPEN_CHECK, false); + JD_I("JD_SORTING_OPEN_CHECK: End %d\n\n", ret); + } + + if (jd_pst_global_variable[1][2] == 1) { + /* 2. Short Test */ + JD_I("[JD_SORTING_SHORT_CHECK]\n"); + ret += jadard_TestItem_Select(JD_SORTING_SHORT_CHECK, false); + JD_I("JD_SORTING_SHORT_CHECK: End %d\n\n", ret); + } + + if (jd_pst_global_variable[2][2] == 1) { + /* 3. NORMAL ACTIVE SB_DEV Test */ + JD_I("[JD_SORTING_NORMALACTIVE_SB_DEV]\n"); + ret += jadard_TestItem_Select(JD_SORTING_NORMALACTIVE_SB_DEV, false); + JD_I("JD_SORTING_NORMALACTIVE_SB_DEV: End %d\n\n", ret); + } + + if (jd_pst_global_variable[3][2] == 1) { + /* 4. NORMAL ACTIVE NOISE Test */ + JD_I("[JD_SORTING_NORMALACTIVE_NOISE]\n"); + ret += jadard_TestItem_Select(JD_SORTING_NORMALACTIVE_NOISE, false); + JD_I("JD_SORTING_NORMALACTIVE_NOISE: End %d\n\n", ret); + } + + if (jd_pst_global_variable[4][2] == 1) { + /* 5. NORMAL IDLE RAWDATA CHECK Test */ + JD_I("[JD_SORTING_NORMALIDLE_RAWDATA_CHECK]\n"); + ret += jadard_TestItem_Select(JD_SORTING_NORMALIDLE_RAWDATA_CHECK, false); + JD_I("JD_SORTING_NORMALIDLE_RAWDATA_CHECK: End %d\n\n", ret); + } + + if (jd_pst_global_variable[5][2] == 1) { + /* 6. NORMAL IDLE NOISE Test */ + JD_I("[JD_SORTING_NORMALIDLE_NOISE]\n"); + ret += jadard_TestItem_Select(JD_SORTING_NORMALIDLE_NOISE, false); + JD_I("JD_SORTING_NORMALIDLE_NOISE: End %d\n\n", ret); + } + +#if JD_SORTING_LPWUG_CHECK + if (jd_pst_global_variable[6][2] == 1) { + /* 7. LPWUG ACTIVE SB_DEV Test */ + JD_I("[JD_SORTING_LPWUGACTIVE_SB_DEV]\n"); + ret += jadard_TestItem_Select(JD_SORTING_LPWUGACTIVE_SB_DEV, false); + JD_I("JD_SORTING_LPWUGACTIVE_SB_DEV: End %d\n\n", ret); + } + + if (jd_pst_global_variable[7][2] == 1) { + /* 8. LPWUG ACTIVE NOISE Test */ + JD_I("[JD_SORTING_LPWUGACTIVE_NOISE]\n"); + ret += jadard_TestItem_Select(JD_SORTING_LPWUGACTIVE_NOISE, false); + JD_I("JD_SORTING_LPWUGACTIVE_NOISE: End %d\n\n", ret); + } + + if (jd_pst_global_variable[8][2] == 1) { + /* 9. LPWUG IDLE RAWDATA CHECK Test */ + JD_I("[JD_SORTING_LPWUGIDLE_RAWDATA_CHECK]\n"); + ret += jadard_TestItem_Select(JD_SORTING_LPWUGIDLE_RAWDATA_CHECK, false); + JD_I("JD_SORTING_LPWUGIDLE_RAWDATA_CHECK: End %d\n\n", ret); + } + + if (jd_pst_global_variable[9][2] == 1) { + /* 10. LPWUG IDLE NOISE Test */ + JD_I("[JD_SORTING_LPWUGIDLE_NOISE]\n"); + ret += jadard_TestItem_Select(JD_SORTING_LPWUGIDLE_NOISE, false); + JD_I("JD_SORTING_LPWUGIDLE_NOISE: End %d\n\n", ret); + } +#endif + + jd_test_data_pop_out(jd_g_rslt_data, jd_g_file_path, ret); + +#if (JD_PRODUCT_TYPE == 1) + g_module_fp.fp_ClearMpBypassMain(); +#endif + + /* Enter normal mode */ + jadard_pst_enter_normal_mode(); +#if (JD_PRODUCT_TYPE == 2) + g_module_fp.fp_PorInit(); +#endif + g_module_fp.fp_soft_reset(); +#if (JD_PRODUCT_TYPE == 2) + /* Unnecessary start mcu */ +#else + g_module_fp.fp_StartMCU(); +#endif + +END_SORTING_TEST: + if (jd_g_json_data && (jd_g_json_len > 1)) { + /* Clear last comma(,) */ + jd_g_json_data[jd_g_json_len - 1] = 0x00; + scnprintf(json_buf, len, "{\"result\":\"%s\",%s}\n", ret ? "NG" : "PASS", jd_g_json_data); + } else { + scnprintf(json_buf, len, "{\"result\":\"NG\"}\n"); + } + + jadard_sorting_data_deinit(); + + JD_I("Sorting test result = %d \n", ret); + + res = (ret != 0); +#if defined(CONFIG_TOUCHSCREEN_JADARD_DEBUG) + res |= (jd_g_dbg_enable && (Soc_Debug_Number >= 6)); + JD_D("SoC debug result = %d \n", Soc_Debug_Number); +#endif + if (res) { + /* Return fail */ + ret = 1; + } + + JD_I("%s:OUT\n", __func__); + g_module_fp.fp_Fw_DBIC_On(); + +#ifdef JD_UPGRADE_ITO_FW + fileName = "Jadard_firmware.bin"; + JD_I("%s: Bin file name(%s)\n", __func__, fileName); + +#ifdef JD_ZERO_FLASH + JD_I("Running Zero flash upgrade\n"); + + fw_ret = g_module_fp.fp_0f_upgrade_fw(fileName); + if (fw_ret < 0) { + JD_E("Zero flash upgrade fail\n"); + jadard_int_enable(true); + mutex_unlock(&(pjadard_ts_data->sorting_active)); + pjadard_ts_data->ito_sorting_active = false; + return JD_SORTING_UPGRADE_FW_ERR; + } else { + JD_I("Zero flash upgrade success\n"); + } +#else + JD_I("Running flash upgrade\n"); + + fw_ret = request_firmware(&fw, fileName, pjadard_ts_data->dev); + if (fw_ret < 0) { + JD_E("Fail to open file: %s (fw_ret: %d)\n", fileName, fw_ret); + jadard_int_enable(true); + mutex_unlock(&(pjadard_ts_data->sorting_active)); + pjadard_ts_data->ito_sorting_active = false; + return JD_SORTING_UPGRADE_FW_ERR; + } + + JD_I("FW size is %d Bytes\n", (int)fw->size); + + if (g_module_fp.fp_flash_write(0, (uint8_t *)fw->data, fw->size) < 0) { + JD_E("%s: TP upgrade fail\n", __func__); + release_firmware(fw); + jadard_int_enable(true); + mutex_unlock(&(pjadard_ts_data->sorting_active)); + pjadard_ts_data->ito_sorting_active = false; + return JD_SORTING_UPGRADE_FW_ERR; + } else { + JD_I("%s: TP upgrade success\n", __func__); + } + + release_firmware(fw); +#endif + + g_module_fp.fp_read_fw_ver(); +#endif + +#ifdef JD_ESD_CHECK + if (pjadard_ts_data->esd_check_running == false) { + JD_I("Start esd check on ITO\n"); + pjadard_ts_data->esd_check_running = true; + queue_delayed_work(pjadard_ts_data->jadard_esd_check_wq, &pjadard_ts_data->work_esd_check, 0); + } +#endif + + /* Enable ATTN */ + jadard_int_enable(true); + mutex_unlock(&(pjadard_ts_data->sorting_active)); + pjadard_ts_data->ito_sorting_active = false; + + return ret; +} + +void jadard_sorting_init(void) +{ + JD_I("%s: enter \n", __func__); + mutex_init(&(pjadard_ts_data->sorting_active)); + g_module_fp.fp_sorting_test = jadard_sorting_test; +} + +#ifndef CONFIG_JD_DB +MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); +MODULE_IMPORT_NS(ANDROID_GKI_VFS_EXPORT_ONLY); +#endif diff --git a/drivers/input/touchscreen/jdchipset/jadard_sorting.h b/drivers/input/touchscreen/jdchipset/jadard_sorting.h new file mode 100644 index 0000000000000..52e8530df32fb --- /dev/null +++ b/drivers/input/touchscreen/jdchipset/jadard_sorting.h @@ -0,0 +1,168 @@ +#ifndef JADARD_SORTING_H +#define JADARD_SORTING_H + +#include "jadard_common.h" +#include "jadard_module.h" +#include + +#ifdef JD_SORTING_THRES_BUILT_IN +#include "jadard_sorting_threshold.h" +#endif + +#define JD_RSLT_OUT_PATH "/sdcard/" +#define JD_RSLT_OUT_FILE "jd_sorting_result_" + +#if (JD_PRODUCT_TYPE == 1) +#define JD_OUTPUT_BUFFER_SIZE 0x2300 +#elif (JD_PRODUCT_TYPE == 2) +#define JD_OUTPUT_BUFFER_SIZE 0x2D00 +#else +#define JD_OUTPUT_BUFFER_SIZE 0x1000 +#endif + +static char *jd_g_file_path; +static char *jd_g_rslt_data; +static char *jd_g_json_data; +static size_t jd_g_json_len; + +#define JD_JASON_BUFFER_SIZE (492) +#define JD_SORTING_ACTIVE_ITEM 10 +#define JD_COMMA_NUMBER 6 +static int JD_READ_THRESHOLD_SIZE; +static int **jd_g_sorting_threshold; +static uint8_t *GET_RAWDATA; + +/* ASCII number */ +#define ASCII_LF (0x0A) +#define ASCII_CR (0x0D) +#define ASCII_COMMA (0x2C) +#define ACSII_SPACE (0x20) +#define ACSII_COLON (0x3A) + +/* Sorting config */ +#define JD_SORTING_THRESHOLD_DBG 0 +#define JD_SORTING_NOISE_DIFF_MIN 0 +#define JD_SORTING_LPWUG_CHECK 0 + +char *jd_action_item_name[] = { + "Open_Check", + "Short_Check", + "NormalActive_SB_Dev", + "NormalActive_Noise", + "NormalIdle_RawData_Check", + "NormalIdle_Noise", + "LpwugActive_SB_Dev", + "LpwugActive_Noise", + "LpwugIdle_RawData_Check", + "LpwugIdle_Noise", +}; + +enum JD_SORTING_ACTION_ITEM { + JD_SORTING_SLEEP_IN = 0, + JD_SORTING_SLEEP_OUT, + JD_SORTING_OPEN_CHECK, + JD_SORTING_SHORT_CHECK, + JD_SORTING_NORMALACTIVE_SB_DEV, + JD_SORTING_NORMALACTIVE_NOISE, + JD_SORTING_NORMALIDLE_RAWDATA_CHECK, + JD_SORTING_NORMALIDLE_NOISE, + JD_SORTING_LPWUGACTIVE_SB_DEV, + JD_SORTING_LPWUGACTIVE_NOISE, + JD_SORTING_LPWUGIDLE_RAWDATA_CHECK, + JD_SORTING_LPWUGIDLE_NOISE, +}; + +enum JD_SORTING_ERROR_STATUS { + JD_SORTING_SOC_ERR = 0, + JD_SORTING_OK = 0, + JD_SORTING_SLEEP_IN_ERR = 1, + JD_SORTING_SLEEP_OUT_ERR = 1 << 1, + JD_SORTING_OPEN_CHECK_ERR = 1 << 2, + JD_SORTING_SHORT_CHECK_ERR = 1 << 3, + JD_SORTING_NORMALACTIVE_SB_DEV_ERR = 1 << 4, + JD_SORTING_NORMALACTIVE_NOISE_ERR = 1 << 5, + JD_SORTING_NORMALIDLE_RAWDATA_CHECK_ERR = 1 << 6, + JD_SORTING_NORMALIDLE_NOISE_ERR = 1 << 7, + JD_SORTING_LPWUGACTIVE_SB_DEV_ERR = 1 << 8, + JD_SORTING_LPWUGACTIVE_NOISE_ERR = 1 << 9, + JD_SORTING_LPWUGIDLE_RAWDATA_CHECK_ERR = 1 << 10, + JD_SORTING_LPWUGIDLE_NOISE_ERR = 1 << 11, + JD_SORTING_UPGRADE_FW_ERR = 1 << 12, +}; + +enum JD_MPAP_PW { + JD_MPAP_PW_NORMAL_ACTIVE_hbyte = 0xFF, + JD_MPAP_PW_NORMAL_ACTIVE_lbyte = 0xFF, + JD_MPAP_PW_MP_SORTING_FINISH_hbyte = 0x03, + JD_MPAP_PW_MP_SORTING_FINISH_lbyte = 0x01, + JD_MPAP_PW_MP_SHORT_START_hbyte = 0x04, + JD_MPAP_PW_MP_SHORT_START_lbyte = 0x01, + JD_MPAP_PW_MP_SHORT_FINISH_hbyte = 0x06, + JD_MPAP_PW_MP_SHORT_FINISH_lbyte = 0x01, + JD_MPAP_PW_MP_OPEN_START_hbyte = 0x07, + JD_MPAP_PW_MP_OPEN_START_lbyte = 0x01, + JD_MPAP_PW_MP_OPEN_FINISH_hbyte = 0x09, + JD_MPAP_PW_MP_OPEN_FINISH_lbyte = 0x01, + JD_MPAP_PW_MP_NORMAL_ACTIVE_START_hbyte = 0x0A, + JD_MPAP_PW_MP_NORMAL_ACTIVE_START_lbyte = 0x01, + JD_MPAP_PW_MP_NORMAL_ACTIVE_FINISH_hbyte = 0x0C, + JD_MPAP_PW_MP_NORMAL_ACTIVE_FINISH_lbyte = 0x01, + JD_MPAP_PW_MP_NORMAL_IDLE_START_hbyte = 0x0D, + JD_MPAP_PW_MP_NORMAL_IDLE_START_lbyte = 0x01, + JD_MPAP_PW_MP_NORMAL_IDLE_FINISH_hbyte = 0x0F, + JD_MPAP_PW_MP_NORMAL_IDLE_FINISH_lbyte = 0x01, + JD_MPAP_PW_MP_NORMAL_ACTIVE_DIFF_START_hbyte = 0x11, + JD_MPAP_PW_MP_NORMAL_ACTIVE_DIFF_START_lbyte = 0x01, + JD_MPAP_PW_MP_NORMAL_ACTIVE_DIFF_FINISH_hbyte = 0x13, + JD_MPAP_PW_MP_NORMAL_ACTIVE_DIFF_FINISH_lbyte = 0x01, + JD_MPAP_PW_MP_NORMAL_IDLE_DIFF_START_hbyte = 0x14, + JD_MPAP_PW_MP_NORMAL_IDLE_DIFF_START_lbyte = 0x01, + JD_MPAP_PW_MP_NORMAL_IDLE_DIFF_FINISH_hbyte = 0x16, + JD_MPAP_PW_MP_NORMAL_IDLE_DIFF_FINISH_lbyte = 0x01, + JD_MPAP_PW_MP_LPWUG_ACTIVE_START_hbyte = 0x01, + JD_MPAP_PW_MP_LPWUG_ACTIVE_START_lbyte = 0x02, + JD_MPAP_PW_MP_LPWUG_ACTIVE_FINISH_hbyte = 0x03, + JD_MPAP_PW_MP_LPWUG_ACTIVE_FINISH_lbyte = 0x02, + JD_MPAP_PW_MP_LPWUG_IDLE_START_hbyte = 0x04, + JD_MPAP_PW_MP_LPWUG_IDLE_START_lbyte = 0x02, + JD_MPAP_PW_MP_LPWUG_IDLE_FINISH_hbyte = 0x06, + JD_MPAP_PW_MP_LPWUG_IDLE_FINISH_lbyte = 0x02, + JD_MPAP_PW_MP_LPWUG_ACTIVE_DIFF_START_hbyte = 0x07, + JD_MPAP_PW_MP_LPWUG_ACTIVE_DIFF_START_lbyte = 0x02, + JD_MPAP_PW_MP_LPWUG_ACTIVE_DIFF_FINISH_hbyte = 0x09, + JD_MPAP_PW_MP_LPWUG_ACTIVE_DIFF_FINISH_lbyte = 0x02, + JD_MPAP_PW_MP_LPWUG_IDLE_DIFF_START_hbyte = 0x0A, + JD_MPAP_PW_MP_LPWUG_IDLE_DIFF_START_lbyte = 0x02, + JD_MPAP_PW_MP_LPWUG_IDLE_DIFF_FINISH_hbyte = 0x0C, + JD_MPAP_PW_MP_LPWUG_IDLE_DIFF_FINISH_lbyte = 0x02, +}; + +enum JD_PST_MP_Mode { + JD_PST_MP_Mode_Null = 0, + JD_PST_MP_Mode_Sorting, + JD_PST_MP_Mode_MP_Normal_Active, + JD_PST_MP_Mode_MP_Normal_Active_Diff, + JD_PST_MP_Mode_MP_Normal_Idle, + JD_PST_MP_Mode_MP_Normal_Idle_Diff, + JD_PST_MP_Mode_MP_LPWUG_Active, + JD_PST_MP_Mode_MP_LPWUG_Active_Diff, + JD_PST_MP_Mode_MP_LPWUG_Idle, + JD_PST_MP_Mode_MP_LPWUG_Idle_Diff, + JD_PST_MP_Mode_Short, + JD_PST_MP_Mode_Open, +}; + +enum JD_MPAP_HANDSHAKE { + JD_MPAP_HANDSHAKE_BUSY = 0x11, + JD_MPAP_HANDSHAKE_FINISH = 0x22, +}; + +enum JD_SLEEP_MODE_PASSWORD { + JD_MPAP_PW_SLEEP_IN_hbyte = 0x01, + JD_MPAP_PW_SLEEP_IN_lbyte = 0xFE, + + JD_MPAP_PW_SLEEP_OUT_hbyte = 0x01, + JD_MPAP_PW_SLEEP_OUT_lbyte = 0xFF, +}; + +#endif diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index a8682db8a4116..2b08cf88f705d 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "leds.h" struct gpio_led_data { @@ -23,6 +24,9 @@ struct gpio_led_data { struct gpio_desc *gpiod; u8 can_sleep; u8 blinking; + u8 pending_initial_on; + unsigned int initial_on_delay_ms; + struct delayed_work initial_on_work; gpio_blink_set_t platform_gpio_blink_set; }; @@ -38,6 +42,9 @@ static void gpio_led_set(struct led_classdev *led_cdev, struct gpio_led_data *led_dat = cdev_to_gpio_led_data(led_cdev); int level; + if (led_dat->pending_initial_on) + return; + if (value == LED_OFF) level = 0; else @@ -62,11 +69,43 @@ static int gpio_led_set_blocking(struct led_classdev *led_cdev, return 0; } +static void gpio_led_initial_on_work(struct work_struct *work) +{ + struct gpio_led_data *led_dat = container_of(to_delayed_work(work), + struct gpio_led_data, initial_on_work); + + mutex_lock(&led_dat->cdev.led_access); + + if (!led_dat->pending_initial_on) + goto unlock; + + led_dat->pending_initial_on = 0; + led_dat->cdev.brightness = led_dat->cdev.max_brightness; + gpio_led_set(&led_dat->cdev, led_dat->cdev.brightness); + +unlock: + mutex_unlock(&led_dat->cdev.led_access); +} + +static void gpio_led_cancel_initial_on_work(void *data) +{ + struct gpio_led_data *led_dat = data; + + if (!led_dat->pending_initial_on) + return; + + cancel_delayed_work_sync(&led_dat->initial_on_work); + led_dat->pending_initial_on = 0; +} + static int gpio_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { struct gpio_led_data *led_dat = cdev_to_gpio_led_data(led_cdev); + if (led_dat->pending_initial_on) + return 0; + led_dat->blinking = 1; return led_dat->platform_gpio_blink_set(led_dat->gpiod, GPIO_LED_BLINK, delay_on, delay_off); @@ -109,6 +148,12 @@ static int create_gpio_led(const struct gpio_led *template, led_dat->platform_gpio_blink_set = blink_set; led_dat->cdev.blink_set = gpio_blink_set; } + + led_dat->initial_on_delay_ms = 0; + if (fwnode) + fwnode_property_read_u32(fwnode, "initial-on-delay-ms", + &led_dat->initial_on_delay_ms); + if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP) { state = gpiod_get_value_cansleep(led_dat->gpiod); if (state < 0) @@ -116,7 +161,15 @@ static int create_gpio_led(const struct gpio_led *template, } else { state = (template->default_state == LEDS_GPIO_DEFSTATE_ON); } - led_dat->cdev.brightness = state; + if (led_dat->initial_on_delay_ms && state) { + led_dat->pending_initial_on = 1; + led_dat->cdev.brightness = LED_OFF; + state = 0; + } else { + led_dat->pending_initial_on = 0; + led_dat->cdev.brightness = state; + } + led_dat->cdev.max_brightness = 1; if (!template->retain_state_suspended) led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; @@ -138,6 +191,20 @@ static int create_gpio_led(const struct gpio_led *template, &init_data); } + if (ret < 0) + return ret; + + if (led_dat->pending_initial_on) { + INIT_DELAYED_WORK(&led_dat->initial_on_work, gpio_led_initial_on_work); + ret = devm_add_action_or_reset(parent, gpio_led_cancel_initial_on_work, + led_dat); + if (ret) + return ret; + + schedule_delayed_work(&led_dat->initial_on_work, + msecs_to_jiffies(led_dat->initial_on_delay_ms)); + } + return ret; } @@ -327,6 +394,8 @@ static void gpio_led_shutdown(struct platform_device *pdev) for (i = 0; i < priv->num_leds; i++) { struct gpio_led_data *led = &priv->leds[i]; + gpio_led_cancel_initial_on_work(led); + if (!(led->cdev.flags & LED_RETAIN_AT_SHUTDOWN)) gpio_led_set(&led->cdev, LED_OFF); } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 38afdd0111a2b..6d30183b9eb7b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -50,6 +50,9 @@ #include "dwxgmac2.h" #include "hwif.h" +#define MAXIO_PHY_MAE0621A_Q2C_ID 0x7b744411 +#define MAXIO_PHY_MAE0621A_Q3C_ID 0x7b744412 + /* As long as the interface is active, we keep the timestamping counter enabled * with fine resolution and binary rollover. This avoid non-monotonic behavior * (clock jumps) when changing timestamping settings at runtime. @@ -7732,6 +7735,16 @@ int stmmac_resume(struct device *dev) stmmac_free_tx_skbufs(priv); stmmac_clear_descriptors(priv, &priv->dma_conf); + /* + * Provide RX CLK for Rockchip's DWMAC otherwise the controller will + * fail to initialize with "DMA engine initialization failed". + */ + if (ndev->phydev->drv->config_init) { + if (ndev->phydev->phy_id == MAXIO_PHY_MAE0621A_Q2C_ID || + ndev->phydev->phy_id == MAXIO_PHY_MAE0621A_Q3C_ID) + ndev->phydev->drv->config_init(ndev->phydev); + } + stmmac_hw_setup(ndev, false); stmmac_init_coalesce(priv); stmmac_set_rx_mode(ndev); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index c601cdc5c4220..18a73be640682 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -219,6 +219,11 @@ config MARVELL_88X2222_PHY Support for the Marvell 88X2222 Dual-port Multi-speed Ethernet Transceiver. +config MAXIO_PHY + tristate "Maxio Ethernet PHYs" + help + Support for the Maxio MAExxxx Ethernet PHYs + config MAXLINEAR_GPHY tristate "Maxlinear Ethernet PHYs" select POLYNOMIAL if HWMON diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 161e54a9fe460..692371d9fc569 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_LXT_PHY) += lxt.o obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o obj-$(CONFIG_MARVELL_PHY) += marvell.o obj-$(CONFIG_MARVELL_88X2222_PHY) += marvell-88x2222.o +obj-$(CONFIG_MAXIO_PHY) += maxio.o obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o diff --git a/drivers/net/phy/maxio.c b/drivers/net/phy/maxio.c new file mode 100644 index 0000000000000..540d63c626c82 --- /dev/null +++ b/drivers/net/phy/maxio.c @@ -0,0 +1,436 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* drivers/net/phy/maxio.c + * + * Driver for Maxio PHYs + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Source from https://github.com/zuyih/linux-cubie/blob/c5ea47e5f899042abe54437ced1fd49ac1226582/drivers/net/phy/maxio.c, + * with minor modifications. + */ +#define MAXIO_PHY_VER "v1.8.1.13-dirty" +#define MAXIO_PAGE_SELECT 0x1f +#define MAXIO_MAE0621A_WORK_STATUS_REG 0x1d +#define MAXIO_MAE0621A_CLK_MODE_REG 0x02 + +#define MAXIO_PHYSR_P_A43 (0X1A) +#define MAXIO_PHY_LINK (1<<2) +#define MAXIO_PHY_DUPLEX (1<<3) +#define MAXIO_PHY_SPEED (3<<4) +#define MAXIO_PHY_1000M (0X20) +#define MAXIO_PHY_100M (0X10) +#define MAXIO_PHY_10M (0X00) + +#define AUTONEG_COMPLETED_INT_EN (0x8) +#define LINKOK (0x4) +#define AUTONEG_COMPLETED (0x8) + +#define PHY_READ(a,b) phy_read((a),(b)) +#define PHY_WRITE(a,b,c) phy_write((a),(b),(c)) + +int maxio_read_paged(struct phy_device *phydev, int page, u32 regnum) +{ + int ret = 0, oldpage; + + oldpage = PHY_READ(phydev, MAXIO_PAGE_SELECT); + if (oldpage >= 0) { + PHY_WRITE(phydev, MAXIO_PAGE_SELECT, page); + ret = PHY_READ(phydev, regnum); + } + PHY_WRITE(phydev, MAXIO_PAGE_SELECT, oldpage); + + return ret; +} + +int maxio_write_paged(struct phy_device *phydev, int page, u32 regnum, u16 val) +{ + int ret = 0, oldpage; + + oldpage = PHY_READ(phydev, MAXIO_PAGE_SELECT); + if (oldpage >= 0) { + PHY_WRITE(phydev, MAXIO_PAGE_SELECT, page); + ret = PHY_WRITE(phydev, regnum, val); + } + + PHY_WRITE(phydev, MAXIO_PAGE_SELECT, oldpage); + + return ret; +} + +int maxio_adcc_check(struct phy_device *phydev) +{ + int ret = 0; + int adcvalue; + u32 regval; + int i; + + maxio_write_paged(phydev, 0xd96, 0x2, 0x1fff ); + maxio_write_paged(phydev, 0xd96, 0x2, 0x1000 ); + + for (i = 0; i < 4; i++) { + regval = 0xf908 + i * 0x100; + maxio_write_paged(phydev, 0xd8f, 0xb, regval ); + adcvalue = maxio_read_paged(phydev, 0xd92, 0xb); + if (adcvalue & 0x1ff) { + continue; + } else { + ret = -1; + break; + } + } + + return ret; +} + +int maxio_self_check(struct phy_device *phydev, int checknum) +{ + int ret = 0; + int i; + + for (i = 0; i < checknum; i++) { + ret = maxio_adcc_check(phydev); + if (0 == ret) { + printk("MAE0621A READY\n"); + break; + } else { + maxio_write_paged(phydev, 0x0, 0x0, 0x1940 ); + PHY_WRITE(phydev, MAXIO_PAGE_SELECT, 0x0); + msleep(10); + maxio_write_paged(phydev, 0x0, 0x0, 0x1140 ); + maxio_write_paged(phydev, 0x0, 0x0, 0x9140 ); + } + } + + maxio_write_paged(phydev, 0xd96, 0x2, 0xfff ); + maxio_write_paged(phydev, 0x0, 0x0, 0x9140 ); + PHY_WRITE(phydev, MAXIO_PAGE_SELECT, 0x0); + + return ret; +} + +static int maxio_mae0621a_resume(struct phy_device *phydev) +{ + int ret; + + ret = genphy_resume(phydev); + + ret |= PHY_WRITE(phydev, MII_BMCR, BMCR_RESET | PHY_READ(phydev, MII_BMCR)); + msleep(20); + + return ret; +} + +static int maxio_mae0621a_suspend(struct phy_device *phydev) +{ + int ret = 0; + + ret = genphy_suspend(phydev); + ret |= PHY_WRITE(phydev, MAXIO_PAGE_SELECT ,0); + + return ret; +} + +int maxio_restart_aneg(struct phy_device *phydev) +{ + int ctl = PHY_READ(phydev, MII_BMCR); + + if (ctl < 0) + return ctl; + + ctl |= BMCR_ANENABLE | BMCR_ANRESTART; + + ctl &= ~BMCR_ISOLATE; + + return PHY_WRITE(phydev, MII_BMCR, ctl); +} + +static void phy_resolve_aneg_linkmode_maxio(struct phy_device *phydev){ + + int physr_p_a43 = maxio_read_paged(phydev,0xa43,MAXIO_PHYSR_P_A43); + + if ((physr_p_a43&MAXIO_PHY_SPEED) == MAXIO_PHY_1000M) { + phydev->speed = SPEED_1000; + } else if ((physr_p_a43&MAXIO_PHY_SPEED) == MAXIO_PHY_100M) { + phydev->speed = SPEED_100; + } else if ((physr_p_a43&MAXIO_PHY_SPEED) == MAXIO_PHY_10M) { + phydev->speed = SPEED_10; + } + + if (physr_p_a43 & MAXIO_PHY_DUPLEX) { + phydev->duplex = DUPLEX_FULL; + } else { + phydev->duplex = DUPLEX_HALF; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0) + genphy_read_lpa(phydev); +#else + if (phydev->duplex == DUPLEX_FULL) { + int lpa = PHY_READ(phydev, MII_LPA); + phydev->pause = (lpa & LPA_PAUSE_CAP) ? 1 : 0; + phydev->asym_pause = (lpa & LPA_PAUSE_ASYM) ? 1 : 0; + } +#endif +} + +void phy_resolve_link_compatibility_maxio(struct phy_device *phydev) +{ + int *paras = (int *)phydev->priv; + int maxio_an_times = paras[0]; + int link_stable = paras[1]; + int iner, physr, insr; + iner = maxio_read_paged(phydev, 0xa42, 0x12); + if (iner&AUTONEG_COMPLETED_INT_EN) { + physr = maxio_read_paged(phydev, 0xa43, 0x1a); + if (physr & LINKOK) { + insr = maxio_read_paged(phydev, 0xa43, 0x1d); + if ((insr & AUTONEG_COMPLETED) == 0 && (link_stable == 0)) { + if (maxio_an_times < 4 ) { + maxio_restart_aneg(phydev); + phydev->link = 0; + maxio_an_times++; + } else if (maxio_an_times == 4) { + link_stable = 1; + } + } else if (insr & AUTONEG_COMPLETED) { + maxio_an_times = 0; + link_stable = 1; + } + + if (link_stable == 1) + maxio_an_times = 0; + } else + link_stable = 0; + } + + paras[0] = maxio_an_times; + paras[1] = link_stable; +} + +static int maxio_mae0621a_status(struct phy_device *phydev) +{ + int err, old_link = phydev->link; + + err = genphy_update_link(phydev); + if (err) + return err; + + if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) + return 0; + + phydev->speed = SPEED_UNKNOWN; + phydev->duplex = DUPLEX_UNKNOWN; + phydev->pause = 0; + phydev->asym_pause = 0; + + phy_resolve_aneg_linkmode_maxio(phydev); + + if (phydev->autoneg == AUTONEG_ENABLE) + phy_resolve_link_compatibility_maxio(phydev); + + return 0; +} + +static void maxio_mae0621a_remove(struct phy_device *phydev) +{ + printk("maxio driver remove\r\n"); + if (phydev->priv != NULL) { + kfree(phydev->priv); + } + phydev->priv=NULL; +} + +static int maxio_mae0621a_config_init(struct phy_device *phydev) +{ + int ret = 0; + + printk("MAXIO_PHY_VER: %s \n",MAXIO_PHY_VER); + + /* + * KICKPI K3B requires this (extracted from the maxio v1.8.1.1 driver), + * otherwise a DMA reset error occurs on the RK3562 STMicro MAC. + * What exactly does this do? I couldn't find this specific page in the datasheet... + */ + ret |= maxio_write_paged(phydev, 0xd92, 0x2, 0x200a); + + ret |= maxio_write_paged(phydev, 0xda0, 0x10, 0xc13); + ret |= maxio_write_paged(phydev, 0x0, 0xd, 0x7); + ret |= maxio_write_paged(phydev, 0x0, 0xe, 0x3c); + ret |= maxio_write_paged(phydev, 0x0, 0xd, 0x4007); + ret |= maxio_write_paged(phydev, 0x0, 0xe, 0x0); + ret |= maxio_write_paged(phydev, 0xd96, 0x13, 0x7bc); + ret |= maxio_write_paged(phydev, 0xd8f, 0x8, 0x2500); + ret |= maxio_write_paged(phydev, 0xd90, 0x2, 0x1555); + ret |= maxio_write_paged(phydev, 0xd90, 0x5, 0x2b15); + ret |= maxio_write_paged(phydev, 0xd92, 0x14, 0xa); + ret |= maxio_write_paged(phydev, 0xd91, 0x7, 0x5b00); + ret |= maxio_write_paged(phydev, 0xd8f, 0x0, 0x300); + ret |= maxio_write_paged(phydev, 0xd92, 0xa, 0x8506); + ret |= maxio_write_paged(phydev, 0xd91, 0x6, 0x6870); + ret |= maxio_write_paged(phydev, 0xd91, 0x1, 0x940); + ret |= maxio_write_paged(phydev, 0xda0, 0x13, 0x1303); + ret |= maxio_write_paged(phydev, 0xd97, 0xc, 0x177); + ret |= maxio_write_paged(phydev, 0xd97, 0xb, 0x9a9); + ret |= maxio_write_paged(phydev, 0xa42, 0x12, 0x28); + ret |= maxio_write_paged(phydev, 0x0, 0x4, 0xde1); + ret |= maxio_write_paged(phydev, 0x0, 0x0, 0x9140); + + PHY_WRITE(phydev, MAXIO_PAGE_SELECT, 0x0); + + ret |= maxio_self_check(phydev,50); + msleep(100); + + return 0; +} + +static int maxio_mae0621a_probe(struct phy_device *phydev) +{ + int *paras; + paras = kzalloc( 2 * sizeof(int), GFP_KERNEL); + if (!paras) + return -ENOMEM; + + phydev->priv = paras; + + /* + * KICKPI K3B requires this (extracted from the maxio v1.8.1.1 driver), + * otherwise a DMA reset error occurs on the RK3562 STMicro MAC. + * What exactly does this do? I couldn't find this specific page in the datasheet... + */ + maxio_write_paged(phydev, 0xd92, 0x2, 0x200a); + + printk("maxio_mae0621a_probe clkmode(oscillator) PHY_ID: 0x%x\n", phydev->phy_id); + + PHY_WRITE(phydev, MAXIO_PAGE_SELECT, 0x0); + mdelay(100); + + return 0; +} + +static int maxio_mae0621aq3ci_probe(struct phy_device *phydev) +{ + int *paras; + paras = kzalloc( 2 * sizeof(int), GFP_KERNEL); + if(!paras) + return -ENOMEM; + + phydev->priv = paras; + + printk("maxio_mae0621aQ3C probe PHY_ID: 0x%x\n", phydev->phy_id); + + return 0; +} + +static int maxio_mae0621aq3ci_config_init(struct phy_device *phydev) +{ + int ret = 0; + printk("MAXIO_PHY_VER: %s \n",MAXIO_PHY_VER); + + ret |= maxio_write_paged(phydev, 0xa43, 0x19, 0x823); + ret |= maxio_write_paged(phydev, 0xdab, 0x17, 0xC13); + ret |= maxio_write_paged(phydev, 0xd96, 0x15, 0xc08a); + ret |= maxio_write_paged(phydev, 0xda4, 0x12, 0x7bc); + ret |= maxio_write_paged(phydev, 0xd8f, 0x16, 0x2500); + ret |= maxio_write_paged(phydev, 0xd90, 0x16, 0x1555); + ret |= maxio_write_paged(phydev, 0xd92, 0x11, 0x2b15); + ret |= maxio_write_paged(phydev, 0xd96, 0x16, 0x4010); + ret |= maxio_write_paged(phydev, 0xda5, 0x11, 0x4a12); + ret |= maxio_write_paged(phydev, 0xda5, 0x12, 0x4a12); + ret |= maxio_write_paged(phydev, 0xd99, 0x16, 0xa); + ret |= maxio_write_paged(phydev, 0xd95, 0x13, 0x5b00); + ret |= maxio_write_paged(phydev, 0xd8f, 0x10, 0x300); + ret |= maxio_write_paged(phydev, 0xd98, 0x17, 0x8506); + ret |= maxio_write_paged(phydev, 0xd95, 0x12, 0x6870); + ret |= maxio_write_paged(phydev, 0xd93, 0x15, 0x940); + ret |= maxio_write_paged(phydev, 0xdad, 0x12, 0x303); // TXCST OFF + ret |= maxio_write_paged(phydev, 0xdad, 0x13, 0x50d); // IO DS=1 + ret |= maxio_write_paged(phydev, 0xdad, 0x14, 0xd05); + ret |= maxio_write_paged(phydev, 0xdad, 0x15, 0x505); + ret |= maxio_write_paged(phydev, 0xdad, 0x17, 0x1); + ret |= maxio_write_paged(phydev, 0xda8, 0x11, 0x177); + ret |= maxio_write_paged(phydev, 0xda8, 0x10, 0x9a9); + ret |= maxio_write_paged(phydev, 0xda8, 0x12, 0x868); + ret |= maxio_write_paged(phydev, 0xa42, 0x12, 0x28); + ret |= maxio_write_paged(phydev, 0x0, 0x4, 0xde1); + ret |= maxio_write_paged(phydev, 0x0, 0x0, 0x9140); + + ret |= PHY_WRITE(phydev, MAXIO_PAGE_SELECT, 0); + + return 0; +} + +static int maxio_mae0621aq3ci_resume(struct phy_device *phydev) +{ + int ret = 0; + ret = genphy_resume(phydev); + ret |= maxio_write_paged(phydev, 0xdaa, 0x17, 0x1001 ); + ret |= maxio_write_paged(phydev, 0xdab, 0x15, 0x0 ); + ret |= PHY_WRITE(phydev, MAXIO_PAGE_SELECT, 0); + + return ret; +} + +static int maxio_mae0621aq3ci_suspend(struct phy_device *phydev) +{ + int ret = 0; + + ret = maxio_write_paged(phydev, 0xdaa, 0x17, 0x1011 ); + ret |= maxio_write_paged(phydev, 0xdab, 0x15, 0x5550 ); + ret |= PHY_WRITE(phydev, MAXIO_PAGE_SELECT, 0); + + ret |= genphy_suspend(phydev); + + ret |= PHY_WRITE(phydev, MAXIO_PAGE_SELECT ,0); + + return ret; +} + +static struct phy_driver maxio_nc_drvs[] = { + { + .phy_id = 0x7b744411, + .phy_id_mask = 0x7fffffff, + .name = "MAE0621A-Q2C Gigabit Ethernet", + .features = PHY_GBIT_FEATURES, + .probe = maxio_mae0621a_probe, + .config_init = maxio_mae0621a_config_init, + .config_aneg = &genphy_config_aneg, + .read_status = maxio_mae0621a_status, + .suspend = maxio_mae0621a_suspend, + .resume = maxio_mae0621a_resume, + .remove = maxio_mae0621a_remove, + }, + { + .phy_id = 0x7b744412, + .phy_id_mask = 0x7fffffff, + .name = "MAE0621A/B-Q3C(I) Gigabit Ethernet", + .features = PHY_GBIT_FEATURES , + .probe = maxio_mae0621aq3ci_probe, + .config_aneg = &genphy_config_aneg, + .config_init = maxio_mae0621aq3ci_config_init, + .read_status = &maxio_mae0621a_status, + .suspend = maxio_mae0621aq3ci_suspend, + .resume = maxio_mae0621aq3ci_resume, + .remove = maxio_mae0621a_remove, + }, +}; + +module_phy_driver(maxio_nc_drvs); +static struct mdio_device_id __maybe_unused maxio_nc_tbl[] = { + { 0x7b744411, 0x7fffffff }, + { 0x7b744412, 0x7fffffff }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, maxio_nc_tbl); + +MODULE_DESCRIPTION("Maxio PHY driver"); +MODULE_AUTHOR("Zhao Yang"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 389f4e5256fa5..9dafef39d071b 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -902,6 +902,16 @@ static int get_phy_c22_id(struct mii_bus *bus, int addr, u32 *phy_id) { int phy_reg; +#ifdef CONFIG_MAXIO_PHY + /* + * An MDIO connects to multiple PHYs requiring write before read. + * And this is also required for KICKPI K3B, + * otherwise, the STMicro MAC will throw a DMA reset error. + * MII_PHYSID2 is a read-only register and writine to it has no effect. + */ + mdiobus_write(bus, addr, MII_PHYSID2, 0); +#endif + /* Grab the bits from PHYIR1, and put them in the upper half */ phy_reg = mdiobus_read(bus, addr, MII_PHYSID1); if (phy_reg < 0) {