Search code examples
androidtouchembedded-linuxatmeldevice-tree

How to correctly configure interrupt for INT line of Atmel MXT641T touch chip in Android 5 kernel device tree?


I am having troubles getting a touch screen powered by an Atmel MXT641T on an Android 5 platform to work.

The setup I have is as follows:

  • Hardware: Inforce 6309 SBC with Qualcomm Snapdragon 410 msm8916 ARM64 processor.
  • Custom touch screen with Atmel MXT641T controller chip.
  • I2C connection between Atmel and Snapdragon connected to I2C0.
  • Android 5 operating system using Linux kernel 3.10 from git://codeaurora.org/kernel/msm-3.10.git branch Rel_V1.3 (this is part of the BSP that comes with the SBC)...
  • ... but with the latest version of the Atmel driver atmel_mxt_ts.c overlaid on the kernel tree (but also tested with version of atmel_maxtouch_ts.c in msm-3.10.git which shows same behaviour).
  • INT line from Atmel chip connected to GPIO 53 (this is EXT_CONN_GPIO_1 of this board) and with external pull-up resistor to 1.8V.
  • RESET line from Atmel chip disconnected.

What I did to get to this point is to modify the device tree to include the Atmel device as follows:

&i2c_0 {

  atmel_maxtouch_ts@4a {
    compatible = "atmel,maxtouch";
    reg = <0x4a>;
    interrupt-parent = <&msm_gpio>;
    interrupts = <53 0>;
    atmel,panel-coords = <0 0 1024 768>;
    atmel,display-coords = <0 0 1024 768>;
    atmel,family-id = <164>;
    atmel,variant-id = <2>;
    atmel,version = <21>;
    atmel,build = <0xaa>;
  };

};

For reference, the msm_gpio is defined as follows in the BSP (untouched).

&soc {
        tlmm_pinmux: pinctrl@1000000 {
                compatible = "qcom,msm-tlmm-8916";
                reg = <0x1000000 0x300000>;
                interrupts = <0 208 0>;

                /*General purpose pins*/
                gp: gp {
                        qcom,num-pins = <122>;
                        #qcom,pin-cells = <1>;
                        msm_gpio: msm_gpio {
                                compatible = "qcom,msm-tlmm-gp";
                                gpio-controller;
                                #gpio-cells = <2>;
                                interrupt-controller;
                                #interrupt-cells = <2>;
                                num_irqs = <122>;
                        };
                };

I compiled the kernel as a module (CONFIG_TOUCHSCREEN_ATMEL_MXT=m) and I am running insmod manually.

What I see is the following:

  • When using the Atmel utility mxt-app the device works: when I touch the screen messages come in, so the I2C connection is ok (but it uses polling).
  • When loading the driver mxt_start is called, in which the interrupt is enabled. I have added a number of debug statements to the driver to verify that it is actually loading.
  • When loading the driver the info block is read from the device and brief I2C traffic shows on the oscilloscope. The I2C address is read from the device tree so I am sure that my device tree is loaded.
  • The input device is registered as /dev/input/event6 and can be opened with cat (but no messages appear when touching the screen).
  • The interrupt is visible in /proc/interrupts but never fires (see below).
  • Whenever I touch the screen, the INT line from the Atmel chip is pulled low by the chip, but no I2C traffic is visible on the oscilloscope.
  • I verified that the interrupt triggering condition (0x0, 0x8 or 0x2008 as second element in the interrupt cell in the device tree) does not matter by manually causing highs and lows on the interrupt line: no interrupt is triggered in any event.

Entry in /proc/interrupts:

 $ cat /proc/interrupts
 ...
 326:          0          0          0          0  msm_tlmm_irq  maxtouch
 ...

This is what appears in dmesg:

<6>[   55.290620] atmel_mxt_ts 0-004a: Family: 164 Variant: 2 Firmware V1.5.AA Objects: 43
<4>[   55.291252] atmel_mxt_ts 0-004a: Enabling RETRIGEN workaround
<6>[   55.365918] atmel_mxt_ts 0-004a: Touchscreen size X1024Y768
<6>[   55.367017] input: Atmel maXTouch Touchscreen as /devices/soc.0/78b6000.i2c/i2c-0/0-004a/input/input6

What I understand from reading the driver code in atmel_mxt_ts.c is that the driver should trigger on this interrupt line, and then query the device by starting an I2C transfer to read the T5 message, upon which the device will return a list of touches which are then passed on to the operating system. I have not found a datasheet or document properly explaining this, but this is what I suspect based on what I have seen so far.

I have tested the GPIO pin 53 (to which I normally connect the INT line of the Atmel chip) manually by doing the following:

$ echo 955 > /sys/class/gpio/export     # 955 because EXP_CONN_GPIO_1 is GPIO pin 53, which has offset 902
cat /sys/class/gpio/gpio955/value

This value changes when I connect the INT line to V+ or ground, so I am sure that I have to use GPIO 53.

No GPIO for the maxtouch driver is shown in /sys/kernel/debug/gpio:

$ cat /sys/kernel/debug/gpio
GPIOs 576-607, platform/qcom,smp2pgpio-ssr-smp2p-4-out.19, master-kernel:

GPIOs 608-639, platform/qcom,smp2pgpio-ssr-smp2p-4-in.18, slave-kernel:

GPIOs 640-671, platform/qcom,smp2pgpio-ssr-smp2p-1-out.13, master-kernel:

GPIOs 672-703, platform/qcom,smp2pgpio-ssr-smp2p-1-in.12, slave-kernel:

GPIOs 704-735, platform/qcom,smp2pgpio-smp2p-4-out.16, smp2p:

GPIOs 736-767, platform/qcom,smp2pgpio-smp2p-4-in.14, smp2p:

GPIOs 768-799, platform/qcom,smp2pgpio-smp2p-1-out.10, smp2p:

GPIOs 800-831, platform/qcom,smp2pgpio-smp2p-1-in.8, smp2p:

GPIOs 832-863, platform/qcom,smp2pgpio-smp2p-7-out.6, smp2p:

GPIOs 864-895, platform/qcom,smp2pgpio-smp2p-7-in.4, smp2p:

GPIOs 896-899, spmi/qpnp-pin-ffffffc031550c00, pm8916-gpio:
 gpio-898 (qcom,hub-reset-gpio ) out hi
 gpio-899 (qcom,sw-sel-gpio    ) in  lo

GPIOs 900-901, spmi/qpnp-pin-ffffffc031550800, pm8916-mpp:

GPIOs 902-1023, platform/1000000.pinctrl, msm_tlmm_gpio:
 gpio-922 (adv7533_hpd_irq_gpio) in  lo
 gpio-923 (led1                ) out lo
 gpio-927 (disp_rst_n          ) in  hi
 gpio-933 (adv7533_irq_gpio    ) in  hi
 gpio-934 (hdmi_lvds           ) in  lo
 gpio-940 (7864900.sdhci cd    ) in  hi
 gpio-1009 (volume_up           ) in  hi
 gpio-1010 (camera_focus        ) in  hi
 gpio-1011 (camera_snapshot     ) in  hi
 gpio-1022 (led2                ) out lo
 gpio-1023 (USB_ID_GPIO         ) in  hi

I phrased some specific questions to help solve the puzzle:

  • What is the correct way to register the interrupt? I am using interrupt-parent = <&msm_gpio>; and interrupts = <53 0> to identify the GPIO pin 53 of the Snapdragon. I tested with both <53 0> and <53 8>.
  • I sometimes see people use 0x2008 as second entry in the cell. I think the 0x0008 is to set the interrupt to trigger on LOW level, but what does the 13-th bit do? I tested with both 0x0 and 0x8, does not make a difference (yet :-)).
  • Should I expect an entry in /sys/kernel/debug/gpio?
  • Are any additional entries in the device tree needed to hook up the maxtouch interrupt to the physical pin?
  • Where does the IRQ number 326 in /proc/interrupts come from, and is there a way to verify what pin it is linked to?
  • Is it possible to configure that the INT line will be pulled up by the Snapdragon, instead of having to use an external pull-up resistor?

Thanks in advance for your help.

PS: And a tangentially related question: how can I quickly test updates of the device tree without having to wait 20 minutes for all Makefiles to load and the kernel to recompile and then flash the new boot.img to the device and reboot? I use the command make bootimage.


Solution

  • After finding out that there is already a more or less working touchscreen definition in the device tree but that the pins are different, I ended up with the following device tree:

    &i2c_0 {
    
      atmel_maxtouch_ts@4a {
        compatible = "atmel,maxtouch";
        reg = <0x4a>;
        interrupt-parent = <&msm_gpio>;
        interrupts = <53 0x2008>;
        pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_suspend";
        pinctrl-0 = <&ts_int_active &ts_reset_active>;
        pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
        pinctrl-2 = <&ts_release>;
        atmel,irq-gpio = <&msm_gpio 53 0x2008>;
        atmel,reset-gpio = <&msm_gpio 54 0>;
        atmel,panel-coords = <0 0 800 480>;
        atmel,display-coords = <0 0 800 480>;
        atmel,family-id = <164>;
        atmel,variant-id = <2>;
        atmel,version = <21>;
        atmel,build = <0xaa>;
      };
    
    };
    

    so, the following lines are different:

    interrupts = <53 0x2008>;
    pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_suspend";
    pinctrl-0 = <&ts_int_active &ts_reset_active>;
    pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
    pinctrl-2 = <&ts_release>;
    atmel,irq-gpio = <&msm_gpio 53 0x2008>;
    atmel,reset-gpio = <&msm_gpio 54 0>;
    

    The 0x2008 is needed to make the Snapdragon pull up this interrupt line and trigger on the falling edge.

    The pinctrl definitions were already located in qcom/msm8916-pinctrl.dtsi that comes with the BSP, however, for my case I had to change pin 12 to 54 and pin 13 to 53:

    diff --git a/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi b/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi
    index 204c718..80a2a6d 100644
    --- a/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi
    +++ b/arch/arm/boot/dts/qcom/msm8916-pinctrl.dtsi
    @@ -30,16 +30,6 @@
                            };
                    };
    
    -               atmel-int-pin {
    -                       qcom,pins = <&gp 53>;
    -                       qcom,num-grp-pins = <1>;
    -                       label = "atmel-int-pin";
    -                       default {
    -                               drive-strength = <0>;
    -                               bias-pull-up;
    -                       };
    -               };
    -
                    ext-cdc-tlmm-lines {
                            qcom,pins = <&gp 116>, <&gp 112>, <&gp 117>,
                                                    <&gp 118>, <&gp 119>;
    @@ -1175,7 +1165,7 @@
    
                    /* add pingrp for touchscreen */
                    pmx_ts_int_active {
    -                       qcom,pins = <&gp 13>;
    +                       qcom,pins = <&gp 53>;
                            qcom,pin-func = <0>;
                            qcom,num-grp-pins = <1>;
                            label = "pmx_ts_int_active";
    @@ -1187,7 +1177,7 @@
                    };
    
                    pmx_ts_int_suspend {
    -                       qcom,pins = <&gp 13>;
    +                       qcom,pins = <&gp 53>;
                            qcom,pin-func = <0>;
                            qcom,num-grp-pins = <1>;
                            label = "pmx_ts_int_suspend";
    @@ -1199,7 +1189,7 @@
                    };
    
                    pmx_ts_reset_active {
    -                       qcom,pins = <&gp 12>;
    +                       qcom,pins = <&gp 54>;
                            qcom,pin-func = <0>;
                            qcom,num-grp-pins = <1>;
                            label = "pmx_ts_reset_active";
    @@ -1211,7 +1201,7 @@
                    };
    
                    pmx_ts_reset_suspend {
    -                       qcom,pins = <&gp 12>;
    +                       qcom,pins = <&gp 54>;
                            qcom,pin-func = <0>;
                            qcom,num-grp-pins = <1>;
                            label = "pmx_ts_reset_suspend";
    @@ -1223,7 +1213,7 @@
                    };
    
                    pmx_ts_release {
    -                       qcom,pins = <&gp 13>, <&gp 12>;
    +                       qcom,pins = <&gp 53>, <&gp 54>;
                            qcom,num-grp-pins = <2>;
                            label = "pmx_ts_release";