Because the customer is useful to the gsl1680 7 inch capacitive screen, so took a piece come over, in the 329XX platform above start debugging.
Probably browsed the information provided, only the information about the module and a Chinese version of the Datasheet,datasheet just said a general, did not mention the reading of touch coordinates register. But fortunately there is a driver on the other processor platform, so read the coordinates of the part of the code to be ported over.
gsl1680 interface with other capacitive screen, is also i²c interface, it seems that the market capacitive screen is I²c interface, capacitive screen with a microcontroller MCU, with processing samples, coordinate conversion, and some jitter algorithm processing, after the coordinates are saved in a fixed register inside, An interrupt signal is then output to the pin pin, which informs the master to read the coordinates. But the hand to get this is no flash inside, that itself without firmware, the initialization to rely on the main control will firmware through the interface loaded into the touch screen RAM, then the capacitive screen to work properly. Personally think this way has two disadvantages: 1.firmware has more than 8,000 values, loading needs to spend about 10s, increase the boot time (later can be the I²c clk tune to 400K try) ; 2. Without the firmware itself, need to load to work, no doubt to increase the difficulty of debugging. However, relative resistance screen, capacitive screen debugging is relatively simple, do not have to deal with sampling/conversion, as well as interference/jitter and other issues. Capacitive screen, comes with the MCU, so these work has been done for you, it is very convenient.
Below we specifically first look at gsl1680 hardware module interface, a total of 12 pin, valid only 6 pin, respectively is Gnd,vcc,sda,scl,io cntl,int.
1----GND 2-----NC
3----NC 4-----NC
5----NC 6-----GND
7----SDA 8-----SCL
9----IO CNTL-----INT
----VDD-----VDD
Simply explain:
1,6:pin Connect GND;
2,3,4,5 Floating
7,8 I²c Interface
9 IO Cntl Hardware Reset/wake Pin
INT Interrupts pin Pin
11,12 VCC Connection 3.0 or 3.3V
Understanding the above hardware interface, the touch screen needs to occupy the main hardware resources are: I²C interface, an external interrupt, a gpio (used to control the touch screen hardware reset/power down into the Power saving mode) can complete the touch screen coordinates obtained.
Let's start with the drive-specific process.
1.module_init function inside, register platform equipment platform device;
2. Register platform device driver;
static struct Platform_device Gp_tp_device = {
. Name = "GP_TP",
. id =-1,
. Dev = {
. Release = Gp_tp_device_release,
}
};
static struct Platform_driver Gp_tp_driver = {
. Driver = {
. Name = "GP_TP",
. Owner = This_module,
},
. Probe = Gp_tp_probe,
. remove = Gp_tp_remove,
. Suspend = Gp_tp_suspend,
. Resume = Gp_tp_resume,
};
The probe function in the platform_driver above will do several things:
1) Create a single kernel thread, register kernel thread functions, interrupt the reading of the touch screen coordinates of the lower half, and escalate the coordinate values to the Linux input subsystem;
Create a task queue kernel thread by calling the Create_singlethread_workqueue API;
2) Create an event device, the coordinates obtained from the touchscreen will be escalated to the event, and the user layer will read from the event to the touch-screen coordinates;
3) applications for i²c devices; for communication with touch screen and loading firmware;
4) apply for a GPIO port to control the touch screen reset/wake, that is, to receive 9 IO CNTL pin pin;
5) Software/hardware reset touch screen, load firmware;
6) Apply/Register the external interrupt function;
The above is done in the probe function, the next step is to wait for the touch screen press, and then interrupt function to notify the kernel thread function to read the coordinates of the touch, escalated to the event,
It is also the process of continuous recycling.
The complete implementation code for the touch screen driver probe function is as follows:
/** Device driver probe*/
static int __init gp_tp_probe (struct platform_device *pdev)
{
int RC;
int ret = 0;
int Intidx, SLAVEADDR;
int io_wake=-1;
gpio_content_t CTX;
unsigned int debounce = 1;//27000; /*1ms*/
gp_board_touch_t *touch_config = NULL;
Print_info ("Entering gp_tp_probe\n");
#ifdef Virtual_keys
Virtual_keys_init ();
#endif
memset (&ts, 0, sizeof (gp_tp_t));
/* Create single thread Work Queue */
Ts.touch_wq = Create_singlethread_workqueue ("Touch_wq");
if (!TS.TOUCH_WQ)
{
Print_info ("%s Unable to create single thread work queue\n", __func__);
ret =-enomem;
Goto __err_work_queue;
}
Init_work (&ts.mt_set_nice_work, gp_mt_set_nice_work);
Queue_work (Ts.touch_wq, &ts.mt_set_nice_work);
Ts.dev = Input_allocate_device ();
if (Null==ts.dev) {
Print_info ("Unable to alloc input device\n");
ret =-enomem;
Goto __err_alloc;
}
I2c_request:
Gp_i2c_handle = Gslx680_i2c_request ();
if (Gp_i2c_handle = =-1) {
Diag_error ("Cap Touch panel IIC request error!\n");
Goto I2c_request;
Return-enomem;
}
__set_bit (Ev_abs, ts.dev->evbit);
Input_set_abs_params (Ts.dev, abs_mt_position_x, 0, screen_max_x-1, 0, 0);
Input_set_abs_params (Ts.dev, abs_mt_position_y, 0, screen_max_y-1, 0, 0);
Input_set_abs_params (Ts.dev, abs_mt_tracking_id, 0, (max_contacts + 1), 0, 0);
Input_set_abs_params (Ts.dev, abs_mt_touch_major, 0, 255, 0, 0);
Input_set_capability (Ts.dev, Ev_key, Key_back);
Input_set_capability (Ts.dev, Ev_key, key_home);
Input_set_capability (Ts.dev, Ev_key, Key_menu);
Ts.dev->name = "Gp_ts";
Ts.dev->phys = "Gp_ts";
Ts.dev->id.bustype = BUS_I2C;
/* All went OK, so register to the input system */
rc = Input_register_device (Ts.dev);
if (RC) {
ret =-eio;
Goto __err_reg_input;
}
/* Request CPT Reset pin*/
Intidx = Mk_gpio_index (Rst_channel, Rst_func, Rst_gid, Rst_pin);
Touch_reset = Gp_gpio_request (Intidx, "Touch_reset"); /* GPIO1[7]----*/
if (Is_err ((void*) touch_reset)) {
Print_info ("%s Unable to register client\n", __func__);
ret =-enomem;
Goto __err_register;
}
Gp_gpio_set_output (Touch_reset, 1,0);
Dbg_print ("=======gslx680 CTP test=====\n");
Gp_i2c_handle = Gslx680_i2c_request ();
if (Gp_i2c_handle = =-1) {
Diag_error ("Cap Touch panel IIC request error!\n");
Return-enomem;
}
Gp_gpio_set_output (Touch_reset, 0,0);
Msleep (100);
Gp_gpio_set_output (Touch_reset, 1,0);
Msleep (100);
Reset_chip ();
GP_LOAD_CTP_FW ();
Startup_chip ();
Msleep (50);
Reset_chip ();
Startup_chip ();
Gp_i2c_bus_release (Gp_i2c_handle);
Init_work (&ts.mt_work, gp_multi_touch_work);
Intidx = Mk_gpio_index (Int_irq_channel, Int_irq_func, Int_irq_gid, Int_irq_pin);
Ts.client = Gp_gpio_request (Intidx, "touch_int"); /* GPIO1[7]----*/
if (Is_err ((void*) ts.client)) {
Print_info ("%s Unable to register client\n", __func__);
ret =-enomem;
Goto __err_register;
}
Gp_gpio_set_input (Ts.client, Gpio_pull_low);
Gp_gpio_irq_property (Ts.client, gpio_irq_edge_trigger| Gpio_irq_active_rising, &debounce);
GP_GPIO_REGISTER_ISR (Ts.client, Gp_ts_callback, (void *) ts.client);
Print_info ("End gp_tp_probe\n");
return 0;
__err_register:
Input_unregister_device (Ts.dev);
__err_reg_input:
Gp_ti2c_bus_release (Ts.i2c_handle);
__ERR_I2C:
Kfree (Ts.i2c_handle);
__err_i2c_allocate:
Gp_gpio_release (Ts.touch_reset);
__err_pin_request:
Input_free_device (Ts.dev);
__err_alloc:
Destroy_workqueue (TS.TOUCH_WQ);
__err_work_queue:
return ret;
}
the touch screen press the interrupt handler function as shown below
/**
* Interrupt Callback
*/
void Gp_ts_callback (void* client)
{
GP_GPIO_ENABLE_IRQ (ts.client, 0);
Queue_work (Ts.touch_wq, &ts.mt_work);
}
The interrupt mechanism for Linux is generally divided into two parts: the top half and the lower half. The upper half of the work should generally be as small and fast as possible, while the heavy, cumbersome and long-handled work is left in the lower part to deal with. So, the task performed on the top half is relatively easy, just clearing out the external midrange status register, and then dispatching the next half of the operation.
Let's take a look at the bottom half of the interrupt by touching the screen:
static void
Gp_mt_set_nice_work (
struct Work_struct *work
)
{
Print_info ("[%s:%d]\n", __function__, __line__);
Set_user_nice (Current,-20);
}
static inline unsigned int join_bytes (unsigned char A, unsigned char b)
{
unsigned int ab = 0;
AB = AB | A
AB = AB << 8 | b
return AB;
}
static void
Gp_multi_touch_work (
struct Work_struct *work
)
{
int I,ret;
Char touched, ID;
unsigned short x, y;
unsigned int pending;
int irq_state;
Char tp_data[(multi_tp_points + 1)];
Print_info ("WQ gp_multi_touch_work.\n");
#if adjust_cpu_freq
Clockstatus_configure (clock_status_touch,1);
#endif
ret = Gsl_ts_read (0x80, Tp_data, sizeof (Tp_data));
if (Ret < 0) {
Print_info ("Gp_tp_get_data fail,return%d\n", ret);
GP_GPIO_ENABLE_IRQ (ts.client, 1);
Return
}
touched = (tp_data[0]< multi_tp_points tp_data[0]: multi_tp_points);
for (i=1;i<=max_contacts;i++) {
Id_state_flag[i] = 0;
}
PRINTK ("point =%d", touched);
for (i = 0; i < touched; i++) {
id = tp_data[4 * (i + 1) + 3] >> 4;
x = Join_bytes (Tp_data[4 * (i + 1) + 3] & 0xf,tp_data[4 * (i + 1) + 2]);
y = join_bytes (tp_data[4 * (i + 1) + 1],tp_data[4 * (i + 1) + 0]);
if (1 <= ID && ID <= max_contacts) {
Record_point (x, y, id);
Report_data (X_new, y_new, ten, id);
Id_state_flag[id] = 1;
}
}
if (touched = = 0) {
Input_mt_sync (Ts.dev);
}
for (i=1;i<=max_contacts;i++)
{
if ((0 = = touched) | | ((0! = Id_state_old_flag[i]) && (0 = = Id_state_flag[i])))
{
id_sign[i]=0;
}
Id_state_old_flag[i] = Id_state_flag[i];
}
#if adjust_cpu_freq
if (touched = = 0) {
Clockstatus_configure (clock_status_touch,0);
}
#endif
ts.prev_touched = touched;
Input_sync (Ts.dev);
__error_check_touch_int:
__error_get_mt_data:
/* Clear Interrupt Flag */
Pending = (1 << gpio_pin_number (ts.intioindex));
Gphalgpiosetintpending (Ts.intioindex, pending);
GP_GPIO_ENABLE_IRQ (ts.client, 1);
}
First from the touch screen controller 0x80 Register start reading 24 byte, and then the data will be read back to parse, get the current touch points, coordinates, etc., after the relevant processing, escalated to the event. Because it is collecting multipoint coordinates and then processing the coordinates of these points together, we report a point to call Input_mt_sync until the coordinates of all currently pressed points are escalated, and then call the Input_sync function to synchronize.
The above analysis of the gsl1680 capacitive screen Linux drive, in fact, the drive process of capacitive screen is similar, the processing process is similar, with Universal.
Before also debugging a pier Thai ft5x06 capacitive screen, this is relatively simple, initialization without loading firmware, the interface is almost the same, just ft5x06 the finger when the interrupt output pin is low, but gsl1680 this finger press interrupt signal for the periodic square wave.
The above is for reference only, the deficiency also please correct me.
Drive debugging analysis of capacitive screen gsl1680 based on GPL329XX Linux platform