Several of the previous articles have been ported by configuring DTS for multiple drives, and then we are addressing tq335x's touch-driven issues. For various reasons, tq335x touch screen drive is provided by the module, and the Linux official kernel also does not have the drive source code with the touchscreen, the simple configuration of DTS is unable to complete the tq335x touch-driven porting work, therefore, this article refers to the core of the original pixcir_i2c_ The TS driver writes the tq335x Touch screen (TN92) driver.
Before porting TQ210, I have written the TQ210 touch screen driver, my tq335x is still using the TQ210 screen, therefore, the difficulty is not very big. It is important to note that the understanding of the multi-touch protocol is not sufficiently deep in the TQ210 drive porting, when the driver single touch was written to work normally, but the multi-touch was incorrect (this time writing tq335x's touch drive was realized). But the written TQ210 drive Multitouch actually uses the multi-touch a protocol, but in the wrong place, this article based on Tq335x's rewritten touch drive is written according to the multi-touch B protocol, using the Tslib test normally, at the end of the article.
TN92 touch screen using the touch chip is GT811, below we analyze the touch screen driver writing.
(1) View schematic diagram
As you can see from the touchscreen schematic, there are four pins connected to the GT811 board, namely SDA, SDL, int, and reset. Where I2C_SDA and i2c_sdl are connected to the I2C1 port on the am335x to communicate with the SOC, the int pin is connected to the 27th pin of the GPIO1, and when touch is detected, the GT811 initiates an interrupt request to the SOC via this pin The reset pin on the GPIO1 26th pin of the SOC is used to receive the SOC reset operation, and for this article, the SOC is am335x.
Where the PIN connection information for the GT811 and Soc can be found from the backplane schematic, SDA and SCL I will not be posted, the connection between int and reset is as follows:
The YP is connected to the reset foot of the GT811, then through the short-circuit cap and the gpio1_26 link, the YM is connected to the GT811 int pin, via the short-circuit cap and the gpio1_27 link, therefore, the gpio1_27 needs to be configured as the terminal input pin, gpio1_ 26 is configured as an output pin. In addition, view GT811 's chip manuals for information on the operation of INT and reset:
1. When touch is detected, the GT811 pulls down the interrupt pin, so the gpio1_27 needs to be configured for a falling edge trigger. 2. The GT811 reset pin is active low, so you need to pull down the reset pin when you power up. 3. The GT811 reset pin comes with a pull-up, so use gpio1_26 to switch the GT811 reset to the suspended input too.
With this information, we can start analyzing the drive structure.
(2) DTS Configuration Platform Information
With the previous analysis, we know that we need to configure the am335x four pins to make the GT811 work properly. Wherein, the GT811 through the I²c interface to the am335x i2c1, therefore, the need to configure the i2c1 of the am335x two pin for the I²c function, the gpio1_27 needs to be configured as interrupt input, falling edge trigger, the interrupt number can also be determined, is the GPIO1 27th horn (the core can convert the PIN to the interrupt number), and finally the reset foot, the driver initialization GT811 need to operate the reset pin, and GT811 to pull the low reset, it can be GPIO1 26 angle set to the output level state. Learning from the previous articles, we know that DTS can configure Pinmux, then analyze the DTS files that the kernel comes with, and DTS can also pass the connection information to the kernel. After analysis and reference, my most Tq335x.dts file made the following changes:
Step1. Check the Pinmux configuration of the i²c pin
Find i2c1 can find the I2C1 node, the pinctrl-0 of the node only want to Phandler on the i2c1 of the two pins are related to the configuration, therefore, no modification is required.
Step2. Configuring the int and reset pins
Add PIN configuration information within the AM33XX_PINMUX node, as follows:
gt811_ts_pins:gt811_ts_pins {pinctrl-single,pins = <0x68 (Pin_input_pullup | Mux_mode7) 0x6c (Pin_input_pullup | MUX_MODE7) >;};
Step3. Adding GT811 device information within the I2C1 node
GT811 device node needs to provide the following information, i²c device address, PINMUX configuration, interrupt information, screen size, and so on, as follows (here is not detailed, what is unclear can leave a message to discuss).
[Email protected] {compatible = "Gt811,gt811_ts";p inctrl-names = "Default";p inctrl-0 = <>811_ts_pins>;reg = <0x5d>; Interrupt-parent = <&gpio1>;interrupts = <27 2>;gpios = <&gpio1-0>;touchscreen-size-x = < 800>;touchscreen-size-y = <480>;touchscreen-swap = <1>;touchscreen-revert-x = <1>; Touchscreen-revert-y = <1>;};
At this point, the configuration of the DTS is complete, the following is the GT811 driver writing.
(3) driver writing
Drive to write the root before the TQ210, there is not much change, is the use of the new I²C device driver architecture, the important difference is that the support of multi-touch, the driver of the detailed analysis I will not say, specifically can refer to Vedon Teacher's video tutorial (absolute value for money). Below is GT811 's multi-touch driver source code. From the GT811 device node to obtain the coordinates of the part I directly posted out, complete code or please to download the resources, or a bit expensive, but this drive can be used directly, do not need any modification. The following is an incomplete code that prints out the touch point coordinates that have been written out of the core of this drive. In fact, many friends do not need to download the source code can be supplemented to improve this driver, and I sincerely hope to read this article friends do not need to download the source code can write their own touch drive.
#include <linux/module.h> #include <linux/i2c.h> #include <linux/platform_device.h> #include < linux/gpio.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_gpio.h># Include <linux/input.h> #include <linux/input/mt.h> #include <linux/interrupt.h> #include <linux /delay.h> #include <linux/io.h>struct gt811_ts_platdata{u32 size_x;u32 size_y;u32 size_p;u32 swap;u32 Revert_ X;u32 revert_y;u32 reset_pin;u32 interrupt_pin;u32 ponits_max;struct i2c_client *client;struct input_dev *input;struct Work_struct work;}; static const struct OF_DEVICE_ID gt811_ts_of_match[] = {{. compatible = ' Gt811,gt811_ts ',. Data = NULL},{}};static int i 2c_write_bytes (struct i2c_client *client, uint8_t *data, int len) {struct i2c_msg msg;msg.flags=! I2c_m_rd;msg.addr=client->addr;msg.len=len;msg.buf=data;return I2c_transfer (client->adapter,&msg, 1);} static int i2c_read_bytes (struct i2c_client *client, uint8_t *buf, int len) {sTruct i2c_msg msgs[2];msgs[0].flags=! I2C_M_RD;MSGS[0].ADDR=CLIENT->ADDR;MSGS[0].LEN=2;MSGS[0].BUF=&BUF[0];MSGS[1].FLAGS=I2C_M_RD;MSGS[1]. Addr=client->addr;msgs[1].len=len-2;msgs[1].buf=&buf[2];return I2c_transfer (CLIENT->ADAPTER,MSGS, 2);} static void Gt811_ts_handler (struct work_struct *work) {struct Gt811_ts_platdata *pdata = container_of (work, struct gt811 _ts_platdata, work); struct device *dev = &pdata->client->dev;uint8_t buffer[36] = {0x07, 0x21, 0};uint8_t count , index, flags, Position;int x, y;buffer[0] = 0x0f;buffer[1] = 0xff;if (I2c_write_bytes (pdata->client,buffer,2) < 0) {Dev_err (dev, "Failed to write Wakeup message.\n"); goto REENABLE_IRQ;} Buffer[0] = 0x07;buffer[1] = 0x21;if (i2c_read_bytes (pdata->client, buffer, sizeof (buffer)) < 0) {Dev_err (dev, "Fai led to read touch message.\n "); goto REENABLE_IRQ;} Buffer[0] = 0x80;buffer[1] = 0x00;if (i2c_write_bytes (pdata->client, buffer, 2) < 0) {Dev_err (dev, "Failed to write Sleep message.\n "); goto REENABLE_IRQ;} BUFFER[25] = buffer[19];buffer[19] = 0;flags = Buffer[2]&0x1f;while (Flags) {if (! ( flags&0x1)) {continue;} if (Index < 3) {position = 4 + index * 5;} Else{position = + (index-3) * 5;} x = (Buffer[position] << 8) | Buffer[position + 1];y = (buffer[position + 2] << 8) | Buffer[position + 3];if (pdata->swap) {swap (x, y);} if (pdata->revert_x) {x = Pdata->size_x-x;} if (pdata->revert_y) {y = pdata->size_y-y;} PRINTK ("point: (x:%03d, y:%03d) \ n", x, y);} The touch point information detected by the organization is escalated to the input subsystem node to REENABLE_IRQ:ENABLE_IRQ (PDATA->CLIENT->IRQ);} static irqreturn_t Gt811_ts_isr (int irq, void *dev_id) {struct gt811_ts_platdata* pdata = (struct gt811_ts_platdata*) dev_ Id;disable_irq_nosync (PDATA->CLIENT->IRQ); Schedule_work (&pdata->work); return IRQ_HANDLED;} static int gt811_ts_initilize (struct i2c_client *client) {struct device *dev = &client->dev;struct gt811_ts_ Platdata *pdata = (struct gt811_ts_platdata*) i2c_get_clientdata (client); int STatus = 0, Count = 0;uint8_t version[4] = {0x7, 0x17, 0};uint8_t config[] = {0x06,0xa2,0x12,0x10,0x0e,0x0c,0x0a,0x08,0x06, 0X04,0X02,0X00,0XE2,0X53,0XD2,0X53,0XC2,0X53,0XB2,0X53,0XA2,0X53,0X92,0X53,0X82,0X53,0X72,0X53,0X62,0X53,0X52, 0x53,0x42,0x53,0x32,0x53,0x22,0x53,0x12,0x53,0x02,0x53,0xf2,0x53,0x0f,0x13,0x40,0x40,0x40,0x10,0x10,0x10,0x0f, 0x0f,0x0a,0x35,0x25,0x0c,0x03,0x00,0x05,0x20,0x03,0xe0,0x01,0x00,0x00,0x34,0x2c,0x36,0x2e,0x00,0x00,0x03,0x19, 0x03,0x08,0x00,0x00,0x00,0x00,0x00,0x14,0x10,0xec,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0d, 0X40,0X30,0X3C,0X28,0X00,0X00,0X00,0X00,0XC0,0X12,0X01};CONFIG[62] = 480 >> 8;config[61] = 480 & 0xff;config [+] = >> 8;config[63] =!gpio_is_valid & 0xff;if (pdata->reset_pin) {dev_err (dev, "The Reset pin nu Mber is invalid.\n "); return-einval;} Count = 3;while (count--) {gpio_direction_output (pdata->reset_pin, 0); Msleep (gpio_direction_output); pdata- >reset_pin, 1); Msleep (+); if (I2c_read_bytes (Client, version, sizeof (version)) < 0) {Dev_err (dev, "Failed to get the version of GT811, try again...\n"); status =-en Odev;} else {dev_info (dev, "Gt811 detected, version (%04x) ... \ n", (version[2]<<8) |version[3]); status = 0;break;}} if (status) {return status;} Count = 3;while (count--) {if (i2c_write_bytes (client, config, sizeof (config)) < 0) {Dev_err (dev, "Failed to configure The GT811, try again...\n "); status =-einval;} else {dev_info (dev, "Gt811 configue succeed\n"); status = 0;break;}} return status;} static struct Gt811_ts_platdata *gt811_ts_parse_devtree (struct i2c_client *client) {struct device *dev = &client- >dev;struct device_node *node;struct gt811_ts_platdata *pdata;enum of_gpio_flags flags;node = dev->of_node;if (! node) {dev_err (dev, "The Of_node is null.\n"); return err_ptr (-enodev);} pdata = Devm_kzalloc (dev, sizeof (struct device_node), Gfp_kernel), if (!pdata) {dev_err (dev, "No enough Memory left.\n"); r Eturn err_ptr (-ENOMEM);} Pdata->reset_pin = Of_get_gpio_flags (node, 0, &flags), if (Pdata->reset_pin < 0) {Dev_err (dev, "Get RST pin failed!\n"), Return Err_ptr (-einval );} if (OF_PROPERTY_READ_U32 (node, "Touchscreen-size-x", &pdata->size_x)) {Dev_err (dev, "Failed to get the touch scre En x size.\n "); return err_ptr (-einval);} if (OF_PROPERTY_READ_U32 (node, "Touchscreen-size-y", &pdata->size_y)) {Dev_err (dev, "Failed to get the touch Screen y size.\n "); return err_ptr (-einval);} if (OF_PROPERTY_READ_U32 (node, "Touchscreen-size-p", &pdata->size_p)) {pdata->size_p = 255;} if (OF_PROPERTY_READ_U32 (node, "Touchscreen-swap", &pdata->swap)) {pdata->swap = 1;} if (OF_PROPERTY_READ_U32 (node, "Touchscreen-revert-x", &pdata->revert_x)) {pdata->revert_x = 1;} if (OF_PROPERTY_READ_U32 (node, "Touchscreen-revert-x", &pdata->revert_y)) {pdata->revert_y = 1;} return pdata;} static int gt811_ts_probe (struct i2c_client *client, const struct i2c_device_id *id) {struct device *dev = &client-> Dev;structGt811_ts_platdata *pdata = dev_get_platdata (dev), struct input_dev *input;int error = 0;u32 *p = null;if (!of_match_device ( Of_match_ptr (Gt811_ts_of_match), dev) {dev_err (dev, "Failed to match.\n"); return-einval;} if (!pdata) {pdata = Gt811_ts_parse_devtree (client), if (Is_err (pdata)) {Dev_err (dev, "Get device data from device tree FAI led!\n "); error =-einval;goto failed_exit;}} p = (u32*) ioremap (0x44e1086c, 4), if (NULL = = p) {dev_err (dev, "Failed to pull up the interrupt pin.\n"); goto Failed_exit;} *p &= ~ (1<<3); *p |= 1<<4;pdata->client = client;i2c_set_clientdata (client, pdata); input = Devm_input _allocate_device (Dev), if (!input) {dev_err (dev, "Failed to allocate input device\n"); error =-enomem;goto pdata_free;} Pdata->input = Input;input->name = Client->name;input->id.bustype = Bus_i2c;input->id.product = 0xBEEF; Input->id.vendor =0xdead;input->dev.parent = &client->dev;__set_bit (EV_KEY, input->evbit); __set_ Bit (ev_abs, input->evbit); __Set_bit (Btn_touch, input->keybit); Input_set_abs_params (input, abs_x, 0, pdata->size_x, 0, 0); Input_set_abs_ params (input, abs_y, 0, pdata->size_y, 0, 0); Input_set_abs_params (input, abs_mt_position_x, 0, pdata->size_x, 0, 0 ); Input_set_abs_params (input, abs_mt_position_y, 0, pdata->size_y, 0, 0); error = Input_mt_init_slots (input, 5, input _mt_direct | input_mt_drop_unused); if (error) {Dev_err (dev, "Failed to initialize the multi-touch slots.\n"); goto Input_free;} Input_set_drvdata (input, pdata); error = Input_register_device (input), if (error) {Dev_err (dev, "register input device failed!\n "); goto Input_free;} if (gt811_ts_initilize (client)) {Dev_err (dev, "Failed to initialize gt811.\n");} Init_work (&pdata->work, gt811_ts_handler); error = Devm_request_any_context_irq (Dev, Client->irq, gt811_ts _ISR, Irqf_trigger_falling, Client->name, pdata); if (error) {Dev_err (dev, "Failed to request IRQ (number:%d) \ n", Clien T->IRQ); goto Input_free;} Return 0;input_free:devm_kfree (dEV, input);pd ata_free:devm_kfree (Dev, pdata); Failed_exit:return error;} static int gt811_ts_remove (struct i2c_client *client) {struct Gt811_ts_platdata *pdata = (struct gt811_ts_platdata*) i2c_ Get_clientdata (client);d Evm_free_irq (&client->dev, CLIENT->IRQ, I2c_get_clientdata (client)); Input_ Unregister_device (pdata->input);d evm_kfree (&client->dev, pdata); return 0;} static const struct I2C_DEVICE_ID gt811_ts_id[] = {{"Gt811_ts", 0},{}};static struct i2c_driver gt811_ts_driver = {. dri ver = {. owner= this_module,.name= "Gt811_ts",. of_match_table = Of_match_ptr (gt811_ts_of_match),},.probe= gt811_ts_ probe,.remove= gt811_ts_remove,.id_table = Gt811_ts_id,};module_i2c_driver (gt811_ts_driver); Module_author ("Girlkoo <[email protected]>"); Module_description ("Gt811 i²c touchscreen Driver"); Module_license ("GPL");
(4) test with Tslib tool
Tslib Compiling method Please refer to this blog another piece of article, link as follows:
s5pv210 (TQ210) study notes--touch screen driver writing
This article does not repeat the Tslib configuration method.
(5) Effect display
(6) Full driver code
Please go to my resources to download tq335x touch screen driver source code, the link is as follows:
http://download.csdn.net/download/girlkoo/8202177
This article Girlkoo
This article link: http://blog.csdn.net/girlkoo/article/details/41522095
Am335x (tq335x) Learning notes-touch screen driver writing