分类: 嵌入式
2015-06-01 19:18:39
触摸屏驱动
15年6月1日19:17:30
程序如下:
1
2
#include
3
#include
4
#include
5
#include
6
#include
7
#include
8
#include
9
#include
10
#include
11
#include
12
#include
13
#include
14
#include
15
16
#include
17
18
#include
19
#include
20
21 static struct s3c_ts_regs {
22 unsigned long adccon;
23 unsigned long adctsc;
24 unsigned long adcdly;
25 unsigned long adcdat0;
26 unsigned long adcdat1;
27 unsigned long adcupdn;
28 };
29
30 static struct input_dev *s3c_ts_dev;
31 static struct timer_list s3c_ts_timer;
32
33 static volatile struct s3c_ts_regs *s3c_ts_regs;
34
35 static void enter_wait_pen_down_mode()
36 {
37 s3c_ts_regs->adctsc = 0xd3;
38 }
39
40 static void enter_wait_pen_up_mode()
41 {
42 s3c_ts_regs->adctsc = 0x1d3;
43 }
44
45 static void enter_measure_xy_mode(void)
46 {
47 s3c_ts_regs->adctsc = (1<<2) | (1<<3);
48 }
49
50 static void start_adc(void)
51 {
52 s3c_ts_regs->adccon |= (1<<0);
53 }
54
55 static int s3c_filter_ts(int x[], int y[])
56 {
57 #define ERR_LIMIT 10
58 int avr_x, avr_y;
59 int det_x, det_y;
60
61 avr_x = (x[0] + x[1])/2;
62 avr_y = (y[0] + y[1])/2;
63
64 det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]);
65 det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]);
66
67 if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT))
68 return 0;
69
70 avr_x = (x[1] + x[2])/2;
71 avr_y = (y[1] + y[2])/2;
72
73 det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]);
74 det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]);
75
76 if ((det_x > ERR_LIMIT) | (det_y > ERR_LIMIT))
77 return 0;
78
79 return 1;
80
81 }
82
83 static irqreturn_t adc_irq(int irq, void *dev_id)
84 {
85 static int cnt = 0;
86 int adcdat0, adcdat1;
87 static int x[4], y[4];
88
89 adcdat0 = s3c_ts_regs->adcdat0;
90 adcdat1 = s3c_ts_regs->adcdat1;
91
92 if (s3c_ts_regs->adcdat0 & (1<<15))
93 {
94 cnt = 0;
95 input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0);
96 input_report_key(s3c_ts_dev, BTN_TOUCH, 0);
97
98 enter_wait_pen_down_mode();
99 }
100 else
101 {
102 x[cnt] = s3c_ts_regs->adcdat0 & 0x3ff;
103 y[cnt] = s3c_ts_regs->adcdat1 & 0x3ff;
104 ++cnt;
105
106 if (cnt == 4)
107 {
108 if (s3c_filter_ts(x, y))
109 {
110 //printk("x = %d, ,y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4);
111 input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4);
112 input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4);
113 input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1);
114 input_report_key(s3c_ts_dev, BTN_TOUCH, 1);
115
116 }
117
118 cnt = 0;
119 enter_wait_pen_up_mode();
120
121 mod_timer(&s3c_ts_timer, jiffies + HZ/100);
122 }
123 else
124 {
125 enter_measure_xy_mode();
126 start_adc();
127 }
128 //printk("cnt = %d, x = %d, ,y = %d\n", ++cnt, s3c_ts_regs->adcdat0 & 0x3ff, s3c_ts_regs->adcdat1 & 0x3ff);
129 }
130 return IRQ_HANDLED;
131 }
132
133 static irqreturn_t pen_down_up_irq(int irq, void *dev_id)
134 {
135 if(s3c_ts_regs->adcdat0 & (1<<15))
136 {
137 printk("pen up!\n");
138 enter_wait_pen_down_mode();
139 }
140 else
141 {
142 //printk("pen down!\n");
143 //enter_wait_pen_up_mode();
144 enter_measure_xy_mode();
145 start_adc();
146 }
147 return IRQ_HANDLED;
148 }
149
150 static void s3c_ts_timer_function (unsigned long data)
151 {
152 if(s3c_ts_regs->adcdat0 & (1<<15))
153 {
154 enter_wait_pen_down_mode();
155 }
156 else
157 {
158 enter_measure_xy_mode();
159 start_adc();
160 }
161 }
162
163 static int s3c_ts_init(void)
164 {
165 struct clk* clk;
166
167 /* 1. 分配 input_dev 结构体 */
168 s3c_ts_dev = input_allocate_device();
169
170 /* 2. 设置 */
171 /* 2.1 neng chan sheng na lei shi jian */
172 set_bit(EV_KEY, s3c_ts_dev->evbit);
173 set_bit(EV_ABS, s3c_ts_dev->evbit);
174
175 /*2.2 能产生这类事件的哪些事件 */
176 set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
177
178 input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0);
179 input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0);
180 input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);
181
182
183 /* 3. 注册 */
184 input_register_device(s3c_ts_dev);
185
186 /* 4. 硬件相关操作 */
187 /* 4.1 使能时钟 */
188 clk = clk_get(NULL, "adc");
189 clk_enable(clk);
190
191 /* 4.2 设置 s3c2440 adc/ts 寄存器 */
192 s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs));
193
194 /* bit[14]: 1. A/D converter prescaler enable
195 * bit[13:6]: 49. A/D converter prescaler value
196 * ADCCLK = PCLK/(49+1) = 50MHZ/(50) = 1MHZ.
197 * bit[0] :0. A/D conversion starts by enable.
198 */
199 s3c_ts_regs->adccon = (1<<14) | (49<<6);
200
201 request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL);
202 request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL);
203
204 /* 优化措施1 1 */
205 s3c_ts_regs->adcdly = 0xffff;
206
207 init_timer(&s3c_ts_timer);
208 s3c_ts_timer.function = s3c_ts_timer_function;
209 add_timer(&s3c_ts_timer);
210
211 enter_wait_pen_down_mode();
212
213 return 0;
214 }
215
216 static void s3c_ts_exit()
217 {
218 free_irq(IRQ_TC, NULL);
219 free_irq(IRQ_ADC, NULL);
220 iounmap(s3c_ts_regs);
221 input_unregister_device(s3c_ts_dev);
222 input_free_device(s3c_ts_dev);
223 del_timer(&s3c_ts_timer);
224 }
225
226 module_init(s3c_ts_init);
227 module_exit(s3c_ts_exit);
228
229 MODULE_LICENSE("GPL");
230
总体上来说,从驱动角度看,没有什么难点,就是一个输入子系统,外加各种字符驱动的操作,主要难在硬件相关的操作以及一些优化思想上面。