• 基于设备树的TQ2440触摸屏驱动移植


    平台

    开发板:tq2440
    内核:Linux-4.9
    u-boot:u-boot-2015.04
     

    概述

    之前移植了LCD驱动,下面继续移植触摸屏驱动,然后将tslib也移植上去。

    正文

    一、移植触摸屏驱动

    为了简单起见我们对TQ2440自带的触摸屏驱动进行改写,改成设备树的形式。
    1、设备树
    触摸屏使用了两个中断,如下:
    这两个中断是子中断,隶属于主中断INT_ADC:
    关于寄存器,参考芯片手册的第16章,知道了上面的信息,我们就可以得到如下的设备树节点(可以参考博文基于设备树的TQ2440的中断(1)):
    tq2440ts@5800000 {
    compatible = "tq2440,ts";
    reg = <0x58000000 0x100>;
    reg-names = "adc_ts_physical";
    interrupts = <1 31 9 3>, <1 31 10 3>;
    interrupt-names = "int_ts", "int_adc_s";
    clocks = <&clocks PCLK_ADC>;
    clock-names = "adc";
    }; 
    2、驱动
    对应的触摸屏驱动是drivers/input/touchscreen/tq2440_ts.c
    这部分我已经上传到github上面了,可以使用下面的命令下载:
    git clone git@github.com:pengdonglin137/linux-4.9.git -b tq2440_dt 
    代码如下:
      1 /*************************************
      2 
      3 NAME:tq2440_ts.c
      4 COPYRIGHT:www.embedsky.net
      5 
      6  *************************************/
      7 #include <linux/errno.h>
      8 #include <linux/kernel.h>
      9 #include <linux/module.h>
     10 #include <linux/slab.h>
     11 #include <linux/input.h>
     12 #include <linux/init.h>
     13 #include <linux/serio.h>
     14 #include <linux/delay.h>
     15 #include <linux/platform_device.h>
     16 #include <linux/clk.h>
     17 #include <linux/of_device.h>
     18 #include <linux/of.h>
     19 #include <linux/of_gpio.h>
     20 #include <asm/io.h>
     21 #include <asm/irq.h>
     22 
     23 #include <plat/regs-adc.h>
     24 #include <mach/regs-gpio.h>
     25 
     26 /* For ts.dev.id.version */
     27 #define S3C2410TSVERSION    0x0101
     28 
     29 #define WAIT4INT(x)  (((x)<<8) | 
     30     S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | 
     31     S3C2410_ADCTSC_XY_PST(3))
     32 
     33 #define AUTOPST         (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | 
     34     S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
     35 
     36 static char *tq2440ts_name = "TQ2440 TouchScreen";
     37 
     38 static    struct input_dev *idev;
     39 static    long xp;
     40 static    long yp;
     41 static    int count;
     42 
     43 static void __iomem *base_addr;
     44 
     45 static void touch_timer_fire(unsigned long data)
     46 {
     47     u32 data0;
     48     u32 data1;
     49     int updown;
     50 
     51     data0 = readl(base_addr+S3C2410_ADCDAT0);
     52     data1 = readl(base_addr+S3C2410_ADCDAT1);
     53 
     54     updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
     55 
     56     if (updown) {
     57         if (count != 0) {
     58             long tmp;
     59 
     60             tmp = xp;
     61             xp = yp;
     62             yp = tmp;
     63 
     64             xp >>= 2;
     65             yp >>= 2;
     66 
     67             input_report_abs(idev, ABS_X, xp);
     68             input_report_abs(idev, ABS_Y, yp);
     69 
     70             input_report_key(idev, BTN_TOUCH, 1);
     71             input_report_abs(idev, ABS_PRESSURE, 1);
     72             input_sync(idev);
     73         }
     74 
     75         xp = 0;
     76         yp = 0;
     77         count = 0;
     78 
     79         writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
     80         writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
     81     } else {
     82         count = 0;
     83 
     84         input_report_key(idev, BTN_TOUCH, 0);
     85         input_report_abs(idev, ABS_PRESSURE, 0);
     86         input_sync(idev);
     87 
     88         writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
     89     }
     90 }
     91 
     92 static struct timer_list touch_timer =
     93 TIMER_INITIALIZER(touch_timer_fire, 0, 0);
     94 
     95 static irqreturn_t stylus_updown(int irq, void *dev_id)
     96 {
     97     u32 data0;
     98     u32 data1;
     99     int updown;
    100 
    101     data0 = readl(base_addr+S3C2410_ADCDAT0);
    102     data1 = readl(base_addr+S3C2410_ADCDAT1);
    103 
    104     updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
    105 
    106     if (updown)
    107         touch_timer_fire(0);
    108 
    109     return IRQ_HANDLED;
    110 }
    111 
    112 static irqreturn_t stylus_action(int irq, void *dev_id)
    113 {
    114     u32 data0;
    115     u32 data1;
    116 
    117     data0 = readl(base_addr+S3C2410_ADCDAT0);
    118     data1 = readl(base_addr+S3C2410_ADCDAT1);
    119 
    120     xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
    121     yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
    122     count++;
    123 
    124     if (count < (1<<2)) {
    125         writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
    126         writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
    127     } else {
    128         mod_timer(&touch_timer, jiffies+1);
    129         writel(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
    130     }
    131 
    132     return IRQ_HANDLED;
    133 }
    134 
    135 static int tq2440ts_probe(struct platform_device *pdev)
    136 {
    137     struct device *dev = &pdev->dev;
    138     struct device_node *node = dev->of_node;
    139     struct clk    *adc_clock;
    140     struct resource *tsmem, *irq;
    141     struct input_dev *input_dev;
    142     int ret;
    143 
    144     if (!node) {
    145         dev_dbg(dev, "of_node is NULL
    ");
    146         return -EINVAL;
    147     }
    148 
    149     adc_clock = devm_clk_get(dev, "adc");
    150     dev_dbg(dev, "adc_clock: %p
    ", adc_clock);
    151     if (IS_ERR(adc_clock)) {
    152         dev_err(dev, "cannot get clock
    ");
    153         return -ENOENT;
    154     }
    155     clk_prepare(adc_clock);
    156     clk_enable(adc_clock);
    157 
    158     dev_dbg(dev, "get mem
    ");
    159     tsmem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "adc_ts_physical");
    160     if (!tsmem) {
    161         dev_dbg(dev, "get mem resource failed.
    ");
    162         ret = -EINVAL;
    163         goto err;
    164     }
    165 
    166     base_addr = devm_ioremap_resource(dev, tsmem);
    167     if (IS_ERR(base_addr)) {
    168         dev_dbg(dev, "ioremap failed.
    ");
    169         ret = PTR_ERR(base_addr);
    170         goto err;
    171     }
    172 
    173     writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),base_addr+S3C2410_ADCCON);
    174     writel(0xffff,  base_addr+S3C2410_ADCDLY);
    175     writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
    176 
    177     input_dev = devm_input_allocate_device(dev);
    178     if (!input_dev) {
    179         dev_dbg(dev, "ioremap failed.
    ");
    180         ret = -ENOMEM;
    181         goto err;
    182     }
    183 
    184     idev = input_dev;
    185     idev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
    186 
    187 
    188     __set_bit(EV_SYN, idev->evbit);
    189     __set_bit(EV_KEY, idev->evbit);
    190     __set_bit(EV_ABS, idev->evbit);
    191     __set_bit(BTN_TOUCH, idev->keybit);
    192 
    193     input_set_abs_params(idev, ABS_X, 0, 0x3FF, 0, 0);
    194     input_set_abs_params(idev, ABS_Y, 0, 0x3FF, 0, 0);
    195     input_set_abs_params(idev, ABS_PRESSURE, 0, 1, 0, 0);
    196 
    197     idev->name = tq2440ts_name;
    198     idev->id.bustype = BUS_RS232;
    199     idev->id.vendor = 0xDEAD;
    200     idev->id.product = 0xBEEF;
    201     idev->id.version = S3C2410TSVERSION;
    202 
    203     irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "int_ts");
    204     if (!irq) {
    205         dev_err(dev, "get irq resource int_ts failed.
    ");
    206         ret = -EINVAL;
    207         goto err;
    208     }
    209     ret = devm_request_irq(dev, irq->start, stylus_updown, IRQF_ONESHOT, "int_ts", NULL);
    210     if (ret < 0){
    211         dev_err(dev, "request irq tsirq %d failed.
    ", irq->start);
    212         goto err;
    213     }
    214 
    215     irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "int_adc_s");
    216     if (!irq) {
    217         dev_err(dev, "get irq resource int_adc_s failed.
    ");
    218         ret = -EINVAL;
    219         goto err;
    220     }
    221     ret = devm_request_irq(dev, irq->start, stylus_action, IRQF_ONESHOT, "int_adc_s", NULL);
    222     if (ret < 0) {
    223         dev_err(dev, "request irq adcirq %d failed.
    ", irq->start);
    224         goto err;
    225     }
    226 
    227     dev_info(dev, "%s successfully loaded
    ", tq2440ts_name);
    228     input_register_device(idev);
    229 
    230     return 0;
    231 err:
    232     clk_disable(adc_clock);
    233     return ret;
    234 }
    235 
    236 static const struct of_device_id tq2440ts_match[] = {
    237     { .compatible = "tq2440,ts", .data = (void *)0 },
    238     {},
    239 };
    240 
    241 static struct platform_driver tq2440ts_driver = {
    242     .probe        = tq2440ts_probe,
    243     .driver        = {
    244         .name    = "tq2440ts",
    245         .of_match_table = of_match_ptr(tq2440ts_match),
    246     },
    247 };
    248 
    249 static int __init tq2440ts_init(void)
    250 {
    251     return platform_driver_register(&tq2440ts_driver);
    252 }
    253 
    254 static void __exit tq2440ts_exit(void)
    255 {
    256     platform_driver_unregister(&tq2440ts_driver);
    257 }
    258 
    259 module_init(tq2440ts_init);
    260 module_exit(tq2440ts_exit);
    261 
    262 MODULE_LICENSE("GPL");
    View Code
    3、测试
    查看中断信息:
    [root@tq2440 ]# cat /proc/interrupts 
               CPU0       
      7:        973  s3c-eint   7 Edge      eth0
      8:          0       s3c   8 Edge      s3c2410-rtc tick
     13:     559459       s3c  13 Edge      samsung_time_irq
     16:          0       s3c  16 Edge      4d000000.fb
     26:          0       s3c  26 Edge      ohci_hcd:usb1
     27:          4       s3c  27 Edge      54000000.i2c
     30:          0       s3c  30 Edge      s3c2410-rtc alarm
     32:        218  s3c-level  32 Level     50000000.serial
     33:      11203  s3c-level  33 Level     50000000.serial
     41:        758  s3c-level  41 Edge      int_ts
     42:      16712  s3c-level  42 Edge      int_adc_s
     59:          0  s3c-level  59 Edge      53000000.watchdog
    Err:          0

     使用hexdump /dev/input/event0:

    [root@tq2440 ]# hexdump /dev/input/event0 
    0000000 cb74 386e bc0b 000b 0003 0000 0201 0000
    0000010 cb74 386e bc0b 000b 0003 0001 01e4 0000
    0000020 cb74 386e bc0b 000b 0001 014a 0001 0000
    0000030 cb74 386e bc0b 000b 0003 0018 0001 0000
    0000040 cb74 386e bc0b 000b 0000 0000 0000 0000
    0000050 cb74 386e 0a4e 000c 0003 0000 01dc 0000
    0000060 cb74 386e 0a4e 000c 0003 0001 01fa 0000
    0000070 cb74 386e 0a4e 000c 0000 0000 0000 0000
    0000080 cb74 386e 585a 000c 0001 014a 0000 0000
    0000090 cb74 386e 585a 000c 0003 0018 0000 0000

    二、移植tslib

    参考:
    登陆http://www.tslib.org/下载最新的版本:
    https://github.com/kergoth/tslib/releases/download/1.10/tslib-1.10.tar.xz
    编译安装:
    #!/bin/bash
     
    ./autogen.sh
     
    mkdir install
     
    ./configure  
    --prefix="`pwd`/install" 
    --host=arm-linux  
    ac_cv_func_malloc_0_nonnull=yes
     
    make
    make install

    安装完成后,可以看到:

    $ls install
    bin/  etc/  include/  lib/  share/
    将这些文件拷贝到开发板上面,然后修改板子上面的/etc/profile文件,添加如下内容:
    echo "Set Env for Tslib"
    export TSLIB_ROOT=/
    export TSLIB_TSDEVICE=/dev/input/event0
    export TSLIB_CONFFILE=$TSLIB_ROOT/etc/ts.conf
    export TSLIB_PLUGINDIR=$TSLIB_ROOT/lib/ts
    export TSLIB_CALIBFILE=/etc/pointercal
    export TSLIB_CONSOLEDEVICE=none
    export TSLIB_FBDEVICE=/dev/fb0
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TSLIB_ROOT/lib

     修改完成后,重新启动开发板。

    三、测试

    运行ts_calibrate生成校准数据
    [root@tq2440 ]# ts_calibrate 
    xres = 480, yres = 272
    Took 4 samples...
    Top left : X =  870 Y =  279
    Took 8 samples...
    Top right : X =  162 Y =  277
    Took 5 samples...
    Bot right : X =  156 Y =  757
    Took 2 samples...
    Bot left : X =  688 Y =  660
    Took 3 samples...
    Center : X =  517 Y =  522
    582.617065 -0.602301 -0.108929
    -72.806641 0.023253 0.396149
    Calibration constants: 38182392 -39472 -7138 -4771456 1523 25962 65536 
    运行ts_test测试:
    [root@tq2440 ]# ts_test
    946785862.424089:    321    141      1
    946785862.444036:    321    141      0
    946785865.264038:     82    196      1
    946785865.284058:     82    196      0
    946785865.519036:     26    219      1
    946785865.539107:     29    219      1
    946785865.559054:     30    220      0
    946785865.829038:    229    206      1
    完。
  • 相关阅读:
    【转载】我的七个建议Joel Spolsky
    C语言文件读写操作
    【转】RO段、RW段和ZI段 Image$$??$$Limit 含义(zz)
    给大家一个测试webservice的软件
    .net 实现深拷贝的方法
    第一次设计数据访问层,大家给你建议,谢谢
    重新写博客
    (转)理解 Thread.Sleep 函数
    slk解压缩
    SMTP Service设置
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/6864251.html
Copyright © 2020-2023  润新知