平台


开发板:tq2440


内核:Linux-4.9


u-boot:u-boot-2015.04


 


概述


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


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


正文

一、移植触摸屏驱动


为了简单起见我们对TQ2440自带的触摸屏驱动进行改写,改成设备树的形式。


1、设备树


触摸屏使用了两个中断,如下:



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


这两个中断是子中断,隶属于主中断INT_ADC:



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


关于寄存器,参考​​芯片手册​​的第16章,知道了上面的信息,我们就可以得到如下的设备树节点:




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


代码如下:



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


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


编译安装:




#!/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


完。