基于设备树的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\n");
146         return -EINVAL;
147     }
148 
149     adc_clock = devm_clk_get(dev, "adc");
150     dev_dbg(dev, "adc_clock: %p\n", adc_clock);
151     if (IS_ERR(adc_clock)) {
152         dev_err(dev, "cannot get clock\n");
153         return -ENOENT;
154     }
155     clk_prepare(adc_clock);
156     clk_enable(adc_clock);
157 
158     dev_dbg(dev, "get mem\n");
159     tsmem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "adc_ts_physical");
160     if (!tsmem) {
161         dev_dbg(dev, "get mem resource failed.\n");
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.\n");
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.\n");
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.\n");
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.\n", 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.\n");
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.\n", irq->start);
224         goto err;
225     }
226 
227     dev_info(dev, "%s successfully loaded\n", 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
完。
posted @ 2017-05-16 23:12  dolinux  阅读(1783)  评论(0编辑  收藏  举报