mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
Initialization and support 3128-86v
This commit is contained in:
parent
37f6f8af51
commit
d31be74eb0
35
arch/arm/boot/dts/lcd-rk3128-86v-LVDS1024x600.dtsi
Executable file
35
arch/arm/boot/dts/lcd-rk3128-86v-LVDS1024x600.dtsi
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* RockChip. LCD_LVDS1024x600 FOR rk3128-86V
|
||||
*
|
||||
*/
|
||||
|
||||
/ {
|
||||
|
||||
disp_timings: display-timings {
|
||||
native-mode = <&timing0>;
|
||||
timing0: timing0 {
|
||||
screen-type = <SCREEN_LVDS>;
|
||||
lvds-format = <LVDS_8BIT_1>;
|
||||
out-face = <OUT_P888>;
|
||||
/* Min Typ Max Unit
|
||||
* Clock Frequency fclk 44.9 51.2 63 MHz
|
||||
*/
|
||||
clock-frequency = <60000000>;
|
||||
hactive = <1024>; /* Horizontal display area thd 1024 DCLK */
|
||||
vactive = <600>; /* Vertical display area tvd 600 H */
|
||||
hback-porch = <90>; /* HS Width +Back Porch 160 160 160 DCLK (Thw+ thbp)*/
|
||||
hfront-porch = <160>; /* HS front porch thfp 16 160 216 DCLK */
|
||||
vback-porch = <13>; /* VS front porch tvfp 1 12 127 H */
|
||||
vfront-porch = <12>; /* VS Width+Back Porch 23 23 23 H (Tvw+ tvbp) */
|
||||
hsync-len = <70>; /* HS Pulse Width thw 1 - 140 DCLK */
|
||||
vsync-len = <10>; /* VS Pulse Width tvw 1 - 20 H */
|
||||
hsync-active = <0>;
|
||||
vsync-active = <0>;
|
||||
de-active = <0>;
|
||||
pixelclk-active = <0>;
|
||||
swap-rb = <0>;
|
||||
swap-rg = <0>;
|
||||
swap-gb = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
291
arch/arm/boot/dts/rk3128-86v.dts
Executable file
291
arch/arm/boot/dts/rk3128-86v.dts
Executable file
|
|
@ -0,0 +1,291 @@
|
|||
/dts-v1/;
|
||||
|
||||
#include "rk3128.dtsi"
|
||||
#include "rk3128-cif-sensor.dtsi"
|
||||
#include "rk312x-sdk.dtsi"
|
||||
#include "lcd-rk3128-86v-LVDS1024x600.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "rockchip,rk3128";
|
||||
backlight: backlight {
|
||||
compatible = "pwm-backlight";
|
||||
pwms = <&pwm0 0 25000>;
|
||||
brightness-levels = <18 18 18 18 19 19 19 19 20 20 20 20 20 20 21 21 21 21 21 21 22 22 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255>;
|
||||
default-brightness-level = <128>;
|
||||
enable-gpios = <&gpio0 GPIO_D0 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
usb_control {
|
||||
compatible = "rockchip,rk3126-usb-control";
|
||||
|
||||
//host_drv_gpio = <&gpio3 GPIO_C4 GPIO_ACTIVE_LOW>;
|
||||
//otg_drv_gpio = <&gpio3 GPIO_C1 GPIO_ACTIVE_LOW>;
|
||||
|
||||
rockchip,remote_wakeup;
|
||||
rockchip,usb_irq_wakeup;
|
||||
};
|
||||
|
||||
|
||||
wireless-wlan {
|
||||
compatible = "wlan-platdata";
|
||||
|
||||
wifi_chip_type = "rtkwifi";
|
||||
sdio_vref = <1800>; //1800mv or 3300mv
|
||||
|
||||
// power_ctrl_by_pmu;
|
||||
// pmu_regulator = "act_ldo3";
|
||||
// pmu_enable_level = <1>; //1->HIGH, 0->LOW
|
||||
/* WIFI_HOST_WAKE = GPIO3_C7 */
|
||||
WIFI,host_wake_irq = <&gpio3 GPIO_C7 GPIO_ACTIVE_HIGH>;
|
||||
/* WIFI_REG_ON = GPIO3_D3 */
|
||||
WIFI,poweren_gpio = <&gpio3 GPIO_D3 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
status = "okay";
|
||||
};
|
||||
wireless-bluetooth {
|
||||
compatible = "bluetooth-platdata";
|
||||
|
||||
//wifi-bt-power-toggle;
|
||||
|
||||
uart_rts_gpios = <&gpio0 GPIO_C1 GPIO_ACTIVE_LOW>;
|
||||
pinctrl-names = "default","rts_gpio";
|
||||
pinctrl-0 = <&uart0_rts>;
|
||||
pinctrl-1 = <&uart0_rts_gpio>;
|
||||
|
||||
|
||||
/* BT_HOST_WAKE = GPIO3_C6 */
|
||||
/* BT_RST = GPIO3_C5 */
|
||||
/* BT_WAKE = GPIO3_D2 */
|
||||
//BT,power_gpio = <&gpio4 GPIO_D3 GPIO_ACTIVE_HIGH>;
|
||||
BT,reset_gpio = <&gpio3 GPIO_C5 GPIO_ACTIVE_HIGH>;
|
||||
BT,wake_gpio = <&gpio3 GPIO_D2 GPIO_ACTIVE_HIGH>;
|
||||
BT,wake_host_irq = <&gpio3 GPIO_C6 GPIO_ACTIVE_LOW>;
|
||||
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
rockchip_suspend {
|
||||
rockchip,ctrbits = <
|
||||
(0
|
||||
|RKPM_CTR_PWR_DMNS
|
||||
|RKPM_CTR_GTCLKS
|
||||
|RKPM_CTR_PLLS
|
||||
|RKPM_CTR_ARMOFF_LPMD
|
||||
|RKPM_CTR_IDLESRAM_MD
|
||||
|RKPM_CTR_DDR
|
||||
// |RKPM_CTR_VOLTS
|
||||
|RKPM_CTR_BUS_IDLE
|
||||
// |RKPM_CTR_VOL_PWM1
|
||||
)
|
||||
>;
|
||||
rockchip,pmic-suspend_gpios = <GPIO3_C1>;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
&gmac{
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&uart0 {
|
||||
status = "okay";
|
||||
dma-names = "!tx", "!rx";
|
||||
pinctrl-0 = <&uart0_xfer &uart0_cts>;
|
||||
};
|
||||
|
||||
&rk818 { /* PMIC_INT == GPIO1_B1 PMIC_SLEEP == GPIO3_C1*/
|
||||
gpios =<&gpio1 GPIO_B1 GPIO_ACTIVE_HIGH>,<&gpio3 GPIO_C1 GPIO_ACTIVE_LOW>;
|
||||
};
|
||||
/*
|
||||
&rk818_dcdc3_reg{
|
||||
regulator-name= "vcc_ddr";
|
||||
};
|
||||
|
||||
&rk818_ldo1_reg{
|
||||
regulator-name= "vcc_tp";
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
&i2c2 {
|
||||
status = "okay";
|
||||
ts@40 {
|
||||
compatible = "gslX680";
|
||||
reg = <0x40>;
|
||||
touch-gpio = <&gpio1 GPIO_B0 IRQ_TYPE_LEVEL_LOW>; /* TP_INT == GPIO1_B0 */
|
||||
reset-gpio = <&gpio0 GPIO_D1 GPIO_ACTIVE_LOW>; /* TP_RST == GPIO0_D1 */
|
||||
//power-gpio = <&gpio0 GPIO_C5 GPIO_ACTIVE_LOW>;
|
||||
max-x = <1280>;
|
||||
max-y = <600>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sensor@4c {
|
||||
compatible = "gs_mma7660";
|
||||
reg = <0x4c>;
|
||||
type = <SENSOR_TYPE_ACCEL>;
|
||||
irq-gpio = <&gpio1 GPIO_B2 IRQ_TYPE_LEVEL_LOW>; /* GSENSOR_INT = GPIO1_B2 */
|
||||
irq_enable = <0>;
|
||||
poll_delay_ms = <30>;
|
||||
layout = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
&adc{
|
||||
status = "okay";
|
||||
key: key {
|
||||
compatible = "rockchip,key";
|
||||
io-channels = <&adc 1>;
|
||||
|
||||
vol-up-key {
|
||||
linux,code = <115>;
|
||||
label = "volume up";
|
||||
|
||||
rockchip,adc_value = <1>;
|
||||
|
||||
};
|
||||
|
||||
vol-down-key {
|
||||
linux,code = <114>;
|
||||
label = "volume down";
|
||||
|
||||
rockchip,adc_value = <512>;
|
||||
|
||||
};
|
||||
/* PWR_KEY == GPIO0_A2 */
|
||||
power-key {
|
||||
gpios = <&gpio0 GPIO_A2 GPIO_ACTIVE_LOW>;
|
||||
linux,code = <116>;
|
||||
label = "power";
|
||||
gpio-key,wakeup;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
&fb {
|
||||
rockchip,disp-mode = <ONE_DUAL>;
|
||||
rockchip,uboot-logo-on = <1>;
|
||||
};
|
||||
|
||||
&rk_screen {
|
||||
display-timings = <&disp_timings>;
|
||||
};
|
||||
|
||||
&lvds {
|
||||
status = "okay";
|
||||
|
||||
pinctrl-names = "lcdc";
|
||||
pinctrl-0 = <&lcdc0_lcdc_d>;
|
||||
};
|
||||
|
||||
&lcdc {
|
||||
status = "okay";
|
||||
|
||||
//backlight = <&backlight>;
|
||||
pinctrl-names = "default", "gpio";
|
||||
pinctrl-0 = <&lcdc0_lcdc>;
|
||||
pinctrl-1 = <&lcdc0_gpio>;
|
||||
|
||||
rockchip,fb-win-map = <FB_DEFAULT_ORDER>;
|
||||
power_ctr: power_ctr {
|
||||
rockchip,debug = <0>;
|
||||
/*
|
||||
lcd_en: lcd_en {
|
||||
rockchip,power_type = <GPIO>;
|
||||
gpios = <&gpio3 GPIO_C4 GPIO_ACTIVE_HIGH>;
|
||||
rockchip,delay = <10>;
|
||||
};
|
||||
*/
|
||||
};
|
||||
};
|
||||
|
||||
&hdmi {
|
||||
status = "okay"; //"disabled";
|
||||
};
|
||||
|
||||
&sdmmc {/* SDMMC_DET = GPIO1_C1 */
|
||||
cd-gpios = <&gpio1 GPIO_C1 GPIO_ACTIVE_HIGH>;/*CD GPIO*/
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&dwc_control_usb {
|
||||
usb_uart {
|
||||
status = "ok";
|
||||
};
|
||||
};
|
||||
|
||||
&codec {
|
||||
spk_ctl_io = <&gpio0 GPIO_D6 GPIO_ACTIVE_HIGH>;/* SPK_CTL == GPIO0_D6 */
|
||||
spk-mute-delay = <200>;
|
||||
hp-mute-delay = <100>;
|
||||
rk312x_for_mid = <1>;
|
||||
is_rk3128 = <0>;/* is_rk3128 = <0> */
|
||||
spk_volume = <25>;
|
||||
hp_volume = <25>;
|
||||
capture_volume = <26>;
|
||||
gpio_debug = <1>;
|
||||
codec_hp_det = <0>;
|
||||
};
|
||||
|
||||
&rk3128_cif_sensor{
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
||||
&clk_core_dvfs_table {
|
||||
operating-points = <
|
||||
/* KHz uV */
|
||||
216000 925000
|
||||
408000 925000
|
||||
600000 950000
|
||||
696000 975000
|
||||
816000 1050000
|
||||
1008000 1175000
|
||||
1200000 1300000
|
||||
// 1296000 1350000
|
||||
// 1320000 1375000
|
||||
>;
|
||||
status="okay";
|
||||
};
|
||||
|
||||
&clk_gpu_dvfs_table {
|
||||
operating-points = <
|
||||
/* KHz uV */
|
||||
200000 1000000
|
||||
300000 1025000
|
||||
400000 1125000
|
||||
//480000 1175000
|
||||
>;
|
||||
status="okay";
|
||||
};
|
||||
|
||||
&clk_ddr_dvfs_table {
|
||||
operating-points = <
|
||||
/* KHz uV */
|
||||
200000 1000000
|
||||
300000 1000000
|
||||
400000 1075000
|
||||
533000 1250000
|
||||
>;
|
||||
|
||||
freq-table = <
|
||||
/*status freq(KHz)*/
|
||||
SYS_STATUS_NORMAL 400000
|
||||
SYS_STATUS_SUSPEND 200000
|
||||
SYS_STATUS_VIDEO_1080P 240000
|
||||
SYS_STATUS_VIDEO_4K 400000
|
||||
SYS_STATUS_PERFORMANCE 528000
|
||||
SYS_STATUS_DUALVIEW 400000
|
||||
SYS_STATUS_BOOST 324000
|
||||
SYS_STATUS_ISP 533000
|
||||
>;
|
||||
auto-freq-table = <
|
||||
240000
|
||||
324000
|
||||
396000
|
||||
528000
|
||||
>;
|
||||
auto-freq=<0>;
|
||||
status="okay";
|
||||
};
|
||||
|
|
@ -10,7 +10,7 @@ rk3128_cif_sensor: rk3128_cif_sensor{
|
|||
CONFIG_SENSOR_AF_IOCTL_USR = <0>;
|
||||
|
||||
ov2659{
|
||||
is_front = <1>;
|
||||
is_front = <1>;
|
||||
rockchip,powerdown = <&gpio3 GPIO_D7 GPIO_ACTIVE_HIGH>;
|
||||
pwdn_active = <ov2659_PWRDN_ACTIVE>;
|
||||
#rockchip,power = <>;
|
||||
|
|
@ -22,7 +22,7 @@ ov2659{
|
|||
mir = <0>;
|
||||
flash_attach = <0>;
|
||||
resolution = <ov2659_FULL_RESOLUTION>;
|
||||
powerup_sequence = <ov2659_PWRSEQ>;
|
||||
powerup_sequence = <ov2659_PWRSEQ>;
|
||||
orientation = <0>;
|
||||
i2c_add = <ov2659_I2C_ADDR>;
|
||||
i2c_rata = <100000>;
|
||||
|
|
@ -31,7 +31,7 @@ ov2659{
|
|||
mclk_rate = <24>;
|
||||
};
|
||||
gc0329{
|
||||
is_front = <1>;
|
||||
is_front = <1>;
|
||||
rockchip,powerdown = <&gpio3 GPIO_D7 GPIO_ACTIVE_HIGH>;
|
||||
pwdn_active = <gc0329_PWRDN_ACTIVE>;
|
||||
#rockchip,power = <>;
|
||||
|
|
@ -43,7 +43,7 @@ gc0329{
|
|||
mir = <0>;
|
||||
flash_attach = <0>;
|
||||
resolution = <gc0329_FULL_RESOLUTION>;
|
||||
powerup_sequence = <gc0329_PWRSEQ>;
|
||||
powerup_sequence = <gc0329_PWRSEQ>;
|
||||
orientation = <0>;
|
||||
i2c_add = <gc0329_I2C_ADDR>;
|
||||
i2c_rata = <100000>;
|
||||
|
|
@ -51,6 +51,42 @@ gc0329{
|
|||
cif_chl = <0>;
|
||||
mclk_rate = <24>;
|
||||
};
|
||||
|
||||
gc2035{
|
||||
is_front = <0>;
|
||||
rockchip,power = <&gpio2 GPIO_B2 GPIO_ACTIVE_HIGH>;
|
||||
rockchip,powerdown = <&gpio3 GPIO_B3 GPIO_ACTIVE_HIGH>;
|
||||
pwdn_active = <gc2035_PWRDN_ACTIVE>;
|
||||
pwr_active = <PWR_ACTIVE_HIGH>;
|
||||
mir = <0>;
|
||||
flash_attach = <0>;
|
||||
resolution = <gc2035_FULL_RESOLUTION>;
|
||||
powerup_sequence = <gc2035_PWRSEQ>;
|
||||
orientation = <180>;
|
||||
i2c_add = <gc2035_I2C_ADDR>;
|
||||
i2c_rata = <100000>;
|
||||
i2c_chl = <2>;
|
||||
cif_chl = <0>;
|
||||
mclk_rate = <24>;
|
||||
};
|
||||
gc0308{
|
||||
is_front = <1>;
|
||||
rockchip,power = <&gpio2 GPIO_B2 GPIO_ACTIVE_HIGH>;
|
||||
rockchip,powerdown = <&gpio3 GPIO_D7 GPIO_ACTIVE_HIGH>;
|
||||
pwdn_active = <gc0308_PWRDN_ACTIVE>;
|
||||
pwr_active = <PWR_ACTIVE_HIGH>;
|
||||
mir = <0>;
|
||||
flash_attach = <0>;
|
||||
resolution = <gc0308_FULL_RESOLUTION>;
|
||||
powerup_sequence = <gc0308_PWRSEQ>;
|
||||
orientation = <180>;
|
||||
i2c_add = <gc0308_I2C_ADDR>;
|
||||
i2c_rata = <100000>;
|
||||
i2c_chl = <2>;
|
||||
cif_chl = <0>;
|
||||
mclk_rate = <24>;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@ config TOUCHSCREEN_ZET62XX
|
|||
zet62xx touchscreen driver
|
||||
|
||||
|
||||
config TOUCHSCREEN_GSLX680
|
||||
tristate "gslX680 touchscreen driver"
|
||||
help
|
||||
gslX680 touchscreen driver
|
||||
|
||||
config TOUCHSCREEN_GT8XX
|
||||
tristate "Goodix touch screen gt801X2 support for rockchip based platform"
|
||||
help
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
wm97xx-ts-y := wm97xx-core.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_ZET62XX) += zet62xx/
|
||||
obj-$(CONFIG_TOUCHSCREEN_GSLX680) += rockchip_gslX680_rk3128.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_CT36X_TS) += ct36x/
|
||||
obj-$(CONFIG_TOUCHSCREEN_GT8XX) += rk29_i2c_goodix.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
|
||||
|
|
|
|||
993
drivers/input/touchscreen/rockchip_gslX680_rk3128.c
Executable file
993
drivers/input/touchscreen/rockchip_gslX680_rk3128.c
Executable file
|
|
@ -0,0 +1,993 @@
|
|||
/*
|
||||
* drivers/input/touchscreen/gslX680.c
|
||||
*
|
||||
* Copyright (c) 2012 Shanghai Basewin
|
||||
* Guan Yuwei<guanyuwei@basewin.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/async.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include "rockchip_gslX680_rk3128.h"
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include "tp_suspend.h"
|
||||
|
||||
#define GPIO_HIGH 1
|
||||
#define GPIO_LOW 0
|
||||
|
||||
/* #define GSL_DEBUG */
|
||||
/* #define GSL_TIMER */
|
||||
#define REPORT_DATA_ANDROID_4_0
|
||||
|
||||
/* #define HAVE_TOUCH_KEY */
|
||||
|
||||
#define GSLX680_I2C_NAME "gslX680"
|
||||
#define GSLX680_I2C_ADDR 0x40
|
||||
|
||||
/* #define IRQ_PORT RK2928_PIN1_PB0 */
|
||||
/* #define WAKE_PORT RK2928_PIN0_PD3 */
|
||||
|
||||
#define GSL_DATA_REG 0x80
|
||||
#define GSL_STATUS_REG 0xe0
|
||||
#define GSL_PAGE_REG 0xf0
|
||||
|
||||
#define PRESS_MAX 255
|
||||
#define MAX_FINGERS 5
|
||||
#define MAX_CONTACTS 10
|
||||
#define DMA_TRANS_LEN 0x20
|
||||
/* #define FILTER_POINT */
|
||||
#ifdef FILTER_POINT
|
||||
#define FILTER_MAX 6
|
||||
#endif
|
||||
|
||||
#define WRITE_I2C_SPEED (350*1000)
|
||||
#define I2C_SPEED (200*1000)
|
||||
|
||||
|
||||
|
||||
#define CLOSE_TP_POWER 0
|
||||
|
||||
#if CLOSE_TP_POWER
|
||||
static void set_tp_power(bool flag);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOUCH_KEY
|
||||
static u16 key;
|
||||
static int key_state_flag;
|
||||
|
||||
|
||||
struct key_data {
|
||||
u16 key;
|
||||
u16 x_min;
|
||||
u16 x_max;
|
||||
u16 y_min;
|
||||
u16 y_max;
|
||||
};
|
||||
|
||||
const u16 key_array[] = {
|
||||
KEY_BACK,
|
||||
KEY_HOME,
|
||||
KEY_MENU,
|
||||
KEY_SEARCH,
|
||||
};
|
||||
|
||||
#define MAX_KEY_NUM (sizeof(key_array)/sizeof(key_array[0]))
|
||||
|
||||
struct key_data gsl_key_data[MAX_KEY_NUM] = {
|
||||
{KEY_BACK, 2048, 2048, 2048, 2048},
|
||||
{KEY_HOME, 2048, 2048, 2048, 2048},
|
||||
{KEY_MENU, 2048, 2048, 2048, 2048},
|
||||
{KEY_SEARCH, 2048, 2048, 2048, 2048},
|
||||
};
|
||||
#endif
|
||||
|
||||
struct gsl_ts_data {
|
||||
u8 x_index;
|
||||
u8 y_index;
|
||||
u8 z_index;
|
||||
u8 id_index;
|
||||
u8 touch_index;
|
||||
u8 data_reg;
|
||||
u8 status_reg;
|
||||
u8 data_size;
|
||||
u8 touch_bytes;
|
||||
u8 update_data;
|
||||
u8 touch_meta_data;
|
||||
u8 finger_size;
|
||||
};
|
||||
|
||||
static struct gsl_ts_data devices[] = {
|
||||
{
|
||||
.x_index = 6,
|
||||
.y_index = 4,
|
||||
.z_index = 5,
|
||||
.id_index = 7,
|
||||
.data_reg = GSL_DATA_REG,
|
||||
.status_reg = GSL_STATUS_REG,
|
||||
.update_data = 0x4,
|
||||
.touch_bytes = 4,
|
||||
.touch_meta_data = 4,
|
||||
.finger_size = 70,
|
||||
},
|
||||
};
|
||||
|
||||
struct gsl_ts {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
struct work_struct work;
|
||||
struct workqueue_struct *wq;
|
||||
struct gsl_ts_data *dd;
|
||||
u8 *touch_data;
|
||||
u8 device_id;
|
||||
int irq;
|
||||
#if defined(CONFIG_HAS_EARLYSUSPEND)
|
||||
struct early_suspend early_suspend;
|
||||
#endif
|
||||
#ifdef GSL_TIMER
|
||||
struct timer_list gsl_timer;
|
||||
#endif
|
||||
int reset_gpio;
|
||||
};
|
||||
|
||||
static struct gsl_ts *g_gsl_ts;
|
||||
|
||||
#ifdef GSL_DEBUG
|
||||
#define print_info(fmt, args...) printk(fmt, ##args)
|
||||
#else
|
||||
#define print_info(fmt, args...)
|
||||
#endif
|
||||
|
||||
static int ts_global_reset_pin;
|
||||
|
||||
static u32 id_sign[MAX_CONTACTS+1] = {0};
|
||||
static u8 id_state_flag[MAX_CONTACTS+1] = {0};
|
||||
static u8 id_state_old_flag[MAX_CONTACTS+1] = {0};
|
||||
static u16 x_old[MAX_CONTACTS+1] = {0};
|
||||
static u16 y_old[MAX_CONTACTS+1] = {0};
|
||||
static u16 x_new;
|
||||
static u16 y_new;
|
||||
|
||||
int i2c_master_normal_send(const struct i2c_client *client, const char *buf, int count, int scl_rate)
|
||||
{
|
||||
int ret;
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
struct i2c_msg msg;
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags;
|
||||
msg.len = count;
|
||||
msg.buf = (char *)buf;
|
||||
msg.scl_rate = scl_rate;
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
return (ret == 1) ? count : ret;
|
||||
}
|
||||
|
||||
int i2c_master_normal_recv(const struct i2c_client *client, char *buf, int count, int scl_rate)
|
||||
{
|
||||
struct i2c_adapter *adap = client->adapter;
|
||||
struct i2c_msg msg;
|
||||
int ret;
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = client->flags | I2C_M_RD;
|
||||
msg.len = count;
|
||||
msg.buf = (char *)buf;
|
||||
msg.scl_rate = scl_rate;
|
||||
|
||||
ret = i2c_transfer(adap, &msg, 1);
|
||||
|
||||
return (ret == 1) ? count : ret;
|
||||
}
|
||||
|
||||
static int gslX680_shutdown_low(void)
|
||||
{
|
||||
gpio_direction_output(ts_global_reset_pin, GPIO_LOW);
|
||||
gpio_set_value(ts_global_reset_pin, GPIO_LOW);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gslX680_shutdown_high(void)
|
||||
{
|
||||
gpio_direction_output(ts_global_reset_pin, GPIO_HIGH);
|
||||
gpio_set_value(ts_global_reset_pin, GPIO_HIGH);
|
||||
return 0;
|
||||
}
|
||||
static inline u16 join_bytes(u8 a, u8 b)
|
||||
{
|
||||
u16 ab = 0;
|
||||
|
||||
ab = ab | a;
|
||||
ab = ab << 8 | b;
|
||||
return ab;
|
||||
}
|
||||
|
||||
static u32 gsl_write_interface(struct i2c_client *client, const u8 reg, u8 *buf, u32 num)
|
||||
{
|
||||
struct i2c_msg xfer_msg[1];
|
||||
|
||||
buf[0] = reg;
|
||||
|
||||
xfer_msg[0].addr = client->addr;
|
||||
xfer_msg[0].len = num + 1;
|
||||
xfer_msg[0].flags = client->flags & I2C_M_TEN;
|
||||
xfer_msg[0].buf = buf;
|
||||
xfer_msg[0].scl_rate = WRITE_I2C_SPEED;
|
||||
|
||||
return i2c_transfer(client->adapter, xfer_msg, 1) == 1 ? 0 : -EFAULT;
|
||||
}
|
||||
|
||||
static int gsl_ts_write(struct i2c_client *client, u8 addr, u8 *pdata, int datalen)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 tmp_buf[128];
|
||||
unsigned int bytelen;
|
||||
|
||||
bytelen = 0;
|
||||
|
||||
if (datalen > 125) {
|
||||
printk("%s too big datalen = %d!\n", __func__, datalen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp_buf[0] = addr;
|
||||
bytelen++;
|
||||
if (datalen != 0 && pdata != NULL) {
|
||||
memcpy(&tmp_buf[bytelen], pdata, datalen);
|
||||
bytelen += datalen;
|
||||
}
|
||||
ret = i2c_master_normal_send(client, tmp_buf, bytelen, I2C_SPEED);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int gsl_ts_read(struct i2c_client *client, u8 addr, u8 *pdata, unsigned int datalen)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (datalen > 126) {
|
||||
printk("%s too big datalen = %d!\n", __func__, datalen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = gsl_ts_write(client, addr, NULL, 0);
|
||||
if (ret < 0) {
|
||||
printk("%s set data address fail!\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
return i2c_master_normal_recv(client, pdata, datalen, I2C_SPEED);
|
||||
}
|
||||
|
||||
|
||||
static __inline__ void fw2buf(u8 *buf, const u32 *fw)
|
||||
{
|
||||
u32 *u32_buf = (int *)buf;
|
||||
*u32_buf = *fw;
|
||||
}
|
||||
|
||||
static void gsl_load_fw(struct i2c_client *client)
|
||||
{
|
||||
u8 buf[DMA_TRANS_LEN*4 + 1] = {0};
|
||||
u8 send_flag = 1;
|
||||
u8 *cur = buf + 1;
|
||||
u32 source_line = 0;
|
||||
u32 source_len;
|
||||
u8 read_buf[4] = {0};
|
||||
const struct fw_data *ptr_fw;
|
||||
printk("=============gsl_load_fw start==============\n");
|
||||
|
||||
#ifdef GSL1680E_COMPATIBLE
|
||||
msleep(50);
|
||||
gsl_ts_read(client, 0xfc, read_buf, 4);
|
||||
|
||||
|
||||
if (read_buf[2] != 0x82 && read_buf[2] != 0x88) {
|
||||
msleep(100);
|
||||
gsl_ts_read(client, 0xfc, read_buf, 4);
|
||||
}
|
||||
if (read_buf[2] == 0x82) {
|
||||
ptr_fw = GSL1680E_FW;
|
||||
source_len = ARRAY_SIZE(GSL1680E_FW);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
ptr_fw = GSLX680_FW;
|
||||
source_len = ARRAY_SIZE(GSLX680_FW);
|
||||
}
|
||||
|
||||
for (source_line = 0; source_line < source_len; source_line++) {
|
||||
/* init page trans, set the page val */
|
||||
if (GSL_PAGE_REG == ptr_fw[source_line].offset) {
|
||||
fw2buf(cur, &ptr_fw[source_line].val);
|
||||
gsl_write_interface(client, GSL_PAGE_REG, buf, 4);
|
||||
send_flag = 1;
|
||||
} else {
|
||||
if (1 == send_flag % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20))
|
||||
buf[0] = (u8)ptr_fw[source_line].offset;
|
||||
|
||||
fw2buf(cur, &ptr_fw[source_line].val);
|
||||
cur += 4;
|
||||
|
||||
if (0 == send_flag % (DMA_TRANS_LEN < 0x20 ? DMA_TRANS_LEN : 0x20)) {
|
||||
gsl_write_interface(client, buf[0], buf, cur - buf - 1);
|
||||
cur = buf + 1;
|
||||
}
|
||||
|
||||
send_flag++;
|
||||
}
|
||||
}
|
||||
|
||||
printk("=============gsl_load_fw end==============\n");
|
||||
}
|
||||
|
||||
|
||||
static void startup_chip(struct i2c_client *client)
|
||||
{
|
||||
u8 tmp = 0x00;
|
||||
u8 buf[4] = {0x00};
|
||||
|
||||
buf[3] = 0x01;
|
||||
buf[2] = 0xfe;
|
||||
buf[1] = 0x10;
|
||||
buf[0] = 0x00;
|
||||
gsl_ts_write(client, 0xf0, buf, sizeof(buf));
|
||||
buf[3] = 0x00;
|
||||
buf[2] = 0x00;
|
||||
buf[1] = 0x00;
|
||||
buf[0] = 0x0f;
|
||||
gsl_ts_write(client, 0x04, buf, sizeof(buf));
|
||||
msleep(20);
|
||||
gsl_ts_write(client, 0xe0, &tmp, 1);
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static void reset_chip(struct i2c_client *client)
|
||||
{
|
||||
u8 tmp = 0x88;
|
||||
u8 buf[4] = {0x00};
|
||||
|
||||
gsl_ts_write(client, 0xe0, &tmp, sizeof(tmp));
|
||||
msleep(20);
|
||||
tmp = 0x04;
|
||||
gsl_ts_write(client, 0xe4, &tmp, sizeof(tmp));
|
||||
msleep(10);
|
||||
gsl_ts_write(client, 0xbc, buf, sizeof(buf));
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
static void clr_reg(struct i2c_client *client)
|
||||
{
|
||||
u8 write_buf[4] = {0};
|
||||
|
||||
write_buf[0] = 0x88;
|
||||
gsl_ts_write(client, 0xe0, &write_buf[0], 1);
|
||||
msleep(20);
|
||||
write_buf[0] = 0x01;
|
||||
gsl_ts_write(client, 0x80, &write_buf[0], 1);
|
||||
msleep(5);
|
||||
write_buf[0] = 0x04;
|
||||
gsl_ts_write(client, 0xe4, &write_buf[0], 1);
|
||||
msleep(5);
|
||||
write_buf[0] = 0x00;
|
||||
gsl_ts_write(client, 0xe0, &write_buf[0], 1);
|
||||
msleep(20);
|
||||
}
|
||||
|
||||
static void init_chip(struct i2c_client *client)
|
||||
{
|
||||
gslX680_shutdown_low();
|
||||
msleep(20);
|
||||
gslX680_shutdown_high();
|
||||
msleep(20);
|
||||
clr_reg(client);
|
||||
reset_chip(client);
|
||||
gsl_load_fw(client);
|
||||
startup_chip(client);
|
||||
reset_chip(client);
|
||||
startup_chip(client);
|
||||
}
|
||||
|
||||
static void check_mem_data(struct i2c_client *client)
|
||||
{
|
||||
u8 read_buf[4] = {0};
|
||||
|
||||
msleep(50);
|
||||
gsl_ts_read(client, 0xb0, read_buf, sizeof(read_buf));
|
||||
|
||||
if (read_buf[3] != 0x5a || read_buf[2] != 0x5a || read_buf[1] != 0x5a || read_buf[0] != 0x5a) {
|
||||
printk("#########check mem read 0xb0 = %x %x %x %x #########\n", read_buf[3], read_buf[2], read_buf[1], read_buf[0]);
|
||||
#if CLOSE_TP_POWER
|
||||
set_tp_power(false);
|
||||
msleep(200);
|
||||
set_tp_power(true);
|
||||
msleep(100);
|
||||
#endif
|
||||
init_chip(client);
|
||||
}
|
||||
}
|
||||
|
||||
static void record_point(u16 x, u16 y , u8 id)
|
||||
{
|
||||
u16 x_err = 0;
|
||||
u16 y_err = 0;
|
||||
|
||||
id_sign[id] = id_sign[id] + 1;
|
||||
|
||||
if (id_sign[id] == 1) {
|
||||
x_old[id] = x;
|
||||
y_old[id] = y;
|
||||
}
|
||||
|
||||
x = (x_old[id] + x)/2;
|
||||
y = (y_old[id] + y)/2;
|
||||
|
||||
if (x > x_old[id]) {
|
||||
x_err = x - x_old[id];
|
||||
} else {
|
||||
x_err = x_old[id]-x;
|
||||
}
|
||||
|
||||
if (y > y_old[id]) {
|
||||
y_err = y - y_old[id];
|
||||
} else {
|
||||
y_err = y_old[id] - y;
|
||||
}
|
||||
|
||||
if ((x_err > 3 && y_err > 1) || (x_err > 1 && y_err > 3)) {
|
||||
x_new = x;
|
||||
x_old[id] = x;
|
||||
y_new = y;
|
||||
y_old[id] = y;
|
||||
} else {
|
||||
if (x_err > 3) {
|
||||
x_new = x;
|
||||
x_old[id] = x;
|
||||
} else
|
||||
x_new = x_old[id];
|
||||
|
||||
if (y_err > 3) {
|
||||
y_new = y;
|
||||
y_old[id] = y;
|
||||
} else
|
||||
y_new = y_old[id];
|
||||
}
|
||||
|
||||
if (id_sign[id] == 1) {
|
||||
x_new = x_old[id];
|
||||
y_new = y_old[id];
|
||||
}
|
||||
}
|
||||
|
||||
static void report_data(struct gsl_ts *ts, u16 x, u16 y, u8 pressure, u8 id)
|
||||
{
|
||||
swap(x, y);
|
||||
|
||||
print_info("#####id=%d,x=%d,y=%d######\n", id, x, y);
|
||||
x = 1024 - x;
|
||||
y = 600 - y;
|
||||
|
||||
if (x > SCREEN_MAX_X || y > SCREEN_MAX_Y) {
|
||||
#ifdef HAVE_TOUCH_KEY
|
||||
report_key(ts, x, y);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef REPORT_DATA_ANDROID_4_0
|
||||
input_mt_slot(ts->input, id);
|
||||
input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
|
||||
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure);
|
||||
input_report_abs(ts->input, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
|
||||
input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1);
|
||||
#else
|
||||
input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
|
||||
input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, pressure);
|
||||
input_report_abs(ts->input, ABS_MT_POSITION_X, x);
|
||||
input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
|
||||
input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1);
|
||||
input_mt_sync(ts->input);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void process_gslX680_data(struct gsl_ts *ts)
|
||||
{
|
||||
u8 id, touches;
|
||||
u16 x, y;
|
||||
int i = 0;
|
||||
|
||||
touches = ts->touch_data[ts->dd->touch_index];
|
||||
for (i = 1; i <= MAX_CONTACTS; i++) {
|
||||
if (touches == 0)
|
||||
id_sign[i] = 0;
|
||||
id_state_flag[i] = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < (touches > MAX_FINGERS ? MAX_FINGERS : touches); i++) {
|
||||
x = join_bytes((ts->touch_data[ts->dd->x_index + 4*i + 1] & 0xf), ts->touch_data[ts->dd->x_index + 4*i]);
|
||||
y = join_bytes(ts->touch_data[ts->dd->y_index + 4*i + 1], ts->touch_data[ts->dd->y_index + 4*i]);
|
||||
id = ts->touch_data[ts->dd->id_index + 4*i] >> 4;
|
||||
|
||||
if (1 <= id && id <= MAX_CONTACTS) {
|
||||
#ifdef FILTER_POINT
|
||||
filter_point(x, y, id);
|
||||
#else
|
||||
record_point(x, y, id);
|
||||
#endif
|
||||
report_data(ts, x_new, y_new, 50, id);
|
||||
id_state_flag[id] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 1; i <= MAX_CONTACTS; i++) {
|
||||
if ((0 == touches) || ((0 != id_state_old_flag[i]) && (0 == id_state_flag[i]))) {
|
||||
#ifdef REPORT_DATA_ANDROID_4_0
|
||||
input_mt_slot(ts->input, i);
|
||||
input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1);
|
||||
input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false);
|
||||
#endif
|
||||
id_sign[i] = 0;
|
||||
}
|
||||
id_state_old_flag[i] = id_state_flag[i];
|
||||
}
|
||||
#ifndef REPORT_DATA_ANDROID_4_0
|
||||
if (0 == touches) {
|
||||
input_mt_sync(ts->input);
|
||||
#ifdef HAVE_TOUCH_KEY
|
||||
if (key_state_flag) {
|
||||
input_report_key(ts->input, key, 0);
|
||||
input_sync(ts->input);
|
||||
key_state_flag = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
input_sync(ts->input);
|
||||
}
|
||||
|
||||
|
||||
static void gsl_ts_xy_worker(struct work_struct *work)
|
||||
{
|
||||
int rc;
|
||||
u8 read_buf[4] = {0};
|
||||
|
||||
struct gsl_ts *ts = container_of(work, struct gsl_ts, work);
|
||||
print_info("---gsl_ts_xy_worker---\n");
|
||||
|
||||
/* read data from DATA_REG */
|
||||
rc = gsl_ts_read(ts->client, 0x80, ts->touch_data, ts->dd->data_size);
|
||||
print_info("---touches: %d ---\n", ts->touch_data[0]);
|
||||
|
||||
if (rc < 0) {
|
||||
dev_err(&ts->client->dev, "read failed\n");
|
||||
goto schedule;
|
||||
}
|
||||
|
||||
if (ts->touch_data[ts->dd->touch_index] == 0xff) {
|
||||
goto schedule;
|
||||
}
|
||||
|
||||
rc = gsl_ts_read(ts->client, 0xbc, read_buf, sizeof(read_buf));
|
||||
if (rc < 0) {
|
||||
dev_err(&ts->client->dev, "read 0xbc failed\n");
|
||||
goto schedule;
|
||||
}
|
||||
print_info("//////// reg %x : %x %x %x %x\n", 0xbc, read_buf[3], read_buf[2], read_buf[1], read_buf[0]);
|
||||
|
||||
if (read_buf[3] == 0 && read_buf[2] == 0 && read_buf[1] == 0 && read_buf[0] == 0) {
|
||||
process_gslX680_data(ts);
|
||||
} else {
|
||||
reset_chip(ts->client);
|
||||
startup_chip(ts->client);
|
||||
}
|
||||
schedule:
|
||||
enable_irq(ts->irq);
|
||||
}
|
||||
|
||||
static irqreturn_t gsl_ts_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct gsl_ts *ts = dev_id;
|
||||
|
||||
print_info("==========GSLX680 Interrupt============\n");
|
||||
|
||||
disable_irq_nosync(ts->irq);
|
||||
|
||||
if (!work_pending(&ts->work)) {
|
||||
queue_work(ts->wq, &ts->work);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
||||
}
|
||||
|
||||
#ifdef GSL_TIMER
|
||||
static void gsl_timer_handle(unsigned long data)
|
||||
{
|
||||
struct gsl_ts *ts = (struct gsl_ts *)data;
|
||||
|
||||
#ifdef GSL_DEBUG
|
||||
printk("----------------gsl_timer_handle-----------------\n");
|
||||
#endif
|
||||
|
||||
disable_irq_nosync(ts->irq);
|
||||
check_mem_data(ts->client);
|
||||
ts->gsl_timer.expires = jiffies + 3 * HZ;
|
||||
add_timer(&ts->gsl_timer);
|
||||
enable_irq(ts->irq);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int gsl_ts_init_ts(struct i2c_client *client, struct gsl_ts *ts)
|
||||
{
|
||||
struct input_dev *input_device;
|
||||
#ifdef CONFIG_MACH_RK_FAC
|
||||
struct tp_platform_data *pdata = client->dev.platform_data;
|
||||
#endif
|
||||
int rc = 0;
|
||||
|
||||
printk("[GSLX680] Enter %s\n", __func__);
|
||||
|
||||
ts->dd = &devices[ts->device_id];
|
||||
|
||||
if (ts->device_id == 0) {
|
||||
ts->dd->data_size = MAX_FINGERS * ts->dd->touch_bytes + ts->dd->touch_meta_data;
|
||||
ts->dd->touch_index = 0;
|
||||
}
|
||||
|
||||
ts->touch_data = kzalloc(ts->dd->data_size, GFP_KERNEL);
|
||||
if (!ts->touch_data) {
|
||||
pr_err("%s: Unable to allocate memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
||||
input_device = input_allocate_device();
|
||||
if (!input_device) {
|
||||
rc = -ENOMEM;
|
||||
goto error_alloc_dev;
|
||||
}
|
||||
|
||||
ts->input = input_device;
|
||||
input_device->name = GSLX680_I2C_NAME;
|
||||
input_device->id.bustype = BUS_I2C;
|
||||
input_device->dev.parent = &client->dev;
|
||||
input_set_drvdata(input_device, ts);
|
||||
|
||||
#ifdef REPORT_DATA_ANDROID_4_0
|
||||
__set_bit(EV_ABS, input_device->evbit);
|
||||
__set_bit(EV_KEY, input_device->evbit);
|
||||
__set_bit(EV_REP, input_device->evbit);
|
||||
__set_bit(INPUT_PROP_DIRECT, input_device->propbit);
|
||||
input_mt_init_slots(input_device, (MAX_CONTACTS+1), 0);
|
||||
#else
|
||||
input_set_abs_params(input_device, ABS_MT_TRACKING_ID, 0, (MAX_CONTACTS+1), 0, 0);
|
||||
set_bit(EV_ABS, input_device->evbit);
|
||||
set_bit(EV_KEY, input_device->evbit);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TOUCH_KEY
|
||||
input_device->evbit[0] = BIT_MASK(EV_KEY);
|
||||
for (i = 0; i < MAX_KEY_NUM; i++)
|
||||
set_bit(key_array[i], input_device->keybit);
|
||||
#endif
|
||||
|
||||
set_bit(ABS_MT_POSITION_X, input_device->absbit);
|
||||
set_bit(ABS_MT_POSITION_Y, input_device->absbit);
|
||||
set_bit(ABS_MT_TOUCH_MAJOR, input_device->absbit);
|
||||
set_bit(ABS_MT_WIDTH_MAJOR, input_device->absbit);
|
||||
#ifdef CONFIG_MACH_RK_FAC
|
||||
input_set_abs_params(input_device, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
|
||||
input_set_abs_params(input_device, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
|
||||
#else
|
||||
input_set_abs_params(input_device, ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
|
||||
input_set_abs_params(input_device, ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
|
||||
#endif
|
||||
input_set_abs_params(input_device, ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
|
||||
input_set_abs_params(input_device, ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
|
||||
|
||||
client->irq = ts->irq;
|
||||
|
||||
ts->wq = create_singlethread_workqueue("kworkqueue_ts");
|
||||
if (!ts->wq) {
|
||||
dev_err(&client->dev, "Could not create workqueue\n");
|
||||
goto error_wq_create;
|
||||
}
|
||||
flush_workqueue(ts->wq);
|
||||
|
||||
INIT_WORK(&ts->work, gsl_ts_xy_worker);
|
||||
|
||||
rc = input_register_device(input_device);
|
||||
if (rc)
|
||||
goto error_unreg_device;
|
||||
|
||||
return 0;
|
||||
|
||||
error_unreg_device:
|
||||
destroy_workqueue(ts->wq);
|
||||
error_wq_create:
|
||||
input_free_device(input_device);
|
||||
error_alloc_dev:
|
||||
kfree(ts->touch_data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
#if 1
|
||||
static int gsl_ts_suspend(void)
|
||||
{
|
||||
struct gsl_ts *ts = g_gsl_ts;
|
||||
printk("I'am in gsl_ts_suspend() start\n");
|
||||
flush_workqueue(ts->wq);
|
||||
#ifdef GSL_TIMER
|
||||
printk("gsl_ts_suspend () : delete gsl_timer\n");
|
||||
del_timer(&ts->gsl_timer);
|
||||
#endif
|
||||
disable_irq_nosync(ts->irq);
|
||||
gslX680_shutdown_low();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gsl_ts_resume(void)
|
||||
{
|
||||
struct gsl_ts *ts = g_gsl_ts;
|
||||
int i = 0;
|
||||
|
||||
printk("I'am in gsl_ts_resume() start\n");
|
||||
|
||||
gslX680_shutdown_high();
|
||||
msleep(20);
|
||||
reset_chip(ts->client);
|
||||
startup_chip(ts->client);
|
||||
check_mem_data(ts->client);
|
||||
|
||||
msleep(100);
|
||||
reset_chip(ts->client);
|
||||
startup_chip(ts->client);
|
||||
msleep(100);
|
||||
reset_chip(ts->client);
|
||||
startup_chip(ts->client);
|
||||
#ifdef GSL_TIMER
|
||||
printk("gsl_ts_resume () : add gsl_timer\n");
|
||||
init_timer(&ts->gsl_timer);
|
||||
ts->gsl_timer.expires = jiffies + 3 * HZ;
|
||||
ts->gsl_timer.function = &gsl_timer_handle;
|
||||
ts->gsl_timer.data = (unsigned long)ts;
|
||||
add_timer(&ts->gsl_timer);
|
||||
#endif
|
||||
|
||||
for (i = 1; i <= MAX_CONTACTS; i++) {
|
||||
if (0 != id_state_old_flag[i]) {
|
||||
#ifdef REPORT_DATA_ANDROID_4_0
|
||||
input_mt_slot(ts->input, i);
|
||||
input_report_abs(ts->input, ABS_MT_TRACKING_ID, -1);
|
||||
input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false);
|
||||
input_sync(ts->input);
|
||||
#endif
|
||||
id_sign[i] = 0;
|
||||
}
|
||||
id_state_old_flag[i] = id_state_flag[i] = 0;
|
||||
}
|
||||
enable_irq(ts->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gsl_ts_fb_event_notify(struct notifier_block *self,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct fb_event *event = data;
|
||||
int blank_mode = *((int *)event->data);
|
||||
|
||||
if (action == FB_EARLY_EVENT_BLANK) {
|
||||
switch (blank_mode) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
break;
|
||||
default:
|
||||
gsl_ts_suspend();
|
||||
break;
|
||||
}
|
||||
} else if (action == FB_EVENT_BLANK) {
|
||||
switch (blank_mode) {
|
||||
case FB_BLANK_UNBLANK:
|
||||
gsl_ts_resume();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block gsl_ts_fb_notifier = {
|
||||
.notifier_call = gsl_ts_fb_event_notify,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int gslx680_config_hw(struct gsl_ts *ts)
|
||||
{
|
||||
struct device_node *np;
|
||||
enum of_gpio_flags rst_flags;
|
||||
unsigned long irq_flags;
|
||||
unsigned int irq_gpio;
|
||||
struct device *dev;
|
||||
|
||||
dev = &ts->client->dev;
|
||||
np = dev->of_node;
|
||||
|
||||
irq_gpio = of_get_named_gpio_flags(np, "touch-gpio", 0, (enum of_gpio_flags *)&irq_flags);
|
||||
ts->irq = gpio_to_irq(irq_gpio);
|
||||
ts->reset_gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &rst_flags);
|
||||
|
||||
if (gpio_request(ts->reset_gpio, NULL) != 0) {
|
||||
gpio_free(ts->reset_gpio);
|
||||
printk("gslx680_init_platform_hw gpio_request error\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (gpio_request(irq_gpio, NULL) != 0) {
|
||||
gpio_free(irq_gpio);
|
||||
printk("gslx680_init_platform_hw gpio_request error\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
gpio_direction_output(ts->reset_gpio, GPIO_HIGH);
|
||||
mdelay(10);
|
||||
gpio_set_value(ts->reset_gpio, GPIO_LOW);
|
||||
mdelay(10);
|
||||
gpio_set_value(ts->reset_gpio, GPIO_HIGH);
|
||||
msleep(300);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int gsl_ts_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct gsl_ts *ts;
|
||||
int rc;
|
||||
u8 read_buf = 0;
|
||||
int ret;
|
||||
|
||||
printk("GSLX680 Enter %s\n", __func__);
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "I2C functionality not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
|
||||
if (!ts)
|
||||
return -ENOMEM;
|
||||
printk("==kzalloc success=\n");
|
||||
g_gsl_ts = ts;
|
||||
|
||||
ts->client = client;
|
||||
ts->device_id = id->driver_data;
|
||||
|
||||
gslx680_config_hw(ts);
|
||||
ts_global_reset_pin = ts->reset_gpio;
|
||||
i2c_set_clientdata(client, ts);
|
||||
|
||||
rc = gsl_ts_init_ts(client, ts);
|
||||
if (rc < 0) {
|
||||
dev_err(&client->dev, "GSLX680 init failed\n");
|
||||
goto error_mutex_destroy;
|
||||
}
|
||||
|
||||
init_chip(ts->client);
|
||||
check_mem_data(ts->client);
|
||||
|
||||
rc = request_irq(client->irq, gsl_ts_irq, IRQF_TRIGGER_RISING, client->name, ts);
|
||||
if (rc < 0) {
|
||||
printk("gsl_probe: request irq failed\n");
|
||||
goto error_req_irq_fail;
|
||||
}
|
||||
|
||||
disable_irq(client->irq);
|
||||
|
||||
ret = gsl_ts_read(client, 0xf0, &read_buf, sizeof(read_buf));
|
||||
if (ret < 0) {
|
||||
pr_info("gslx680 I2C transfer error!\n");
|
||||
goto error_req_irq_fail;
|
||||
}
|
||||
|
||||
#ifdef GSL_TIMER
|
||||
printk("gsl_ts_probe () : add gsl_timer\n");
|
||||
|
||||
init_timer(&ts->gsl_timer);
|
||||
ts->gsl_timer.expires = jiffies + 3 * HZ;
|
||||
ts->gsl_timer.function = &gsl_timer_handle;
|
||||
ts->gsl_timer.data = (unsigned long)ts;
|
||||
add_timer(&ts->gsl_timer);
|
||||
#endif
|
||||
fb_register_client(&gsl_ts_fb_notifier);
|
||||
|
||||
printk("[GSLX680] End %s\n", __func__);
|
||||
|
||||
return 0;
|
||||
|
||||
error_req_irq_fail:
|
||||
free_irq(ts->irq, ts);
|
||||
|
||||
error_mutex_destroy:
|
||||
input_free_device(ts->input);
|
||||
kfree(ts);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int gsl_ts_remove(struct i2c_client *client)
|
||||
{
|
||||
struct gsl_ts *ts = i2c_get_clientdata(client);
|
||||
printk("==gsl_ts_remove=\n");
|
||||
device_init_wakeup(&client->dev, 0);
|
||||
cancel_work_sync(&ts->work);
|
||||
free_irq(ts->irq, ts);
|
||||
destroy_workqueue(ts->wq);
|
||||
input_unregister_device(ts->input);
|
||||
|
||||
kfree(ts->touch_data);
|
||||
kfree(ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id gsl_ts_id[] = {
|
||||
{GSLX680_I2C_NAME, 0},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, gsl_ts_id);
|
||||
|
||||
static struct of_device_id gslX680_dt_ids[] = {
|
||||
{ .compatible = "gslX680" },
|
||||
};
|
||||
|
||||
static struct i2c_driver gsl_ts_driver = {
|
||||
.driver = {
|
||||
.name = GSLX680_I2C_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(gslX680_dt_ids),
|
||||
},
|
||||
.probe = gsl_ts_probe,
|
||||
.remove = gsl_ts_remove,
|
||||
.id_table = gsl_ts_id,
|
||||
};
|
||||
|
||||
static int __init gsl_ts_init(void)
|
||||
{
|
||||
int ret;
|
||||
printk("==gsl_ts_init==\n");
|
||||
ret = i2c_add_driver(&gsl_ts_driver);
|
||||
printk("ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
static void __exit gsl_ts_exit(void)
|
||||
{
|
||||
printk("==gsl_ts_exit==\n");
|
||||
i2c_del_driver(&gsl_ts_driver);
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(gsl_ts_init);
|
||||
module_exit(gsl_ts_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("GSLX680 touchscreen controller driver");
|
||||
MODULE_AUTHOR("Guan Yuwei, guanyuwei@basewin.com");
|
||||
MODULE_ALIAS("platform:gsl_ts");
|
||||
9558
drivers/input/touchscreen/rockchip_gslX680_rk3128.h
Executable file
9558
drivers/input/touchscreen/rockchip_gslX680_rk3128.h
Executable file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user