平台
开发板: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 =
reg-names = "adc_ts_physical";
interrupts =
interrupt-names = "int_ts", "int_adc_s";
clocks =
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
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 #include
19 #include
20 #include
21 #include
22
23 #include
24 #include
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 NULLn");
146 return -EINVAL;
147 }
148
149 adc_clock = devm_clk_get(dev, "adc");
150 dev_dbg(dev, "adc_clock: %pn", adc_clock);
151 if (IS_ERR(adc_clock)) {
152 dev_err(dev, "cannot get clockn");
153 return -ENOENT;
154 }
155 clk_prepare(adc_clock);
156 clk_enable(adc_clock);
157
158 dev_dbg(dev, "get memn");
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);
百检网秉承“客户至上,服务为先,精诚合作,以人为本”的经营理念,始终站在用户的角度解决问题,为客户提供“一站购物式”的新奇检测体验,打开网站,像挑选商品一样简单,方便。打破行业信息壁垒,建构消费和检测机构之间高效的沟通平台