[punctual atom linux serial] Chapter 64 Linux multipoint capacitance touch screen experiment - extracted from [punctual atom] I.MX6U embedded Linux Driver Development Guide V1.0

Posted by [-_-] on Sat, 25 Sep 2021 12:08:29 +0200

1) Experimental platform: punctual atom alpha Linux development board
2) Platform purchase address: https://item.taobao.com/item.htm?id=603672744434
2) Full set of experimental source code + manual + video download address: http://www.openedv.com/thread-300792-1-1.html
3) Students interested in punctual atomic Linux can add group discussion: 935446741
4) pay attention to the official account of the dot atom and get updated information.

Chapter 64 Linux multipoint capacitive touch screen experiment

Touch screens are used in more and more occasions, from mobile phones, tablets to honeycomb pick-up screens, everywhere is full of touch screens. The touch screen has also developed from the original resistive touch screen to a very popular capacitive touch screen. We have explained how to write a capacitive touch screen driver in the bare metal experiment in Chapter 28. In this chapter, we will learn how to write a multi-point capacitive touch screen driver under linux.

Introduction to capacitive touch screen driver framework under 64.1 Linux
64.1.1 detailed explanation of multi touch (MT) protocol
We have explained the basic principle of capacitive touch drive in detail in Chapter 28 multi-point capacitive touch screen experiment, and reviewed several important knowledge points:
① The capacitive touch screen is IIC interface and needs touch IC. Take the ATK7016 of punctual atom as an example, and the touch screen control IC used is FT5426. Therefore, the so-called capacitive touch driver is IIC device driver.
② Touch IC provides interrupt signal pin (INT), which can obtain touch information through interrupt.
③ The capacitive touch screen obtains the absolute information of the touch position and whether the touch screen is pressed.
④ The capacitive touch screen does not need calibration. Of course, this is only theoretical. If the quality of the capacitive touch screen is poor or the touch glass is not fully aligned with the TFT, it also needs calibration.
According to the above knowledge points, we can conclude that the capacitive touch screen driver is actually a combination of the following linux driver frameworks:
① IIC device driver. Because capacitive touch ICs are basically IIC interfaces, the large frame is IIC device driver.
② . the touch information is reported to the linux kernel through the interrupt pin (INT), so the linux interrupt driver framework is needed. The reporting of coordinates is completed in the interrupt service function.
③ The coordinate information of touch screen, screen pressing and lifting information all belong to the input subsystem of linux. Therefore, the input subsystem must be used to report the coordinate information of touch screen to the linux kernel. However, we have to report the coordinate information according to the rules specified by the linux kernel.
After a simple analysis, we found that we have learned about IIC driver, interrupt driver and input subsystem, but what we haven't learned is the multi-point capacitive touch protocol under the input subsystem, which is the focus of our study in this chapter. A document in the linux kernel explains the multi-point capacitive touch screen protocol in detail. The document path is: Documentation/input/multi-touch-protocol.txt.
The old linux kernel does not support multi touch (MT for short), and the MT protocol is added later. Therefore, if the 2.x linux kernel is used, the MT protocol may not be found. MT protocols are divided into two types, Type A and type B. the differences between these two types are as follows:
Type A: applicable to touch points that cannot be distinguished or tracked. This type of equipment reports original data (this type is very few in actual use!).
Type B: it is applicable to touch devices that have hardware tracking and can distinguish touch points. This type of device updates the information of a touch point through slot. FT5426 belongs to this type. General multipoint capacitive touch screen IC has this ability.
The touch point information is transmitted through a series of ABS_MT events (some data are also called messages) are reported to the linux kernel, only ABS_MT events are used for multi touch, ABS_MT events are defined in the file include/uapi/linux/input.h. related events are as follows:

Example code ABS_MT event
852 #define ABS_MT_SLOT     		0x2f /* MT slot being modified */
853 #define ABS_MT_TOUCH_MAJOR	0x30 /* Major axis of touching ellipse */
854 #define ABS_MT_TOUCH_MINOR  0x31 /* Minor axis (omit if circular) */
855 #define ABS_MT_WIDTH_MAJOR  0x32 /* Major axis of approaching ellipse */
856 #define ABS_MT_WIDTH_MINOR	0x33 /* Minor axis (omit if circular) */
857 #define ABS_MT_ORIENTATION 	0x34 /* Ellipse orientation */
858 #define ABS_MT_POSITION_X  	0x35 /* Center X touch position */
859 #define ABS_MT_POSITION_Y  	0x36 /* Center Y touch position */
860 #define ABS_MT_TOOL_TYPE   	0x37 /* Type of touching device */
861 #define ABS_MT_BLOB_ID     	0x38 /* Group a set of packets as a blob */
862 #define ABS_MT_TRACKING_ID	0x39 /* Unique ID of initiated contact */
863 #define ABS_MT_PRESSURE   	0x3a /* Pressure on contact area */
864 #define ABS_MT_DISTANCE     	0x3b /* Contact hover distance */
865 #define ABS_MT_TOOL_X       	0x3c /* Center X tool position */
866 #define ABS_MT_TOOL_Y       	0x3d /* Center Y tool position */
In these numerous ABS_MT In the event, we most often use ABS_MT_SLOT,ABS_MT_POSITION_X,ABS_MT_POSITION_Y and ABS_MT_TRACKING_ID. among ABS_MT_POSITION_X and ABS_MT_POSITION_Y Used to report touch points(X,Y)Coordinate information, ABS_MT_SLOT Used to report touch points ID,about Type B Type of equipment, need to use ABS_MT_TRACKING_ID Event to distinguish touch points.

For Type A devices, input_mt_sync() function to isolate different touch point data information. The prototype of this function is as follows:
void input_mt_sync(struct input_dev *dev)
This function takes only one parameter and the type is input_dev, used to specify the specific input_dev device. input_ mt_ The sync() function triggers SYN_MT_REPORT event, which will notify the receiver to obtain the current touch data and prepare to receive the next touch point data.
For Type B devices, you need to report the touch point information through input_ mt_ The slot () function distinguishes which touch point is input_ mt_ The prototype of slot() function is as follows:
void input_mt_slot(struct input_dev *dev, int slot)
This function has two parameters. The first parameter is input_dev device. The second parameter slot is used to specify which touch point information is currently reported. input_ mt_ The slot() function triggers ABS_MT_SLOT event. This event will tell the receiver which slot data is currently being updated.
No matter what type of device it is, it will eventually call input_sync() function to identify the completion of multi touch information transmission, tell the receiver to process all messages accumulated before and be ready for the next reception. The biggest difference between type B and Type A is that type B can distinguish touch points, so it can reduce the data sent to the user space. Type B uses the slot protocol to distinguish specific touch points. The slot requires ABS_MT_TRACKING_ID message. This ID needs to be provided by hardware or calculated from the original data. For Type A device, the kernel driver needs to report all the touch point information on the touch screen at one time. The order of the information of each touch point in the reported event flow is not important, because the event filtering and finger (touch point) tracking are processed in the kernel space.
The Type B device driver needs to assign a slot to each recognized touch point, and then use this slot to report the touch point information. You can use the ABS of the slot_ MT_ TRACKING_ ID to add, replace, or delete touch points. A non negative ID represents a valid touch point, - 1 this ID represents an unused slot. An ID that did not exist before indicates that this is a newly added touch point. If an ID does not exist anymore, it indicates that it has been deleted.
Some devices recognize or track more touch point information than they report. These device drivers should assign a Type B slot to each touch point reported by the hardware. Once it is detected that the touch point ID associated with a slot has changed, the driver should change the ABS of the slot_ MT_ TRACKING_ ID to invalidate this slot. If the hardware device tracks more touch points than it is reporting, the driver should send a BTN_TOOL_*TAP message and call input_ mt_ report_ pointer_ The emulation() function, which uses the second parameter of this function_ Count is set to false.
64.1.2 Type A touch point information reporting timing
For Type A devices, the timing of sending touch point information is as follows. Here, take two touch points as an example:

Example code Type A Touch point data reporting timing
Line 1, passed ABS_MT_POSITION_X Event report of the first touch point X Coordinate data, by input_report_abs Function implementation, the same below.
Line 2, passed ABS_MT_POSITION_Y Event report of the first touch point Y Coordinate data.
Line 3, escalation SYN_MT_REPORT Event, by calling input_mt_sync Function.
Line 4, adopted ABS_MT_POSITION_X Event report of the second touch point X Coordinate data.
Line 5, adopted ABS_MT_POSITION_Y Event report of the second touch point Y Coordinate data.
Line 6, escalation SYN_MT_REPORT Event, by calling input_mt_sync Function.
Line 7, escalation SYN_REPORT Event, by calling input_sync Function implementation.
We're writing Type A Type of multi touch driver needs to follow the example code Coordinate information is reported according to the time sequence in. Linux It's also in the kernel Type A Type of multi touch driver, find st2332.c This driver file, path is drivers/input/touchscreen/st1232.c,find st1232_ts_irq_handler Function, which reports the coordinate information of the touch point.
Example code st1232_ts_irq_handler Function code snippet
103 static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
104 {
111     ret = st1232_ts_read_data(ts);
112     if (ret < 0)
113         goto end;
115     /* multi touch protocol */
116     for (i = 0; i < MAX_FINGERS; i++) {
117         if (!finger[i].is_valid)
118             continue;
120         input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
121         input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
122         input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
123         input_mt_sync(input_dev);
124         count++;
125     }
141     /* SYN_REPORT */
142     input_sync(input_dev);
144 end:
145     return IRQ_HANDLED;
146 }
Line 111, get all touch point information.
116th~125 OK, according to Type A The type reports the coordinate information of all touch points in turn, and lines 121 and 122 report the coordinate information of touch points respectively(X,Y)Axis coordinates, i.e ABS_MT_POSITION_X and ABS_MT_POSITION_Y event. Every time a touch point coordinate is reported, it shall be called in line 123 input_mt_sync Function reports a SYN_MT_REPORT Information.
In line 142, it is called every time a round of touch point information is reported input_sync Function, that is, send a SYN_REPORT event

64.1.3 Type B touch point information reporting timing
For Type B devices, the timing of sending touch point information is as follows. Here, take two touch points as an example:

Example code Type B Touch point data reporting timing
Line 1, escalation ABS_MT_SLOT Event, that is, the event corresponding to the touch point SLOT. Use it before reporting the coordinates of one touch point each time input_mt_slot Function reports the current touch point SLOT,Touch point SLOT It's actually a touch point ID,Need to be touched by IC Provide.
Line 2, according to Type B Requirements of each SLOT You must associate a ABS_MT_TRACKING_ID,Through modification SLOT Associated ABS_MT_TRACKING_ID To complete the addition, replacement or deletion of touch points. The specific function used is input_mt_report_slot_state,If you are adding a new touch point, the third parameter of this function active To set to true,linux The kernel automatically assigns a ABS_MT_TRACKING_ID Value, you do not need to specify a specific value ABS_MT_TRACKING_ID Value.
Line 3, report the of touch point 0 X Axis coordinates, using functions input_report_abs To finish.
Line 4, report the of touch point 0 Y Axis coordinates, using functions input_report_abs To finish.
fifth~8 Line, and 1~4 The line is similar, but it is changed to report touch point 0(X,Y)Coordinate information
 In line 9, when all the touch point coordinates are uploaded, they must be sent SYN_REPORT Events, using input_sync Function.
When a touch point is removed, it also needs to be passed SLOT Associated ABS_MT_TRACKING_ID The sequence is as follows:
Example code Type B Touch point removal timing
Line 1, when a touch point(SLOT)After removal, you need to pass ABS_MT_TRACKING_ID Event send a-1 To the kernel. The method is simple, and the same is used input_mt_report_slot_state Function, you only need to set the third parameter of this function active Set to false You don't need to set it manually-1. 
In line 2, when all the touch point coordinates are uploaded, they must be sent SYN_REPORT event.

When you want to write a multi touch driver of Type B, you need to report coordinate information according to the timing in example code There are a large number of Type B multi touch drivers in the Linux kernel. We can refer to these ready-made drivers to write our own driver code. Here, take the touch driver IC ili210x as an example to see how Type B reports the coordinate information of the touch point. Find the ili210x.c driver file with the path of drivers/input/touchscreen/ili210x.c, and find ili210x_report_events function, which is used to report ili210x touch coordinate information. The contents of the function are as follows:

Example code ili210x_report_events Function code snippet
78  static void ili210x_report_events(struct input_dev *input,
79                    const struct touchdata *touchdata)
80  {
81      int i;
82      bool touch;
83      unsigned int x, y;
84      const struct finger *finger;
86      for (i = 0; i < MAX_TOUCHES; i++) {
87          input_mt_slot(input, i);
89          finger = &touchdata->finger[i];
91          touch = touchdata->status & (1 << i);
92          input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
93          if (touch) {
94              x = finger->x_low | (finger->x_high << 8);
95              y = finger->y_low | (finger->y_high << 8);
97              input_report_abs(input, ABS_MT_POSITION_X, x);
98              input_report_abs(input, ABS_MT_POSITION_Y, y);
99          }
100     }
102     input_mt_report_pointer_emulation(input, false);
103     input_sync(input);
104 }
eighty-sixth~100 Line, using for Loop to report all touch point coordinates, and call in line 87 input_mt_slot Function reporting ABS_MT_SLOT event. Line 92 calls input_mt_report_slot_state Function reporting ABS_MT_TRACKING_ID Events, that is to say SLOT Associate a ABS_MT_TRACKING_ID. Lines 97 and 98 use input_report_abs The function reports the information corresponding to the touch point(X,Y)Coordinate values.
Line 103, use input_sync Function reporting SYN_REPORT event.

64.1.4 use of other MT events
All ABS supported by Linux are given in example code MT events, you can combine these events into various event combinations according to actual needs. The simplest combination is ABS_MT_POSITION_X and ABS_MT_POSITION_Y. The touch point can be reported in these two events. If the device supports it, ABS can also be used_ MT_ TOUCH_ Major and ABS_MT_WIDTH_MAJOR these two messages report touch area information about other ABS_ For the specific meaning of MT event, you can check the multi-touch-protocol.txt document in the Linux kernel. Here we focus on adding ABS_MT_TOOL_TYPE event.
ABS_ MT_ TOOL_ The type event is used to report the type of touch tool. Many kernel drivers cannot distinguish the type of touch device. Is it a finger or a touch pen? In this case, this event can be ignored. The current agreement supports Mt_ TOOL_ Finger, MT_ TOOL_ Pen and MT_ TOOL_ The three touch device types of palm are different from Type B. this event is handled by the input subsystem kernel. If the driver needs to report ABS_MT_TOOL_TYPE event, you can use input_mt_report_slot_state function to do this.
That's all for the multi touch (MT) protocol under Linux. To sum up, MT protocol belongs to the input subsystem of Linux and is driven by a large number of ABS_MT event reports multi touch coordinate data to Linux kernel. According to different touch ICs, there are two types: Type A and Type B. different types have different reporting timing. At present, Type B is the most used type. Next, we will write a multi-point capacitive touch driver according to the MT protocol learned earlier. The touch screens used in this chapter are ATK7084(7-inch 800480) and ATK7016(7-inch 1024600) touch screens of punctual atom. Both touch screens use FT5426 touch IC, so the driver is completely universal.
64.1.5 API functions used for multi touch
According to the previous explanation, we know that the multi touch protocol under Linux actually reports the coordinate information of touch points through different events. These events are realized through the corresponding API functions provided by the Linux kernel. In this section, let's take a look at some common API functions.
1,input_mt_init_slots function
input_ mt_ init_ The slots function is used to initialize the input slots of Mt. when writing MT driver, this function must be called to initialize slots. This function is defined in the file drivers / input / input mt.c. the function prototype is as follows:
int input_mt_init_slots( struct input_dev dev,
unsigned int num_slots,
unsigned int flags)
Function parameters and return values have the following meanings:
Dev: input corresponding to MT device_ Dev, because the MT device belongs to input_dev.
num_slots: the number of slots to be used by the device, that is, the number of touch points.
Flags: other flags information. The flags that can be set are as follows:
#define INPUT_MT_POINTER 0x0001 / pointer device, e.g. trackpad /
#define INPUT_MT_DIRECT 0x0002 / direct device, e.g. touchscreen /
#define INPUT_MT_DROP_UNUSED 0x0004 / drop contacts not seen in frame /
#define INPUT_MT_TRACK 0x0008 / use in-kernel tracking /
#define INPUT_MT_SEMI_MT 0x0010 / semi-mt device, finger count handled manually */
You can use the '|' operation to set multiple flags at the same time.
Return value: 0, successful; Negative value, failed.
2,input_mt_slot function
This function is used for Type B, and this function is used to generate ABS_ MT_ The slot event tells the kernel which touch point coordinate data is currently reported. This function is defined in the file include/linux/input/mt.h. the function prototype is as follows:
void input_mt_slot(struct input_dev *dev,
int slot)
Function parameters and return values have the following meanings:
Dev: input corresponding to MT device_ dev.
Slot: the coordinate information of which slot is currently sent, that is, which touch point.
Return value: none.
3,input_mt_report_slot_state function
This function is used for Type B to generate ABS_MT_TRACKING_ID and ABS_MT_TOOL_TYPE event, ABS_ MT_ TRACKING_ An ABS ID event is associated with a slot_ MT_ TRACKING_ ID,ABS_ MT_ TOOL_ The type event specifies the type of touch (pen or finger, etc.). This function is defined in the file drivers / input / input mt.c. the prototype of this function is as follows:
void input_mt_report_slot_state( struct input_dev *dev,
unsigned int tool_type,
bool active)
Function parameters and return values have the following meanings:
Dev: input corresponding to MT device_ dev.
tool_type: touch type, MT can be selected_ TOOL_ Finger, MT_ TOOL_ Pen or MT_ TOOL_ Palm (Palm) is generally a finger for multi-point capacitive touch screen.
active: true, continuous touch, input subsystem kernel will automatically assign an ABS_MT_TRACKING_ID to slot. false, the touch point is raised, indicating that a touch point is invalid. The input subsystem kernel will allocate a - 1 to the slot, indicating that the touch point overflows.
Return value: none.
4,input_report_abs function
Both Type A and Type B use this function to report touch point coordinate information through ABS_MT_POSITION_X and ABS_ MT_ POSITION_ The Y event reports the coordinate information of X and Y axes. This function is defined in the file include/linux/input.h. The function prototype is as follows:
void input_report_abs( struct input_dev *dev,
unsigned int code,
int value)
Function parameters and return values have the following meanings:
Dev: input corresponding to MT device_ dev.
code: the data to be reported can be set to ABS_MT_POSITION_X or ABS_MT_POSITION_Y. That is, x-axis or y-axis coordinate data.
Value: specific X-axis or Y-axis coordinate data value.
Return value: none.
5,input_mt_report_pointer_emulation function
If the number of touch points tracked is more than the number currently reported, the driver uses BTN_ TOOL_ The TAP event notifies the total number of touch points currently tracked by the user space, and then calls input_. mt_ report_ pointer_ The emulation function will use_ The count parameter is set to false. Otherwise, it will be used_ The count parameter is set to true to indicate the current number of touch points (this function will obtain the specific number of touch points, which does not need to be given by the user). This function is defined in the file drivers / input / input mt.c. the function prototype is as follows:
void input_mt_report_pointer_emulation(struct input_dev *dev,
bool use_count)
Function parameters and return values have the following meanings:
Dev: input corresponding to MT device_ dev.
use_count: true, the number of valid touch points; false, the number of tracked touch points is more than the number currently reported.
Return value: none.
64.1.6 multi point capacitive touch drive frame
The previous sections have explained the principle of multi-point touch screen driver under linux in detail. In this section, let's sort out the writing framework and steps of multi-point capacitive touch driver under linux. First, determine what knowledge points and frameworks need to be used for driving? According to the previous analysis, we need to pay attention to the following points when writing drivers:
① The interface of multi-point capacitance touch chip is generally I2C interface, so the driving main frame must be I2C.
② In linux, the coordinate information of the touch point is generally reported through interrupt, so the interrupt framework is needed.
③ The multi-point capacitive touch belongs to the input subsystem, so the input subsystem framework is also used.
④ . in the interrupt handler, report the coordinate information according to the MT protocol of linux.
According to the above analysis, the writing framework and steps of multi-point capacitive touch drive are as follows:
1. I2C drive frame
The I2C frame is adopted for the overall drive, and the reference frame code is as follows:

Example code Multipoint capacitive touch drive I2C Drive frame
1   /* Device tree matching table */ 
2  static const struct i2c_device_id xxx_ts_id[] = {
3   	{ "xxx", 0, },
4   	{ /* sentinel */ }
5  };
7  /* Device tree matching table */
8  static const struct of_device_id xxx_of_match[] = {
9   	{ .compatible = "xxx", },
10  	{ /* sentinel */ }
11 };
13 /* i2c Drive structure */ 
14 static struct i2c_driver ft5x06_ts_driver = {
15  	.driver = {
16      	.owner = THIS_MODULE,
17      	.name = "edt_ft5x06",
18      	.of_match_table = of_match_ptr(xxx_of_match),
19  	},
20  	.id_table = xxx_ts_id,
21  	.probe    = xxx_ts_probe,
22  	.remove   = xxx_ts_remove,
23 };
25 /*
26  * @description  : Drive entry function
27  * @param        : nothing
28  * @return       : nothing
29  */
30 static int __init xxx_init(void)
31 {
32  	int ret = 0;
34  	ret = i2c_add_driver(&xxx_ts_driver);
36  	return ret;
37 }
39 /*
40  * @description  : Drive exit function
41  * @param        : nothing
42  * @return       : nothing
43  */
44 static void __exit xxx_exit(void)
45 {
46  	i2c_del_driver(&ft5x06_ts_driver);
47 }
49 module_init(xxx_init);
50 module_exit(xxx_exit);
52 MODULE_AUTHOR("zuozhongkai");
I2C The driver framework has been explained in detail in Chapter 61, so I won't repeat it here. When touched in the device tree IC After the device node and driver match, example code In line 21 xxx_ts_probe The function will execute, and we can initialize the touch in this function IC,Interrupt and input Subsystem, etc.
2,Initialize touch IC,Interrupt and input Subsystem
 Initialization operations are performed in xxx_ts_probe Function, the reference framework is as follows(The sequence of steps in the following code can be adjusted by itself, not necessarily according to the example framework): 
Example code xxx_ts_probe Drive frame
1  static int xxx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
2  {
3   	struct input_dev *input;
5   	/* 1,Initialize I2C               */
6   	......
8   	/* 2,Apply for interruption, */
9   	devm_request_threaded_irq(&client->dev, client->irq, NULL,
10              xxx_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
11              client->name, &xxx);
12  	......
14  	/* 3,input Equipment application and initialization   */
15  	input = devm_input_allocate_device(&client->dev);
17  	input->name = client->name;
18  	input->id.bustype = BUS_I2C;
19  	input->dev.parent = &client->dev;
20  	......
22  	/* 4,Initialize input and MT          */
23  	__set_bit(EV_ABS, input->evbit);
24  	__set_bit(BTN_TOUCH, input->keybit);
26  	input_set_abs_params(input, ABS_X, 0, width, 0, 0);
27  	input_set_abs_params(input, ABS_Y, 0, height, 0, 0);
28  	input_set_abs_params(input, ABS_MT_POSITION_X,0, width, 0, 0);
29  	input_set_abs_params(input, ABS_MT_POSITION_Y,0, height, 0, 0);      
30  	input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
31  	......
33  	/* 5,Register input_dev           */
34  	input_register_device(input);
35  	......
36 }
fifth~7 OK, the first thing is to initialize the touch chip, including the related information of the chip IO,Such as reset, interrupt, etc IO Pin, and then the initialization of the chip itself, that is, configure the relevant registers of the touch chip.

In line 9, because the touch chip generally reports the touch point coordinate information to the system through interrupt, we need to initialize the interrupt, which is combined with the content of Chapter 51. You may find that line 9 does not use request_ The IRQ function applies for an interrupt, but uses devm_request_threaded_irq this function, why use this function? Is it a request_irq function cannot be used? The answer is definitely not. Use request here_ IRQ function is absolutely no problem. Then why use devm_ request_ threaded_ What about IRQ? Here we will briefly introduce the API function, devm_ request_ threaded_ The characteristics of IRQ function are as follows:
① It is used to apply for interruption, function and request_ The IRQ function is similar.
② This function is used to interrupt threading. If you directly search "devm_request_threaded_irq" on the Internet, you will find that there are few explanations. But let's search for request_ threaded_ IRQ function will have many blogs and posts to explain. The difference between the names of the two functions is that the former has more "devm_" prefix than the latter, and the "devm_" prefix will be explained later. You should notice that "request_threaded_irq" has more threaded functions than "request_irq", which means thread. So why interrupt threading? We all know that hardware interrupts have the highest priority. Whenever a hardware interrupt occurs, the kernel will terminate the current operation and execute the interrupt handler instead (regardless of closing the interrupt and interrupt priority). If the interrupt is very frequent, the kernel will execute the interrupt handler frequently, As a result, the task cannot be handled in time. After interrupt threading, interrupts will run as kernel threads, and can also be given different priorities. The priority of tasks may be higher than that of interrupt threads. The purpose of this is to ensure that high priority tasks can be processed first. You may wonder, didn't we say that more time-consuming interrupts can be processed in the bottom half? Although the lower half can be delayed, it still executes before the thread. Interrupt threading can make these more time-consuming lower half compete fairly with the process.
Note that not all interrupts can be threaded, and important interrupts cannot. For the touch screen, as long as the finger is placed on the screen, it may always generate an interrupt (depending on the specific chip, FT5426 is like this). The interrupt handler needs to read the touch information through I2C and report it to the kernel. The maximum speed of I2C is only 400KHz, which is a low-speed peripheral. The continuous generation of interrupts, reading touch information and reporting information will lead to the processor spending a lot of time on touch interrupts, but touch is relatively less important events, so the touch interrupts can be threaded. If you think touch interrupts are important, you can avoid threading them. In short, whether to thread an interrupt needs to be measured according to the actual situation. GOODIX. C (huiding Technology), mms114.c(MELFAS) and zforce provided with linux kernel_ Ts.c (zforce) and other multi-point capacitive touch IC drivers adopt interrupt threading. Of course, some drivers do not adopt interrupt threading.
③ Finally, let's take a look at the "devm_" prefix. In the linux kernel, many API functions that apply for resource classes have the corresponding "devm_" prefix version. Like devm_request_irq and request_irq these two functions, both of which apply for interruption, we use request_ When the irq function applies for an interrupt, if the driver initialization fails, it will call free_ The irq function releases the irq that has been successfully applied. When unloading the driver, we also need to call free manually_ irq to release irq. If our driver applies for many resources, such as gpio, irq and input_dev, you need to add a lot of goto statements to deal with it. When there are many such labels, the code looks untidy. The "devm_" function was created to handle this situation. The greatest function of the "devm_" function is:
The resources applied by the function prefixed with "devm_" can be automatically released by the system without manual processing.
If we use devm_request_threaded_irq function to apply for interruption, so we don't need to call free again_ The IRQ function releases it. You can notice that the functions prefixed with "devm_" are related to device resource management. The implementation principle of the "devm_" function will not be explained in detail here. Our focus is to learn how to use these API functions. If you are interested, you can refer to some other documents or posts to see the implementation principle of the "devm_" function.
Line 15, then apply for input_dev, because the multi-point capacitive touch belongs to the input subsystem. Devm is also used here_ input_allocate_device function to request input_dev, which is the input we explained earlier_ allocate_ Device function prefixed with "devm_" version. Apply to input_dev needs to be initialized later.
Lines 23 to 24, set input_ The event that dev needs to report is EV_ABS and BTN_TOUCH, because the touch coordinates of the multipoint capacitor screen are absolute values, ev needs to be reported_ ABS events. The touch screen can be pressed or lifted, so BTN needs to be reported_ Touch key.
Lines 26 to 29, call input_ set_ abs_ The params function sets EV_ABS events need to be reported to ABS_X,ABS_Y,ABS_MT_POSITION_X and ABS_MT_POSITION_Y. Single touch needs to be reported to ABS_X and ABS_Y. For multi touch, ABS needs to be reported_ MT_ POSITION_ X and ABS_MT_POSITION_Y.
Line 30, call input_ mt_ init_ The slots function initializes slots for multi-point capacitive touch.
Line 34, call input_ register_ The device function system registers the previously requested input_dev.
3. Reporting coordinate information
Finally, report the read coordinate information in the interrupt service program, and select whether to use Type A or Type B timing according to the type of multipoint capacitive touch device used. Since most devices are of Type B, here we will take Type B as an example to explain the reporting process. The reference driving framework is as follows:

Example code xxx_handler Interrupt handler
1  static irqreturn_t xxx_handler(int irq, void *dev_id)
2  {
4   	int num;            	/* Number of touch points */
5   	int x[n], y[n];     	/* Save coordinate values */
7   	/* 1,Obtain the coordinate values of each touch point from the touch chip */
8   	......
10  	/* 2,Report the coordinates of each touch point */
11  	for (i = 0; i < num; i++) {
12      	input_mt_slot(input, id);
13      	input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
14      	input_report_abs(input, ABS_MT_POSITION_X, x[i]);
15      	input_report_abs(input, ABS_MT_POSITION_Y, y[i]);
16  	}
17  	......
19  	input_sync(input);
20  	......
22  	return IRQ_HANDLED;
23 }
After entering the interrupt handler, the first thing must be from touch IC Read the touch coordinates and the number of touch points inside, assuming that the number of touch points is saved to num Variable, touch point coordinates stored in x,y In the array.
eleventh~16 OK, report the coordinates of each touch point circularly, and be sure to follow Type B Type of timing, which has been in 64.1.3 This section gives a detailed explanation, which will not be repeated here.
In line 19, call once after each round of touch point coordinate reporting input_sync Function to send a SYN_REPORT event.
That's all for the multi-point capacitor touch driver framework. Next, we'll actually write a multi-point capacitor touch driver.

64.2 hardware schematic analysis
Refer to subsection 28.2 for the schematic diagram of experimental hardware in this chapter.
64.3 preparation of test procedure
This test takes the FT5426 touch chip used in the ATK7084(7-inch 800480 resolution) and ATK7016(7-inch 1024600 resolution) of punctual atom as an example to explain how to write a multi-point capacitive touch driver. The details of FT5426 touch chip will not be repeated, because it has been explained in detail in section 28.1 of bare metal. The routine path corresponding to this experiment is: development board CD - > 2, Linux driver routine - > 23_ multitouch.
64.3.1 modifying the device tree
1. Add IO used by FT5426
FT5426 touch chip uses four IOS, one reset IO, one interrupt IO, SCL and SDA of I2C2, so we need to add IO related information in the device tree first. Reset IO and interrupt IO are common gpios, so these two IOS can be described on the same node. SCL and SDA of I2C2 belong to I2C2, so these two IOS should be described on the same node. First, reset IO and interrupt io. imx6ull-alientek-emmc.dts file has a node named "pinctrl_tsc" by default. If it is deleted, it will be created by itself. Under this node, add the interrupt pin information of the touch screen. The modified "pinctrl_tsc" node is as follows:

Example code pinctrl_tsc Node information
1 pinctrl_tsc: tscgrp {
2   fsl,pins = <
3       MX6UL_PAD_GPIO1_IO09__GPIO1_IO09   	0xF080 	/* TSC_INT */
4   >;
5 };
The touch screen reset pin uses SNVS_TAMPER9,Therefore, the reset pin information should be added to the iomuxc_snvs Under node, in iomuxc_snvs Create a new node named pinctrl_tsc_reset And then input the reset pin configuration information in this sub node, as shown below:
Example code pinctrl_tsc_reset Child node content
1 pinctrl_tsc_reset: tsc_reset {
2 		fsl,pins = <
4     	>;
5 };

Continue to add the SCL and SDA IO information of I2C2. The IO information of I2C2 has been added by default in imx6ull-alientek-emmc.dts, which is officially added by NXP, so we don't need to modify it. Find the "pinctrl_i2c2" node, which is the IO information used to describe I2C2. The node content is as follows:

Example code pinctrl_i2c2 Node information
1 pinctrl_i2c2: i2c2grp {
2   fsl,pins = <
3       MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
4       MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
5   >;
6 };
Finally, be sure to check the device tree to make sure that the touch screen is used IO It is not used by other peripherals. If any, it needs to be shielded to ensure that only the touch screen uses these four IO. 
2,add to FT5426 node
FT5426 This touch IC mount  I2C2 Next, so you need to I2C2 Add a child node under node, which is used to describe FT5426,After adding I2C2 The node contents are as follows:(Omit other mounts to I2C2 Equipment under): 
Example code ft5426 Node information
1  &i2c2 {
2   	clock_frequency = <100000>;
3   	pinctrl-names = "default";
4   	pinctrl-0 = <&pinctrl_i2c2>;
5   	status = "okay";
7   	/****************************/
8   	/* Omit other device nodes 			*/
9   	/****************************/
11  	/* zuozhongkai FT5406/FT5426 */
12  	ft5426: ft5426@38 {
13      	compatible = "edt,edt-ft5426";
14      	reg = <0x38>;
15      	pinctrl-names = "default";
16    		pinctrl-0 = <&pinctrl_tsc
17                    &pinctrl_tsc_reset >; 
18      	interrupt-parent = <&gpio1>; 
19      	interrupts = <9 0>; 
20      	reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;  
21      	interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; 
22  	};
23 };
Line 12, used by the touch screen FT5426 Chip node, Mount I2C2 Under the node, FT5426 The device address of is 0 X38. 
Line 14, reg Attribute description FT5426 The device address of is 0 x38. 
Lines 16 and 17, pinctrl-0 Attribute description FT5426 Reset of IO And interrupt IO The node used is pinctrl_tsc and pinctrl_tsc_reset. 
Line 18, interrupt-parent Property description interrupt IO Corresponding GPIO Group is GPIO1. 
Line 19, interrupts Property description interrupt IO Corresponding to GPIO1 Group IOI09. 
Line 20, reset-gpios Attribute description reset IO Corresponding GPIO by GPIO5_IO09. 
Line 21, interrupt-gpios Property description interrupt IO Corresponding GPIO by GPIO1_IO09. 

64.3.2 writing multi-point capacitive touch driver
Create a new folder named "23_multitouch", and then_ Create a vscode project in the multitouch folder, and the workspace is named "multitouch". After the project is created, create a new ft5x06.c driver file, and enter the following contents in it (due to space limitation, some contents are omitted. For complete contents, please check the driver source code):

Example code ft5x06.c File content(There is omission)
1   #include <linux/module.h>
2   #include <linux/ratelimit.h>
15  #include <linux/i2c.h>
16  /***************************************************************
17  Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
18  File name 	:  ft5x06.c
19  Author 	:  Zuo Zhongkai
20  edition 	:  V1.0
21  Description 	:  FT5X06, including touch screen drivers such as FT5206 and FT5426
22  other 	:  nothing
23  Forum 	:  www.openedv.com
24  journal 	:  First version v1.0 created by Zuo Zhongkai on December 23, 2019
25  ***************************************************************/
27  #define MAX_SUPPORT_POINTS    	 five 	/*  5 touch 	*/
28  #define TOUCH_EVENT_DOWN       	 0x00    	/*  Press 	*/
29  #define TOUCH_EVENT_UP         	 0x01   	/*  Lift 	*/
30  #define TOUCH_EVENT_ON           	 0x02    	/*  Contact 	*/
31  #define TOUCH_EVENT_RESERVED   	 0x03   	/*  retain 	*/
33  /* FT5X06 Register Related macro definition */
34  #define FT5X06_TD_STATUS_REG   	 0X02   	/*   Status register address 		*/
35  #define FT5x06_DEVICE_MODE_REG 	 0X00   	/*  Mode register 		*/
36  #define FT5426_IDG_MODE_REG     	 0XA4    	/*  Interrupt mode 	*/
37  #define FT5X06_READLEN           	 twenty-nine 	/*  Number of registers to read 	*/
39  struct ft5x06_dev {
40      struct device_node  *nd;        		/* Device node     		*/
41      int irq_pin,reset_pin;          		/* Interrupt and reset IO    	*/
42      int irqnum;                     		/* interrupt number        	*/
43      void *private_data;             		/* Private data     		*/
44      struct input_dev *input;        		/* input structural morphology 	*/
45      struct i2c_client *client;      		/* I2C client 		*/
46  };
48  static struct ft5x06_dev ft5x06;
50  /*
51   * @description   	: Reset FT5X06
52   * @param - client 	: i2c to operate
53   * @param – multidev	: Custom multitouch device
54   * @return          	: 0,success; Other negative values, failed
55   */
56  static int ft5x06_ts_reset(struct i2c_client *client, 
struct ft5x06_dev *dev)
57  {
58      int ret = 0;
60      if (gpio_is_valid(dev->reset_pin)) {        /* Check if IO is valid */
61          /* Request to reset IO and output low level by default */
62          ret = devm_gpio_request_one(&client->dev,   
63                      dev->reset_pin, GPIOF_OUT_INIT_LOW,
64                      "edt-ft5x06 reset");
65          if (ret) {
66              return ret;
67          }
68          msleep(5);
69          gpio_set_value(dev->reset_pin, 1);  /* Output high level, stop reset */
70          msleep(300);
71      }
72      return 0;
73  }
75  /*
76   * @description	: Read multiple register data from FT5X06
77   * @param – dev	: ft5x06 equipment
78   * @param – reg	: First register address to read
79   * @param – val	: Read data
80   * @param – len	: Length of data to read
81   * @return      	: Operation results
82   */
83  static int ft5x06_read_regs(struct ft5x06_dev *dev, u8 reg, 
void *val, int len)
84  {
85      int ret;
86      struct i2c_msg msg[2];
87      struct i2c_client *client = (struct i2c_client *)dev->client;
101     ret = i2c_transfer(client->adapter, msg, 2);
102     if(ret == 2) {
103         ret = 0;
104     } else {
105         ret = -EREMOTEIO;
106     }
107     return ret;
108 }
110 /*
111  * @description 	: Write data to ft5x06 multiple registers
112  * @param – dev	: ft5x06 equipment
113  * @param – reg	: First address of register to be written
114  * @param – val	: Data buffer to write to
115  * @param – len	: Length of data to write
116  * @return    		: Operation results
117  */
118 static s32 ft5x06_write_regs(struct ft5x06_dev *dev, u8 reg, 
u8 *buf, u8 len)
119 {
120     u8 b[256];
121     struct i2c_msg msg;
122     struct i2c_client *client = (struct i2c_client *)dev->client;
124     b[0] = reg;                 	/* Register header address 						*/
125     memcpy(&b[1],buf,len);      	/* Copy the data to be written into array b 	*/
127     msg.addr = client->addr;    	/* ft5x06 address 						*/
128     msg.flags = 0;              	/* Mark as write data 						*/
130     msg.buf = b;                	/* Data buffer to write to 				*/
131     msg.len = len + 1;          	/* Length of data to write 					*/
133     return i2c_transfer(client->adapter, &msg, 1);
134 }
136 /*
137  * @description 	: Write the specified value to ft5x06 specified register and write a register
138  * @param – dev	: ft5x06 equipment
139  * @param – reg	: Register to write
140  * @param – data	: Value to write
141  * @return   		: nothing
142  */
143 static void ft5x06_write_reg(struct ft5x06_dev *dev, u8 reg,
          u8 data)
144 {
145     u8 buf = 0;
146     buf = data;
147     ft5x06_write_regs(dev, reg, &buf, 1);
148 }
150 /*
151  * @description   	: FT5X06 Interrupt service function
152  * @param - irq     	: interrupt number 
153  * @param - dev_id 	: Equipment structure.
154  * @return          	: Interrupt execution result
155  */
156 static irqreturn_t ft5x06_handler(int irq, void *dev_id)
157 {
158     struct ft5x06_dev *multidata = dev_id;
160     u8 rdbuf[29];
161     int i, type, x, y, id;
162     int offset, tplen;
163     int ret;
164     bool down;
166     offset = 1;     /* Offset 1, that is 0X02+1=0x03, is the touch value from 0X03 */
167     tplen = 6;      /* A touch point has 6 registers to store the touch value */
169     memset(rdbuf, 0, sizeof(rdbuf));        /* eliminate */
171     /* Read FT5X06 touch point coordinates, starting from 0X02 register, and continuously read 29 registers */
172     ret = ft5x06_read_regs(multidata, FT5X06_TD_STATUS_REG, 
rdbuf, FT5X06_READLEN);
173     if (ret) {
174         goto fail;
175     }
177     /* Report the coordinates of each touch point */
178     for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
179         u8 *buf = &rdbuf[i * tplen + offset];
181         /* Take the first touch point as an example, register touch1_ XH (address 0X03), your description is as follows:
182          * bit7:6  Event flag  0:Press 1: Release 2: contact 3: no event
183          * bit5:4  retain
184          * bit3:0  X 11 ~ 8 bits of axis touch point.
185          */
186         type = buf[0] >> 6;     /* Get touch type */
187         if (type == TOUCH_EVENT_RESERVED)
188             continue;
190         /* The touch screen we use and FT5X06 are the opposite */
191         x = ((buf[2] << 8) | buf[3]) & 0x0fff;
192         y = ((buf[0] << 8) | buf[1]) & 0x0fff;
194         /* Take the first touch point as an example, register touch1_ YH (address 0X05), your description is as follows:
195          * bit7:4  Touch ID  Touch ID indicates which touch point it is
196          * bit3:0  Y 11 ~ 8 bits of axis touch point.
197          */
198         id = (buf[2] >> 4) & 0x0f;
199         down = type != TOUCH_EVENT_UP;
201         input_mt_slot(multidata->input, id);
202         input_mt_report_slot_state(multidata->input, MT_TOOL_FINGER, 
204         if (!down)
205             continue;
207         input_report_abs(multidata->input, ABS_MT_POSITION_X, x);
208         input_report_abs(multidata->input, ABS_MT_POSITION_Y, y);
209     }
211     input_mt_report_pointer_emulation(multidata->input, true);
212     input_sync(multidata->input);
214 fail:
215     return IRQ_HANDLED;
217 }
219 /*
220  * @description    	: FT5x06 Interrupt initialization
221  * @param - client  	: i2c to operate
222  * @param – multidev	: Custom multitouch device
223  * @return          	: 0,success; Other negative values, failed
224  */
225 static int ft5x06_ts_irq(struct i2c_client *client,
   struct ft5x06_dev *dev)
226 {
227     int ret = 0;
229     /* 1,Request interrupt GPIO */
230     if (gpio_is_valid(dev->irq_pin)) {
231         ret = devm_gpio_request_one(&client->dev, dev->irq_pin,
232                     GPIOF_IN, "edt-ft5x06 irq");
233         if (ret) {
234             dev_err(&client->dev,
235                 "Failed to request GPIO %d, error %d\n",
236                 dev->irq_pin, ret);
237             return ret;
238         }
239     }
241     /* 2,Apply for interrupt. Client - > IRQ is IO interrupt, */
242     ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
243                   ft5x06_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
244                   client->name, &ft5x06);
245     if (ret) {
246         dev_err(&client->dev, "Unable to request 
touchscreen IRQ.\n");
247         return ret;
248     }
250     return 0;
251 }
253  /*
254   * @description     	: i2c Driven probe function, when driven with
255   *                        This function will be executed after the device matches
256   * @param - client  	: i2c equipment
257   * @param - id      	: i2c Device ID
258   * @return          	: 0,success; Other negative values, failed
259   */
260 static int ft5x06_ts_probe(struct i2c_client *client, 
const struct i2c_device_id *id)
261 {
262     int ret = 0;
264     ft5x06.client = client;
266     /* 1,Gets the interrupt and reset pins in the device tree */
267     ft5x06.irq_pin = of_get_named_gpio(client->dev.of_node, 
"interrupt-gpios", 0);
268     ft5x06.reset_pin = of_get_named_gpio(client->dev.of_node, 
"reset-gpios", 0);
270     /* 2,Reset FT5x06 */
271     ret = ft5x06_ts_reset(client, &ft5x06);
272     if(ret < 0) {
273         goto fail;
274     }
276     /* 3,Initialization interrupt */
277     ret = ft5x06_ts_irq(client, &ft5x06);
278     if(ret < 0) {
279         goto fail;
280     }
282     /* 4,Initialize FT5X06 */
283     ft5x06_write_reg(&ft5x06, FT5x06_DEVICE_MODE_REG, 0);  
284     ft5x06_write_reg(&ft5x06, FT5426_IDG_MODE_REG, 1);  
286     /* 5,input Device registration */
287     ft5x06.input = devm_input_allocate_device(&client->dev);
288     if (!ft5x06.input) {
289         ret = -ENOMEM;
290         goto fail;
291     }
292     ft5x06.input->name = client->name;
293     ft5x06.input->id.bustype = BUS_I2C;
294     ft5x06.input->dev.parent = &client->dev;
296     __set_bit(EV_KEY, ft5x06.input->evbit);
297     __set_bit(EV_ABS, ft5x06.input->evbit);
298     __set_bit(BTN_TOUCH, ft5x06.input->keybit);
300     input_set_abs_params(ft5x06.input, ABS_X, 0, 1024, 0, 0);
301     input_set_abs_params(ft5x06.input, ABS_Y, 0, 600, 0, 0);
302     input_set_abs_params(ft5x06.input, ABS_MT_POSITION_X,
0, 1024, 0, 0);
303     input_set_abs_params(ft5x06.input, ABS_MT_POSITION_Y,
0, 600, 0, 0);      
304     ret = input_mt_init_slots(ft5x06.input, MAX_SUPPORT_POINTS, 0);
305     if (ret) {
306         goto fail;
307     }
309     ret = input_register_device(ft5x06.input);
310     if (ret)
311         goto fail;
313     return 0;
315 fail:
316     return ret;
317 }
319 /*
320  * @description   : i2c The remove function of the driver. This function will be executed when the i2c driver is removed
321  * @param – client	: i2c equipment
322  * @return          	: 0,success; Other negative values, failed
323  */
324 static int ft5x06_ts_remove(struct i2c_client *client)
325 {   
326     /* Release input_dev */
327     input_unregister_device(ft5x06.input);
328     return 0;
329 }
332 /*
333  *  Traditional drive matching table
334  */ 
335 static const struct i2c_device_id ft5x06_ts_id[] = {
336     { "edt-ft5206", 0, },
337     { "edt-ft5426", 0, },
338     { /* sentinel */ }
339 };
341 /*
342  * Device tree matching table 
343  */
344 static const struct of_device_id ft5x06_of_match[] = {
345     { .compatible = "edt,edt-ft5206", },
346     { .compatible = "edt,edt-ft5426", },
347     { /* sentinel */ }
348 };
350 /* i2c Drive structure */    
351 static struct i2c_driver ft5x06_ts_driver = {
352     .driver = {
353         .owner = THIS_MODULE,
354         .name = "edt_ft5x06",
355         .of_match_table = of_match_ptr(ft5x06_of_match),
356     },
357     .id_table = ft5x06_ts_id,
358     .probe    = ft5x06_ts_probe,
359     .remove   = ft5x06_ts_remove,
360 };
362 /*
363  * @description 	: Drive entry function
364  * @param       	: nothing
365  * @return      	: nothing
366  */
367 static int __init ft5x06_init(void)
368 {
369     int ret = 0;
371     ret = i2c_add_driver(&ft5x06_ts_driver);
373     return ret;
374 }
376 /*
377  * @description 	: Drive exit function
378  * @param       	: nothing
379  * @return      	: nothing
380  */
381 static void __exit ft5x06_exit(void)
382 {
383     i2c_del_driver(&ft5x06_ts_driver);
384 }
386 module_init(ft5x06_init);
387 module_exit(ft5x06_exit);
389 MODULE_AUTHOR("zuozhongkai");
thirty-ninth~46 Line, define a device structure to store attribute information related to multi-point capacitive touch devices.
Line 48, define a named ft5x06 The variable type is defined above ft5x06_dev Structure.
fifty-sixth~73 that 's ok, ft5x06_ts_reset Function to initialize FT5426 Touch chip is actually setting FT5426 Reset of IO High level to prevent chip reset. Note the use on line 62 devm_gpio_request_one Function to apply for reset IO,About“ devm_"The function of prefix is already in 64.1.6 Section gives a detailed explanation“ devm_"Prefixed API The resources requested by the function do not need to be released manually. The kernel will process them, so it is used here devm_gpio_request_one Function application IO In the future, we don't need to release this manually when unloading the driver IO. 
eighty-third~108 that 's ok, ft5x06_read_regs Function for continuous reading FT5426 The internal register data is I2C Reading functions are explained in detail in Chapter 61.
118th~134 that 's ok, ft5x06_write_regs Function for adding FT5426 Register writes continuous data, that is I2C Writing functions is also explained in detail in Chapter 61.
143rd~148 that 's ok, ft5x06_write_reg Function, right ft5x06_write_regs Simple encapsulation of functions to FT5426 The specified register writes a data for configuration FT5426. 
156th~217 that 's ok, ft5x06_handler Function, the touch screen interrupt service function, and the reporting of touch point coordinates is completed in this function. Line 172 passes ft5x06_read_regs Function read FT5426 All touch point information register data from 0 X02 Starting from this address, there are 29 registers in total~209 OK for Loop is to report touch point coordinate data one by one, and use Type B We have said this many times before. Finally, it passes on line 212 input_sync Function reporting SYN_REPORT Event. If you understand the previous explanation Type B Timing, then this function is very good to understand.
225th~251 that 's ok, ft5x06_ts_irq Functions, initializing FT5426 Interruption of IO,Line 231 use devm_gpio_request_one Function request interrupt IO. Line 242 uses the function devm_request_threaded_irq Apply for an interrupt. The interrupt processing function is ft5x06_handler. 

In line 260317, this function will be executed after the I2C device matches the driver. Generally, some initialization work is completed in this function. Let's focus on line 287309, which is about the initialization of input_dev device. In line 287294, we apply for and simply initialize input_dev, which we have explained in Chapter 58. Lines 296 and 298 set the events to be reported by input_dev For EV_KEY and EV_ABS, the key code to be reported is BTN_TOUCH. EV_KEY is a key event, which is used to report whether the touch screen is pressed, which is equivalent to treating the touch screen as a key. EV_ABS is the coordinate data of the touch point, and BTN_TOUCH means to use the pressing and lifting of the touch screen as the BTN_TOUCH key. Line 300303 calls the input_set_abs_params function to set the EV_ABS event, and ABS_X ABS_Y, ABS_MT_POSITION_X and ABS_MT_POSITION_Y. for single touch, ABS_X and ABS_Y need to be reported. For multi touch, ABS_MT_POSITION_X and ABS_MT_POSITION_Y need to be reported. In line 304, call the input_mt_init_slots function to initialize slots, that is, the maximum number of touch points. FT5426 is a 5-point capacitive touch chip, so there are 5 slots in total. Finally, call input_register_devic in line 309 The e function registers input_dev with the system.
In lines 324-329, the ft5x06_ts_remove function will be executed when the driver is unloaded. Because many of the previous resources are applied with the "devm_" prefix function, there is no need to release them manually. This function only needs to call input_unregister_device to release the input_dev previously added to the kernel.
Line 330 ~ ends. The rest is the I2C driver framework, which has been explained in detail in Chapter 61.
64.4 operational testing
64.4.1 compiling drivers
Write the Makefile file. The Makefile file of the experiment in this chapter is basically the same as the experiment in Chapter 40, except that the value of obj-m variable is changed to "icm20608.o". The contents of the Makefile are as follows:

Example code Makefile file
1  KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
4  obj-m := ft5x06.o
11 clean:
Line 4, setting obj-m The value of the variable is“ ft5x06.o". 
Input the following command to compile the driver module file:

make -j32
After successful compilation, a driver module file named "ft5x06.ko" will be generated.
64.4.2 operational testing
Compile the device tree and start the linux kernel with the new device tree.
There is no need to write a special APP for multi-point capacitive touch screen test. Copy ft5x06.ko compiled in the previous section to the rootfs/lib/modules/4.1.15 directory, start the development board, enter the directory lib/modules/4.1.15, and enter the following command to load the driver module ft5x06.ko.
depmod / / this command needs to be run when the driver is loaded for the first time
modprobe ft5x06.ko / / load the driver module
After the driver module is loaded successfully, there will be information input as shown in figure

Figure drive loading process
After the driver is loaded successfully, it will generate / dev/input/eventX(X=1,2,3...). For example, the multi-point capacitive touch driver in this experiment will generate / dev/input/event2 under the ALPHA development board platform I use, as shown in figure

Figure event equipment corresponding to capacitor screen
Event serial numbers are different on different platforms, or event3, event4, etc. everything is subject to the actual situation! Enter the following command to view event2, that is, the original data reported by the multi-point capacitive touch screen:
hexdump /dev/input/event2
Now touch the upper right corner of the screen with one finger and then lift it up. The theoretical coordinate value is (1023,0), but due to the touch error, the probability will not be absolute (1023,0). It should be a touch coordinate value near this value. The actual reported data is shown in figure

Figure reported raw data
The information reported in figure is presented according to the input_event type. This is also described in detail in section 58.4.2. Here, we focus on analyzing the specific meaning represented on the multi-point capacitive touch screen, and sort out the data in figure The results are as follows:
Example code meaning of multi-point capacitance touch information
/input_event type***/
/*No. / tv_sec / / tv_usec / / type / / code / / value*/
0000000 02bb 0000 9459 0007 0003 002f 0000 0000
0000010 02bb 0000 9459 0007 0003 0039 0005 0000
0000020 02bb 0000 9459 0007 0003 0035 03ec 0000
0000030 02bb 0000 9459 0007 0003 0036 0017 0000
0000040 02bb 0000 9459 0007 0001 014a 0001 0000
0000050 02bb 0000 9459 0007 0003 0000 03ec 0000
0000060 02bb 0000 9459 0007 0003 0001 0017 0000
0000070 02bb 0000 9459 0007 0000 0000 0000 0000
0000080 02bb 0000 e5f8 0008 0003 0039 ffff ffff
0000090 02bb 0000 e5f8 0008 0001 014a 0000 0000
00000a0 02bb 0000 e5f8 0008 0000 0000 0000 0000
The first line, type 0x3, indicates that it is an EV_ABS event, code 0x2f, and ABS_MT_SLOT. Therefore, this line is the ABS_MT_SLOT event reported by the input_mt_slot function. value=0, indicating that the coordinate of the first touch point is reported next.
Line 2, type 0x3, indicates an EV_ABS event, code 0x39, that is, ABS_MT_TRACKING_ID. this line is the input_mt_report_slot_state function reporting the ABS_MT_TRACKING_ID event. value=5 indicates that the ID assigned to SLOT0 is 5.
Line 3, type 0x3, is an EV_ABS event, code 0x35, is ABS_MT_POSITION_X. this line is the ABS_MT_POSITION_X event reported by the input_report_abs function, that is, the X-axis coordinate of the touch point. value=0x03ec=1004, indicating that the X-axis coordinate of the touch point is 1004, belonging to the upper right corner of the screen.
Line 4, type 0x3, is an EV_ABS event, code 0x36, is ABS_MT_POSITION_Y. this line is the ABS_MT_POSITION_Y event reported by the input_mt_report_slot_state function, that is, the Y-axis coordinate of the touch point. value=0x17=23, indicating that the Y-axis coordinate is 23. It can be seen that the coordinate of this touch is (1004,23), which is in the upper right corner of the screen.
Line 5, type 0x1, is an EV_KEY event, code=0x14a, BTN_TOUCH, value=0x1 indicates that the touch screen is pressed.
Line 6, type 0x3, is an EV_ABS event, code 0x0, ABS_ 10. It is used to report the x-axis coordinates during single touch. Here and ABS_MT_POSITION_X is the same, and value is 0x3f0=1008. ABS_X is by input_ mt_ report_ pointer_ Reported by the emulation function.
Line 7, type 0x3, is an EV_ABS event, code 0x1, is ABS_Y. It is used to report the y-axis coordinates when touching a single point. Here and ABS_MT_POSITION_Y is the same, and value is 0x29=41. ABS_Y is input_ mt_ report_ pointer_ Reported by the emulation function.
Line 8, type 0x0, is an EV_SYN event, by input_ The sync function reports.
Line 9, type 0x3, is an EV_ABS event, code 0x39, that is, ABS_MT_TRACKING_ID, value=0xffffffff=-1, indicating that the touch point has left the screen.
Line 10, type 0x1, is an EV_KEY event, code=0x14a, BTN_TOUCH, value=0x0 means that the finger leaves the touch screen, that is, the touch screen is not pressed.
Line 11, type 0x0, is an EV_SYN event, by input_ The sync function reports.
The above is the coordinate reporting process of a touch point, which is consistent with the Type B device we explained earlier.
64.4.3 add driver to kernel
Previously, we have been compiling the touch driver into modules. After each system startup, the driver module is loaded manually, which is very inconvenient. When we debug the driver successfully, we usually compile it into the kernel, so that the driver will be loaded automatically after the kernel starts, and we don't need to manually modprobe. In this section, we will learn how to add ft5x06.c to the linux kernel. The steps are as follows:
1. Place the driver file in the appropriate location
First of all, we must find a suitable location in the kernel source code and put ft5x06.c in it. ft5x06.c is a touch screen driver. Therefore, we need to find out which directory the touch screen driver in the linux kernel is placed in. In the linux kernel, the touch screen driver is placed in the drivers/input/touchscreen directory, so we need to copy ft5x06.c to this directory. The command is as follows:
cp ft5x06.c (kernel source directory) / drivers/input/touchscreen/ -f
2. Modify the corresponding Makefile
Modify the Makefile in the drivers/input/touchscreen directory and add the following line at the bottom:
Example code added by drivers / input / Touchscreen / makefile
obj-y += ft5x06.o
After completion, as shown in figure

Figure modified Makefile
After the modification, recompile the linux kernel, and then start the development board with the new zImage. If the driver is added successfully, the system will output the information shown in figure when starting:

Figure startup information
As can be seen from figure, the touch screen driver has been started, and / dev/input/evenvtX will be generated automatically at this time. In this experiment, the touch screen driver is added to the linux kernel. After that, the touch screen corresponds to event1 instead of event2 corresponding to the module compiled earlier. We must pay attention to this! Enter the following command to check whether the drive works normally:
hexdump /dev/input/event1 / / view the original data reporting information on the touch screen
The results are shown in figure

Figure reported raw data
It can be seen that the coordinate data is reported normally, indicating that the drive is working properly.
64.5 tslib transplantation and use
64.5.1 tslib migration
Tslib is an open-source third-party library for touch screen performance debugging. When using resistance screen, tslib is generally used for calibration. Although the capacitive screen does not need to be calibrated, sometimes it is not accurate due to the processing of the capacitive screen, so sometimes it also needs to be calibrated. The most important thing is that tslib provides some other software through which we can test whether the touch screen works normally. The latest version of tslib has supported multi-point capacitive touch screen, so you can intuitively test the multi-point capacitive touch screen driver through tslib, which is much more convenient than viewing the original data of eventX.
The migration of tslib is very simple. The steps are as follows:
1. Get tslib source code
First of all, you must get the source code of tslib. The git address is https://github.com/kergoth/tslib , the latest version is 1.21. Tslib source code has been put on the development board CD. The path is: 1. Routine source code - "7. Third party library source code -" tslib-1.21.tar.bz2 ". Send the compressed package to ubuntu and unzip it to get a directory called "tslib-1.21", which is the tslib source code.
2. Modify the user of tslib source code
Modify the user of the extracted tslib-1.21 directory to be the current user. This step must be done! Otherwise, various problems will be encountered in later compilation. My current login user name of ubuntu is "zuozhongkai", then the modification command is as follows:
sudo chown zuozhongkai:zuozhongkai tslib-1.21 -R
3. ubuntu tool installation
When compiling tslib, you need to install some files in ubuntu to prevent errors in the process of compiling tslib. The command is as follows:
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool
4. Compile tslib
First, create a directory named "tslib" in ubuntu to store the compilation results. For example, the full path of the tslib directory we created is: / home/zuozhongkai/linux/IMX6ULL/tool/tslib.
Next, configure and compile tslib by entering the following command:
cd tslib-1.21/ / / enter the tslib source directory
./configure --host=arm-linux-gnueabihf --prefix=/home/zuozhongkai/linux/IMX6ULL/tool/tslib
make / / compile
make install / / install
Note that when configuring tslib with. / configure, the "– host" parameter specifies the compiler, and the "– prefix" parameter specifies where to install the tslib file after compilation. It must be installed in the "tslib" directory we just created.
After completion, the contents in tslib directory are shown in figure

Figure compiled file
The bin directory contains executable files, including tslib's testing tools. The configuration file of tslib is in the etc directory, and the related library files are in the lib directory. Copy all files in figure to the root file system of the development board. The command is as follows:
sudo cp * -rf /home/zuozhongkai/linux/nfs/rootfs
5. Configure tslib
Open the / etc/ts.conf file and find the following line:
module_raw input
If there is "#" before the above sentence, delete "#".
Open the / etc/profile file and add the following contents:
Example code content added to / etc / profile file
1 export TSLIB_TSDEVICE=/dev/input/event1
2 export TSLIB_CALIBFILE=/etc/pointercal
3 export TSLIB_CONFFILE=/etc/ts.conf
4 export TSLIB_PLUGINDIR=/lib/ts
6 export TSLIB_FBDEVICE=/dev/fb0
Line 1, TSLIB_TSDEVICE refers to the touch device file, which is set to / dev/input/event1 here. This should be set according to the specific situation. If your touch device file is event2, it should be set to / dev/input/event2, and so on.
Line 2, TSLIB_CALIBFILE indicates the calibration file. If screen calibration is performed, the calibration results will be saved in this file. Here, set the calibration file as / etc/pointercal. This file may not exist and will be generated automatically during calibration.
Line 3, TSLIB_CONFFILE indicates the touch configuration file, which is / etc/ts.conf. This file will be generated when transplanting tslib.
Line 4, TSLIB_PLUGINDIR indicates the directory location of tslib plug-in, and the directory is / lib/ts.
Line 5, TSLIB_CONSOLEDEVICE indicates console settings. It is not set here, so it is none.
Line 6, TSLIB_FBDEVICE means FB device, that is, screen. According to the actual configuration, my screen file is / dev/fb0, so it is set to / dev/fb0 here.
After all configurations are completed, restart the development board, and then you can test it.
64.5.2 tslib test
The capacitance screen can not be calibrated. If it is a resistance screen, it must be calibrated first! To calibrate, enter the following command:
If you are not satisfied after calibration, or you accidentally calibrate the capacitor screen, you can directly delete the / etc/pointercal file.
Finally, we use ts_test_mt this software to test whether the touch screen works normally and whether the multi-point touch is effective. Execute the following commands:
This command will open a touch test interface, as shown in figure

Figure ts_test_mt interface
In figure, there are three buttons "Draw", "Draw" and "Quit". The functions of these three buttons are as follows:
Drag: drag button, which is the default function. You can see a cross cursor in the middle of the screen. We can drag the cursor by touching the screen. One touch point is a cross cursor. For a 5-point capacitive touch screen, if all five fingers are placed on the screen, there are five cursors, one finger and one.
Draw: draw button. Press this button to simply draw on the screen. You can use this function to detect whether multi touch works normally.
Quit: exit button, exit ts_test_mt test software.
Click the "Draw" button and use the drawing function to Draw five fingers across the screen together. If the multipoint capacitor screen works normally, five lines will be left on the screen, as shown in figure

Figure 5-point touch test
As can be seen from figure, there are 5 lines on the screen, indicating that the 5-point capacitive touch works normally. All the 5 jumpers are white. In figure, due to taking photos and handling, the 5 lines are not white.
64.6 use the kernel's own driver
The Linux kernel has integrated many driver files of capacitive touch IC, such as FT5426 used in the experiment in this chapter. In this section, we will learn how to use the multi-point capacitive touch driver provided by the Linux kernel. Before using, remove the file ft5x06.c we added to the kernel from the kernel. Just modify the file drivers/input/touchscreen/Makefile and delete the following line:
obj-y += ft5x06.o
The driver file of FT5426 included in the kernel is drivers/input/touchscreen/edt-ft5x06.c. This driver file can drive not only FT5426 but also FT5206 and FT5406. Follow the steps below to learn how to use this driver.
1. Modify edt-ft5x06.c
edt-ft5x06.c cannot be used directly. It needs to be modified. Because this file is too large, I won't point out how to modify it one by one. You can directly refer to our modified edt-ft5x06.c. The modified edt-ft5x06.c is placed on the development board CD. The path is: 1. Routine source code / 2. Linux driver routine / 23_multitouch/edt-ft5x06.c, directly replace the edt-ft5x06.c provided by the kernel with the edt-ft5x06.c file provided by us. If you are interested, you can compare the differences between the two files to see what we have modified.
2. Enable the FT5X06 driver that comes with the kernel
edt-ft5x06.c is not enabled by default. We need to configure the Linux kernel to enable this driver. The configuration can be completed through the graphical configuration interface. Enter the Linux kernel source code directory and enter the following command to open the graphical configuration interface:
make menuconfig
The configuration path is as follows:
-> Device Drivers
-> Input device support
-> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y])
-> Touchscreens (INPUT_TOUCHSCREEN [=y])
-> <*> EDT FocalTech FT5x06 I2C Touchscreen support
The configuration is shown in figure 64.6.1:

Figure 64.6.1 enable the FT5X06 driver of the kernel
After configuration, recompile the linux kernel to generate zImage, but it cannot be used directly. You need to modify the device tree.
3. Modify device tree
To modify the ft5426 device node written in 64.3.1, you need to add the compatible attribute in it. Refer to the edt-ft5x06.c file for the added content. The list of compatible attributes supported by edt-ft5x06.c is as follows:

Example code 64.6.1 edt-ft5x06.c of compatible Compatible attribute list
static const struct of_device_id edt_ft5x06_of_match[] = {
    { .compatible = "edt,edt-ft5206", },
    { .compatible = "edt,edt-ft5306", },
    { .compatible = "edt,edt-ft5406", },
    { /* sentinel */ }
As you can see, edt-ft5x06.c File default supported compatible There are only three attributes“ edt,edt-ft5206","edt,edt-ft5306"And“ edt,edt-ft5406". We can modify the in the device tree ft5426 Node, in compatible Add an attribute value“ edt,edt-ft5406"(Example code 64.6.1 Just choose one of the three). Or modify sample code 64.6.1 Medium edt_ft5x06_of_match In the table, add a:

{ .compatible = "edt,edt-ft5426", }
In a word, match the ft5426 device with the edt-ft5x06.c driver! Here I choose to modify the ft5426 node in the device tree. The modified ft5426 node is as follows:

Example code 64.6.2 ft5426 Node content
1  ft5426: ft5426@38 {
2   	compatible = "edt,edt-ft5426","edt,edt-ft5406";
3   	reg = <0x38>;
4   	pinctrl-names = "default";
5   	pinctrl-0 = <&pinctrl_tsc>;
6   	interrupt-parent = <&gpio1>; 
7   	interrupts = <9 0>; 
8   	reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;  
9   	interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; 
10 };
Line 2, add one“ edt,edt-ft5406"Compatibility value.
After modification, recompile the device tree, and then use the new one.dtb and zImage File startup linux Kernel. If everything is normal, the output will be output when the system starts, as shown in Figure 64.6.2 Information shown:

Figure 64.6.2 touch screen log information
Directly run ts_test_mt to test whether the touch screen can be used.
So far, the multi-point capacitive touch driver under Linux is over. The focus is to master the touch screen reporting timing under Linux, most of which are Type B.
64.7 4.3-inch screen touch driving test
Punctual atom has two 4.3-inch capacitive touch screens with resolutions of 800480 and 480272 respectively. The touch driver IC of these two capacitive touch screens is GT9147, so it is essentially to write GT9147 driver. The principle and method are basically the same as the FT5426 used for the 7-inch screen mentioned above. Here we only briefly explain the steps of writing GT9147 driver.
1. Modify the contents of the device tree pinctrl_tsc node
The pinctrl_tsc node is used to save the interrupt and reset pin configuration information of the touch screen. The two IO configurations of GT9147 and FT5426 are slightly different, so the pinctrl_tsc node needs to be modified. The contents of the modified pinctrl_tsc node are as follows:

Example code 64.7.1 Modified pinctrl_tsc node
1 pinctrl_tsc: tscgrp {
2   fsl,pins = <
3       /* 4.3 Inch RGB screen, GT9147 */
4       MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09  	0x10B0      /* TSC_RST */
5       MX6UL_PAD_GPIO1_IO09__GPIO1_IO09    	0x10B0      /* TSC_INT */
6   >;
Lines 4 and 5 are modified GT9147 Reset and interrupt IO to configure.
2,In the device tree i2c2 Add under node gt9147 Child node
 We also need to i2c2 Add under node GT9147 The child nodes of are as follows:
Example code 64.7.2 gt9147 Child node content
1  gt9147:gt9147@14 {
2   	compatible = "goodix,gt9147", "goodix,gt9xx";
3   	reg = <0x14>;
4   	pinctrl-names = "default";
5   	pinctrl-0 = <&pinctrl_tsc>;
6   	interrupt-parent = <&gpio1>; 
7   	interrupts = <9 0>; 
8   	reset-gpios  = <&gpio5 9 GPIO_ACTIVE_LOW>;
9   	interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
10  	status = "okay";
11 };
3,Modify the of the device tree lcdif node
 Different screens have different configuration parameters, so they need to be modified lcdif Node, add parameters corresponding to the screen, 4.3 Inch 800*480 And 480*272 These two screens correspond to lcdif The nodes are as follows:
//Example code 64.7.3 glcdif node content
1  /* 4.3 Inch 480 * 272 */
2  &lcdif {
3   	pinctrl-names = "default";
4   	pinctrl-0 = <&pinctrl_lcdif_dat
5            	&pinctrl_lcdif_ctrl>;
7   	display = <&display0>;
8   	status = "okay";
10  	display0: display {
11      	bits-per-pixel = <24>;
12      	bus-width = <24>;
14      	display-timings {
15          		native-mode = <&timing0>;
16          		timing0: timing0 {
17          		clock-frequency = <9000000>;
18          		hactive = <480>;
19          		vactive = <272>;
20          		hfront-porch = <5>;
21          		hback-porch = <40>;
22          		hsync-len = <1>;
23          		vback-porch = <8>;
24          		vfront-porch = <8>;
25          		vsync-len = <1>;
27          		hsync-active = <0>;
28          		vsync-active = <0>;
29          		de-active = <1>;
30          		pixelclk-active = <0>;
31          		};
32      	};
33  	};
34 };
36 /* 4.3 Inch 800 * 480 */
37 &lcdif {
38  	pinctrl-names = "default";
39  	pinctrl-0 = <&pinctrl_lcdif_dat
40           	&pinctrl_lcdif_ctrl>;
42  	display = <&display0>;
43  	status = "okay";
45  	display0: display {
46      	bits-per-pixel = <24>;
47      	bus-width = <24>;
49      	display-timings {
50          		native-mode = <&timing0>;
51          		timing0: timing0 {
52          		clock-frequency = <31000000>;
53          		hactive = <800>;
54          		vactive = <480>;
55          		hfront-porch = <40>;
56          		hback-porch = <88>;
57          		hsync-len = <48>;
58          		vback-porch = <32>;
59          		vfront-porch = <13>;
60          		vsync-len = <3>;
62          		hsync-active = <0>;
63          		vsync-active = <0>;
64          		de-active = <1>;
65          		pixelclk-active = <0>;
66          		};
67      	};
68  	};
69 };
After modifying the device tree, recompile the device tree and start with the new device tree. Check it LCD Whether the drive is successful. If not, check it lcdif Node configuration.
4,compile GT9147 Drive file
GT9147 The driver writing of is no longer explained in detail here, basic and FT5426 Same, except for different chip configurations. GT9147 The driver has been written and placed in the driver folder of the tutorial in this chapter. The name of the driver file is: 23_multitouch->gt9147.c,You can compile it yourself. Loaded after compilation gt9147.ko Drive file, and then use tslib For testing, I won't show you here.
be careful, gt9147.c The drive inside is single touch, because GT9147 There is no hardware to detect the pressing and lifting of each touch point, so it is difficult to handle when reporting data. I tried some other processing methods, but the effect is not ideal, so I changed to single touch.

Topics: Linux stm32