天天看点

触摸屏驱动笔记

这是我看韦东山第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

继续阅读