這是我看韋東山第2期視訊觸摸屏驅動的一些筆記,記錄友善以後學習。
觸摸屏歸納為輸入子系統,這裡主要是針對電阻屏,其使用過程如下
當用觸摸筆按下時,産生中斷。
在中斷處理函數處理函數中啟動ADC轉換x,y坐标。
ADC結束,産生ADC中斷
在ADC中斷處理函數裡上報(input_event)啟動定時器
再次啟動定時器(可以處理滑動、長按)
松開按鍵
其驅動程式的寫法和之前寫輸入子系統的寫法基本上一緻。
寫出入口函數,出口函數并加以修飾,加入相關頭檔案,然後開始完善各函數,在入口函數中配置設定input_dev結構體,設定(能産生哪類事件,能産生這類事件中的哪些事件),注冊裝置,硬體相關的操作等。出口函數中主要對之前注冊、配置設定的一些資源進行釋放。
還應根據2440資料手冊ADC轉換和觸摸屏那一章,對相關寄存器根據實際需要進行設定。
1. #include <linux/errno.h>
2. #include <linux/kernel.h>
3. #include <linux/module.h>
4. #include <linux/slab.h>
5. #include <linux/input.h>
6. #include <linux/init.h>
7. #include <linux/serio.h>
8. #include <linux/delay.h>
9. #include <linux/platform_device.h>
10. #include <linux/clk.h>
11. #include <asm/io.h>
12. #include <asm/irq.h>
13.
14. #include <asm/plat-s3c24xx/ts.h>
15.
16. #include <asm/arch/regs-adc.h>
17. #include <asm/arch/regs-gpio.h>
18.
19. struct s3c_ts_regs {
20. unsigned long adccon;
21. unsigned long adctsc;
22. unsigned long adcdly;
23. unsigned long adcdat0;
24. unsigned long adcdat1;
25. unsigned long adcupdn;
26. };
27.
28. static struct input_dev *s3c_ts_dev;
29. static volatile struct s3c_ts_regs *s3c_ts_regs;
30.
31. static struct timer_list ts_timer;
32.
33. void enter_wait_pen_down_mode(void)
34. {
35. s3c_ts_regs->adctsc = 0xd3;
36. }
37.
38. void enter_wait_pen_up_mode(void)
39. {
40. s3c_ts_regs->adctsc = 0x1d3;
41. }
42.
43. static void enter_measure_xy_mode(void)
44. {
45. s3c_ts_regs->adctsc = (1<<3) | (1<<2);
46. }
47.
48. static void start_adc(void)
49. {
50. s3c_ts_regs->adccon |= (1<<0);
51. }
52.
53. static int s3c_filter_ts(int x[], int y[])
54. {
55. #define ERR_LIMIT 10
56.
57. int avr_x, avr_y;
58. int det_x, det_y;
59.
60. avr_x = (x[0] + x[1])/2;
61. avr_y = (y[0] + y[1])/2;
62.
63. det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);
64. det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);
65.
66. if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
67. return 0;
68.
69. avr_x = (x[1] + x[2])/2;
70. avr_y = (y[1] + y[2])/2;
71.
72. det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);
73. det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);
74.
75. if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
76. return 1;
77. }
78.
79. static void s3c_ts_timer_functions(unsigned long data)
80. {
81. if (s3c_ts->adcdat0 & (1<<15))
82. {
83.
84. input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
85. input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
86. input_sync(s3c_ts_dev);
87. enter_wait_pen_down_mode();
88. }
89. else
90. {
91.
92. enter_measure_xy_mode();
93. start_adc();
94. }
95.
96. }
97.
98. static irqreturn_t pen_down_up_irq(int irq, void *dev id)
99. {
100. if (s3c_ts->adcdat0 & (1<<15))
101. {
102. printk("pen up\n");
103. enter_wait_pen_down_mode();
104. }
105. else
106. {
107. //printk("pen down\n");
108. //enter_wait_pen_up_mode();
109. enter_measure_xy_mode();
110. start_adc();
111. }
112. return IRQ_HANDLED;
113. }
114.
115. static irqreturn_t adc_irq(int irq, void *dev id)
116. {
117. static int cnt = 0;
118. static int x[4], y[4];
119. int adcdat0, adcdat1;
120.
123. adcdat0 = s3c_ts_regs->adcdat0;
124. adcdat1 = s3c_ts_regs->adcdat1;
125. if (s3c_ts->adcdat0 & (1<<15))
126. {
127.
128. cnt = 0;
129. input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
130. input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
131. input_sync(s3c_ts_dev);
132. enter_wait_pen_up_mode();
133. }
134. else
135. {
136.
137. //printk("adc_irq cnt = %d,x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff);
138.
139.
142. x[cnt] = adcdat0 & 0x3ff;
143. y[cnt] = adcdat1 & 0x3ff;
144. ++cnt;
145. if (cnt == 4)
146. {
147.
150. if (s3c_filter_ts(x, y))
151. {
152. //printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);
153. input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);
154. input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);
155. input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
156. input_report_key(s3c_ts_dev, BTN_TOUCH, 1);
157. input_sync(s3c_ts_dev);
158. }
159. cnt = 0;
160. enter_wait_pen_up_mode();
161.
162.
163. mod_timer(&ts_timer, jiffies + HZ/100);
164. }
165. else
166. {
167. enter_measure_xy_mode();
168. start_adc();
169. }
170. }
171. return IRQ_HANDLED;
172. }
173.
174. static int s3c_ts_init(void)
175. {
176. struct clk* clk;
177.
178. s3c_ts_dev = input_allocate_device();
179.
180.
181. set_bit(EV_KEY, s3c_ts_dev->evbit);
182. set_bit(EV_ABS, s3c_ts_dev->evbit);
183.
184.
185. set_bit(BTN_TOUCH, s3c_ts_dev->evbit);
186.
187. input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
188. input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
189. input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
190.
191.
192.
193. input_register_device(s3c_ts_dev);
194.
195.
196.
197. clk = clk_get(NULL, "adc");
198. clk_enable(clk);
199.
200.
201. s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
202.
211. s3c_ts_regs->adccon = (1<<14) | (49<<6);
212. request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
213. request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
214.
215.
218. s3c_ts_regs->adcdly = 0xffff;
219.
220.
223. init_timer(&ts_timer);
224. ts_timer.function = s3c_ts_timer_function;
225. add_timer(&ts_timer);
226.
227. enter_wait_pen_down_mode();
228. return 0;
229. }
230.
231. static void s3c_ts_exit(void)
232. {
233. free_irq(IRQ_TC, NULL);
234. free_irq(IRQ_ADC, NULL);
235. iounmap(s3c_ts_regs);
236. input_unregister_device(s3c_ts_dev);
237. input_free_device(s3c_ts_dev);
238. del_timer(&ts_timer);
239. }
240.
241.
242. module_init(s3c_ts_init);
243. module_exit(s3c_ts_exit);
244.
245. MODULE_DESCRIPTION("s3c_ts driver for the s3c2440");
246. MODULE_LICENSE("GPL");
測試方法主要是檢測上報事件是否正常,要想更好的測試,需要移植ts_lib這方面的資料網上都可以找到。
以tslib-1.4.tar.gz為例
sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool
編譯:
tar xzf tslib-1.4.tar.gz
cd tslib
./autogen.sh
mkdir tmp // 安裝目錄
echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache
./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp
make
make install
安裝:
cd tmp
cp * -rf /nfsroot // /nfsroot可根據實際情況來定
使用:
先安裝s3c_ts.ko, lcd.ko // lcd.ko是之前編譯好的LCD驅動,如果後面編譯s3c_ts時改過配置,直接裝載之前編譯好的lcd.ko可能會出現段錯誤,重新編譯一下lcd驅動就可以了。
1.
修改 /etc/ts.conf第1行(去掉#号和第一個空格):
# module_raw input
改為:
module_raw input
2.
export TSLIB_TSDEVICE=/dev/event0
export TSLIB_CALIBFILE=/etc/pointercal
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/lib/ts
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
ts_calibrate
ts_test