
Today, I worked with a colleague on a TP driver. After powering on, the logs were normal, but the touchscreen was unresponsive, so we began troubleshooting.
After powering on, we could read the chip’s chip ID normally, which indicates that the I2C communication is functioning correctly, and it also confirms that the power supply to the touchscreen chip is normal.
Based on this, I brought over an oscilloscope to measure the signal on the interrupt pin and observed two phenomena:
1. After transitioning from sleep to wake state, there was a waveform on the interrupt pin, and the waveform appeared normal.
2. The interrupt handler function did not execute.
—— The DTS file for the touchscreen is written as follows:
File: arch/arm/boot/dts/inxxx.dts
cap_touch@14 {
compatible = "mediatek,cap_touch";
reg = <0x14>;
interrupt-parent = <&pio>;
interrupts = <100 IRQ_TYPE_EDGE_FALLING>;
int-gpio = <&pio 100 0>;
rst-gpio = <&pio 101 0>;
};
The compatible field matches the name in the driver.
The reg field is the I2C chip address.
The interrupt-parent corresponds to the platform’s interrupt controller, where the pio used corresponds to the DTS description of the interrupt controller in the mt8167.dtsi file.
The first parameter of interrupts corresponds to the interrupt number, and the second parameter corresponds to the trigger type of the interrupt.
The int-gpio references the GPIO controller in pio, where the second parameter corresponds to the GPIO number, and the third corresponds to the GPIO level.
The rst-gpio is similar to the above.
Refer to the kernel documentation for the description of gpiodts:
File: Documentation/devicetree/binding/pinctrl/pinctrl-mt65xx.txt
Eg: <&pio 6 0>
<[phandle of the gpio controller node]
[line number within the gpio controller]
[flags]>
Values for gpio specifier:
- Line number: is a value between 0 to 202.
- Flags: bit field of flags, as defined in <dt-bindings/gpio/gpio.h>. Only the following flags are supported: 0 - GPIO_ACTIVE_HIGH 1 - GPIO_ACTIVE_LOW
Let’s see what is inside &pio:
pio: pinctrl@10005000 {
compatible = "mediatek,mt8167-pinctrl";
reg = <0 0x1000b000 0 0x1000>;
mediatek,pctl-regmap = <&syscfg_pctl_a>;
pins-are-numbered;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
};
—— Let’s check the registered interrupt numbers:
xxxx:/ # cat proc/interrupts
CPU0
18: 19578 GIC 27 Edge arch_timer
20: 0 MT_SYSIRQ 132 Level mtk_timer
21: 12 MT_SYSIRQ 84 Level mtk-uart
30: 0 MT_SYSIRQ 128 Level SPM
31: 0 MT_SYSIRQ 129 Level SPM
32: 0 MT_SYSIRQ 130 Level SPM
33: 0 MT_SYSIRQ 131 Level SPM
34: 0 MT_SYSIRQ 221 Edge ATF_irq
39: 0 MT_SYSIRQ 194 Level BTCVSD_ISR_Handle
40: 0 MT_SYSIRQ 198 Edge mtk-wdt
42: 0 MT_SYSIRQ 204 Level mt-pmic-pwrap
43: 0 MT_SYSIRQ 149 Edge mtk-kpd
45: 0 MT_SYSIRQ 121 Level 10203000.m4u
46: 0 MT_SYSIRQ 218 Level CIRQ
47: 0 MT_SYSIRQ 114 Level TEE IRQ
49: 2942 MT_SYSIRQ 125 Level mtk_cmdq
50: 0 MT_SYSIRQ 126 Level TEE IRQ
53: 0 MT_SYSIRQ 76 Level mt-pwm
54: 30 MT_SYSIRQ 80 Level i2c-mt65xx
55: 16 MT_SYSIRQ 81 Level i2c-mt65xx
56: 64 MT_SYSIRQ 82 Level i2c-mt65xx
57: 0 MT_SYSIRQ 77 Level mt8167-thermal
58: 16 MT_SYSIRQ 83 Level ptp
62: 20967 MT_SYSIRQ 72 Level musb-hdrc
63: 0 MT_SYSIRQ 120 Level Afe_ISR_Handle
64: 2950 MT_SYSIRQ 185 Level pvrsrvkm
65: 113181 MT_SYSIRQ 78 Level 11120000.mmc
67: 0 MT_SYSIRQ 210 Level musbfsh-hdrc.0
74: 347 MT_SYSIRQ 160 Level DISPSYS
75: 12980 MT_SYSIRQ 162 Level DISPSYS
76: 0 MT_SYSIRQ 163 Level DISPSYS
80: 0 MT_SYSIRQ 167 Level DISPSYS
83: 0 MT_SYSIRQ 171 Level DISPSYS
85: 1466 MT_SYSIRQ 153 Level DISPSYS
88: 0 MT_SYSIRQ 180 Level ISP
123: 0 mtk-eint 28 Level mt6397-pmic
136: 0 mtk-eint 41 Level USB_IDDIG
195: 6 mtk-eint 100 Edge mtk-tpd
264: 0 mt6397-irq 6 Edge mt6397-thr_l
265: 0 mt6397-irq 7 Edge mt6397-thr_h
266: 0 mt6397-irq 5 Edge mtk-pmic-keys
267: 0 mt6397-irq 17 Edge mtk-pmic-keys
268: 0 mt6397-irq 18 Edge mtk-pmic-keys
269: 0 mt6397-irq 19 Edge mtk-pmic-keys
270: 0 mt6397-irq 20 Edge mt6397-rtc
IPI0: 0 CPU wakeup interrupts
IPI1: 0 Timer broadcast interrupts
IPI2: 31856 Rescheduling interrupts
IPI3: 35 Function call interrupts
IPI4: 121 Single function call interrupts
IPI5: 0 CPU stop interrupts
IPI6: 0 IRQ work interrupts
IPI7: 0 completion interrupts
Err: 0
# Let’s see how the driver handles these DTS configurations
First, use the function to obtain the content from the DTS:
tpd_rst_gpio = of_get_named_gpio(dev->of_node, "rst-gpio", 0);
tpd_int_gpio = of_get_named_gpio(dev->of_node, "int-gpio", 0);
Then, request the GPIO:
static int gtp_get_gpio_res(void)
{
#if defined(CONFIG_OF) && !defined(CONFIG_GTP_USE_PINCTRL)
int ret;
/* configure the gpio pins */
ret = gpio_request_one(tpd_rst_gpio, GPIOF_OUT_INIT_LOW,
"touchp_reset");
if (ret < 0) {
GTP_ERROR("Unable to request gpio reset_pin\n");
return -1;
}
ret = gpio_request_one(tpd_int_gpio, GPIOF_IN,
"tpd_int");
if (ret < 0) {
GTP_ERROR("Unable to request gpio int_pin\n");
gpio_free(tpd_rst_gpio);
return -1;
}
#endif
return 0;
}
Next, when looking at the interrupt registration function, there is something strange:
static int tpd_irq_registration(void)
{
struct device_node *node = NULL;
unsigned long irqf_val = 0;
int ret = 0;
// node = of_find_compatible_node(NULL, NULL, "mediatek,cap_touch");//0704
node = of_find_matching_node(NULL, touch_of_match);
if (node) {
// touch_irq = gpio_to_irq(tpd_int_gpio);
touch_irq = irq_of_parse_and_map(node, 0);
GTP_ERROR("###### touch_irq = %d\n",(int)touch_irq);
irqf_val = !int_type ? IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
irq_enabled = true; //
ret = request_irq(touch_irq, (irq_handler_t) tpd_interrupt_handler,
irqf_val, TPD_DEVICE, NULL); //jason test here
GTP_ERROR("###### ret = %d\n",(int)ret);
if (ret < 0)
GTP_ERROR("tpd request_irq IRQ LINE NOT AVAILABLE!.");
}
}
// touch_irq = gpio_to_irq(tpd_int_gpio); This line of code is commented out, meaning that gpio_to_irq is not used to handle the interrupt.
The current driver uses the irq_of_parse_and_map function to parse the DTS content for the driver.
The reason for using irq_of_parse_and_map is to reduce the workload for the driver engineer, as the DTS has already clearly described the interrupt information, including the interrupts and interrupt-parent properties. This function will parse these two properties and implement the corresponding mapping relationship.
—— Let’s look at the kernel code’s explanation of this function:
/**
* irq_of_parse_and_map - Parse and map an interrupt into linux virq space
* @dev: Device node of the device whose interrupt is to be mapped
* @index: Index of the interrupt to map
*
* This function is a wrapper that chains of_irq_parse_one() and
* irq_create_of_mapping() to make things easier to callers
*/
unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
{
struct of_phandle_args oirq;
if (of_irq_parse_one(dev, index, &oirq))
return 0;
return irq_create_of_mapping(&oirq);
}
EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
The above explanation means that this function parses and maps the interrupt to the Linux virq space, where dev corresponds to the device pointer, and index is the index of the interrupt to be mapped.
This function is a wrapper for of_irq_parse_one() and irq_create_of_mapping(), making it easier for developers to write code.
Now let’s look at:
touch_irq = irq_of_parse_and_map(node, 0);
The 0 here indicates the offset index. If we write it like this in the DTS, we can use the index to select our configuration:
interrupts = <0 0 4>, <0 1 4>;
The number “195” we see in proc/interrupts comes from here:
195: 69 0 0 0 mtk-eint 100 Edge mtk-tpd
# So why didn’t the interrupt function execute?
After checking everything, it was found that the interrupts property in the DTS description was not written correctly. The first parameter of interrupts needs to correspond to the GPIO pin number, but we reused the code from the previous project and should have modified this GPIO pin, which we did not update in the software in time.
Of course, once the problem was identified, it was quickly resolved.
Seeing the touchscreen report points correctly after touching is a very satisfying outcome.
# How the driver obtains interrupts from the DTS
This part is very well summarized by Teacher Wei Dongshan, and I recommend everyone to read this article:
Obtaining interrupts described in DTS in Linux drivers
For different devices, the method of obtaining interrupts varies. A common approach is to describe the interrupt as a GPIO pin in the DTS, then in the driver, first obtain the GPIO pin, and then convert it to an interrupt.
# Summary
This part is somewhat repetitive; the touchscreen driver is a common peripheral, and the debugging difficulty is not very high. The normal debugging sequence is:
— First, ensure power supply— then ensure I2C functionality, which generally requires pull-ups, as well as I2C speed and levels.
— Next, check the address; in Linux, we generally use a 7-bit address, and it is important to note that the address may also be related to hardware design.
— Once everything above is normal, we can start troubleshooting the interrupt issue. Some GPIOs may not have interrupts enabled by default and may require software configuration.
— Then observe whether the software can enter the interrupt handler function. Some drivers support polling, but the code locations are generally similar.
Once everything is normal, we can perform a power-on test to check if the touch functionality is working correctly.
Recommended Reading: Collection | Summary of Linux Articles Collection | Programming Life Collection | C Language My Knowledge Circle

Embedded Linux Scan the QR code to follow my public account