s3c2440触摸屏.docx

上传人:b****7 文档编号:10319669 上传时间:2023-02-10 格式:DOCX 页数:16 大小:21.17KB
下载 相关 举报
s3c2440触摸屏.docx_第1页
第1页 / 共16页
s3c2440触摸屏.docx_第2页
第2页 / 共16页
s3c2440触摸屏.docx_第3页
第3页 / 共16页
s3c2440触摸屏.docx_第4页
第4页 / 共16页
s3c2440触摸屏.docx_第5页
第5页 / 共16页
点击查看更多>>
下载资源
资源描述

s3c2440触摸屏.docx

《s3c2440触摸屏.docx》由会员分享,可在线阅读,更多相关《s3c2440触摸屏.docx(16页珍藏版)》请在冰豆网上搜索。

s3c2440触摸屏.docx

s3c2440触摸屏

S3C2440上触摸屏驱动实例开发讲解

 (摘自:

建立触摸屏驱动程序my2440_ts.c,首先实现加载和卸载部分,在驱动加载部分,我们主要做的事情是:

启用ADC所需要的时钟、映射IO口、初始化寄存器、申请中断、初始化输入设备、将输入设备注册到输入子系统。

代码如下:

1.#include  

2.#include  

3.#include  

4.#include  

5.#include  

6.#include  

7.#include  

8.#include  

9.#include  

10. 

11./*用于保存从平台时钟列表中获取的ADC时钟*/ 

12.static struct clk *adc_clk; 

13./*定义了一个用来保存经过虚拟映射后的内存地址*/ 

14.static void __iomem *adc_base; 

15./*定义一个输入设备来表示我们的触摸屏设备*/ 

16.static struct input_dev *ts_dev; 

17./*设备名称*/ 

18.#define DEVICE_NAME    "my2440_TouchScreen" 

19./*定义一个WAIT4INT宏,该宏将对ADC触摸屏控制寄存器进行操作 

20.S3C2410_ADCTSC_YM_SEN这些宏都定义在regs-adc.h中*/ 

21.#define WAIT4INT(x)    (((x)<<8) | S3C2410_ADCTSC_YM_SEN |\

22.S3C2410_ADCTSC_YP_SEN |S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_XY_PST(3)) 

23. 

24.static int __init ts_init(void) 

25.{ 

26.    int ret; 

27. 

28./*从平台时钟队列中获取ADC的时钟,这里为什么要取得这个时钟,因为ADC的转换频率跟时钟有关。

 

29.系统的一些时钟定义在arch/arm/plat-s3c24xx/s3c2410-clock.c中*/ 

30.    adc_clk = clk_get(NULL, "adc"); 

31.    if(!

adc_clk) 

32.    { 

33./*错误处理*/ 

34.        printk(KERN_ERR "falied to find adc clock source\n"); 

35.        return -ENOENT; 

36.    } 

37. 

38./*时钟获取后要使能后才可以使用,clk_enable定义在arch/arm/plat-s3c/clock.c中*/ 

39.    clk_enable(adc_clk); 

40. 

41./*将ADC的IO端口占用的这段IO空间映射到内存的虚拟地址,ioremap定义在io.h中。

 

42.注意:

IO空间要映射后才能使用,以后对虚拟地址的操作就是对IO空间的操作, 

43.S3C2410_PA_ADC是ADC控制器的基地址,定义在mach-s3c2410/include/mach/map.h

44.中,0x20是虚拟地址长度大小*/ 

45.    adc_base = ioremap(S3C2410_PA_ADC, 0x20); 

46.    if(adc_base == NULL) 

47.    { 

48./*错误处理*/ 

49.        printk(KERN_ERR "failed to remap register block\n"); 

50.        ret = -EINVAL; 

51.        goto err_noclk; 

52.    } 

53. 

54./*初始化ADC控制寄存器和ADC 触摸屏控制寄存器*/ 

55.    adc_initialize(); 

56. 

57./*申请ADC中断,AD转换完成后触发。

这里使用共享中断IRQF_SHARED 是因为该中断号在ADC驱动

58.中也使用了,最后一个参数1是随便给的一个值,因为如果不给值设为NULL的话,中断就申请不成功*/ 

59.    ret = request_irq(IRQ_ADC, adc_irq, IRQF_SHARED |\

60.IRQF_SAMPLE_RANDOM, DEVICE_NAME, 1); 

61.    if(ret) 

62.    { 

63.        printk(KERN_ERR "IRQ%d error %d\n", IRQ_ADC, ret); 

64.        ret = -EINVAL; 

65.        goto err_nomap; 

66.    } 

67. 

68./*申请触摸屏中断,对触摸屏按下或提笔时触发*/ 

69.    ret = request_irq(IRQ_TC, tc_irq, IRQF_SAMPLE_RANDOM, DEVICE_NAME, 1); 

70.    if(ret) 

71.    { 

72.        printk(KERN_ERR "IRQ%d error %d\n", IRQ_TC, ret); 

73.        ret = -EINVAL; 

74.        goto err_noirq; 

75.    } 

76. 

77./*给输入设备申请空间,input_allocate_device定义在input.h中*/ 

78.    ts_dev = input_allocate_device(); 

79. 

80./*下面初始化输入设备,即给输入设备结构体input_dev的成员设置值。

 

81.evbit字段用于描述支持的事件,这里支持同步事件、按键事件、绝对坐标事件, 

82.BIT宏实际就是对1进行位操作,定义在linux/bitops.h中*/ 

83.    ts_dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); 

84.     

85./*keybit字段用于描述按键的类型,在input.h中定义了很多,

86.这里用BTN_TOUCH类型来表示触摸屏的点击*/ 

87.    ts_dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH); 

88. 

89./*对于触摸屏来说,使用的是绝对坐标系统。

这里设置该坐标系统中X和Y坐标的最小值和最大值

90.(0-1023范围)ABS_X和ABS_Y就表示X坐标和Y坐标,ABS_PRESSURE就表示触摸屏是按下还是抬起状态*/ 

91.    input_set_abs_params(ts_dev, ABS_X, 0, 0x3FF, 0, 0); 

92.    input_set_abs_params(ts_dev, ABS_Y, 0, 0x3FF, 0, 0); 

93.    input_set_abs_params(ts_dev, ABS_PRESSURE, 0, 1, 0, 0); 

94. 

95./*以下是设置触摸屏输入设备的身份信息,直接在这里写死。

 

96.    这些信息可以在驱动挂载后在/proc/bus/input/devices中查看到*/ 

97.    ts_dev->name          = DEVICE_NAME;   /*设备名称*/ 

98.    ts_dev->id.bustype    = BUS_RS232;     /*总线类型*/     

99.    ts_dev->id.vendor     = 0xDEAD;        /*经销商ID号*/ 

100.    ts_dev->id.product    = 0xBEEF;        /*产品ID号*/ 

101.    ts_dev->id.version    = 0x0101;        /*版本ID号*/ 

102. 

103./*好了,一些都准备就绪,现在就把 ts_dev触摸屏设备注册到输入子系统中*/ 

104.    input_register_device(ts_dev); 

105. 

106.    return 0; 

107. 

108./*下面是错误跳转处理*/ 

109.err_noclk:

 

110.    clk_disable(adc_clk); 

111.    clk_put(adc_clk); 

112. 

113.err_nomap:

 

114.    iounmap(adc_base); 

115. 

116.err_noirq:

 

117.    free_irq(IRQ_ADC, 1); 

118. 

119.    return ret; 

120.} 

121. 

122./*初始化ADC控制寄存器和ADC触摸屏控制寄存器*/ 

123.static void adc_initialize(void) 

124.{ 

125./*计算结果为(二进制):

111111111000000,再根据数据手册得知 

126.此处是将AD转换预定标器值设为255、AD转换预定标器使能有效*/ 

127.    writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF), adc_base  S3C2410_ADCCON); 

128. 

129.    /*对ADC开始延时寄存器进行设置,延时值为0xffff*/ 

130.    writel(0xffff, adc_base  S3C2410_ADCDLY); 

131. 

132.    /*WAIT4INT宏计算结果为(二进制):

11010011,再根据数据手册得知 

133.    此处是将ADC触摸屏控制寄存器设置成等待中断模式*/ 

134.    writel(WAIT4INT(0), adc_base  S3C2410_ADCTSC); 

135.} 

136. 

137.static void __exit ts_exit(void) 

138.{ 

139.    /*屏蔽和释放中断*/ 

140.    disable_irq(IRQ_ADC); 

141.    disable_irq(IRQ_TC); 

142.    free_irq(IRQ_ADC, 1); 

143.    free_irq(IRQ_TC, 1); 

144. 

145.    /*释放虚拟地址映射空间*/ 

146.    iounmap(adc_base); 

147. 

148.    /*屏蔽和销毁时钟*/ 

149.    if(adc_clk) 

150.    { 

151.        clk_disable(adc_clk); 

152.        clk_put(adc_clk); 

153.        adc_clk = NULL; 

154.    } 

155. 

156.    /*将触摸屏设备从输入子系统中注销*/ 

157.    input_unregister_device(ts_dev); 

158.} 

159. 

160.module_init(ts_init); 

161.module_exit(ts_exit); 

162. 

163.MODULE_LICENSE("GPL"); 

164.MODULE_AUTHOR("Huang Gang"); 

165.MODULE_DESCRIPTION("My2440 Touch Screen Driver"); 

3、接下来要做的是,在两个中断服务程序中实现触摸屏状态和坐标的转换。

先看代码,如下:

1./*定义一个外部的信号量ADC_LOCK,因为ADC_LOCK在ADC驱动程序中已申明 

2.这样就能保证ADC资源在ADC驱动和触摸屏驱动中进行互斥访问*/ 

3.extern struct semaphore ADC_LOCK; 

4. 

5./*做为一个标签,只有对触摸屏操作后才对X和Y坐标进行转换*/ 

6.static int OwnADC = 0; 

7. 

8./*用于记录转换后的X坐标值和Y坐标值*/ 

9.static long xp; 

10.static long yp; 

11. 

12./*用于计数对触摸屏压下或抬起时模拟输入转换的次数*/ 

13.static int count; 

14. 

15./*定义一个AUTOPST宏,将ADC触摸屏控制寄存器设置成自动转换模式*/ 

16.#define AUTOPST    (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN\

17.| S3C2410_ADCTSC_XP_SEN |S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0)) 

18. 

19. 

20./*触摸屏中断服务程序,对触摸屏按下或提笔时触发执行*/ 

21.static irqreturn_t tc_irq(int irq, void *dev_id) 

22.{ 

23.    /*用于记录这一次AD转换后的值*/ 

24.    unsigned long data0; 

25.    unsigned long data1; 

26. 

27.    /*用于记录触摸屏操作状态是按下还是抬起*/ 

28.    int updown; 

29. 

30.    /*ADC资源可以获取,即上锁*/ 

31.    if (down_trylock(&ADC_LOCK) == 0) 

32.    { 

33.        /*标识对触摸屏进行了操作*/ 

34.        OwnADC = 1; 

35. 

36.        /*读取这一次AD转换后的值,注意这次主要读的是状态*/ 

37.        data0 = readl(adc_base  S3C2410_ADCDAT0); 

38.        data1 = readl(adc_base  S3C2410_ADCDAT1); 

39. 

40./*记录这一次对触摸屏是压下还是抬起,该状态保存在数据寄存器的第15位,

41.所以与上 S3C2410_ADCDAT0_UPDOWN*/ 

42.updown = (!

(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!

(data1 & S3C2410_ADCDAT0_UPDOWN)); 

43. 

44.        /*判断触摸屏的操作状态*/ 

45.        if (updown) 

46.        { 

47./*如果是按下状态,则调用touch_timer_fire函数来启动ADC转换,该函数定义后面再讲*/ 

48.            touch_timer_fire(0); 

49.        } 

50.        else 

51.        { 

52./*如果是抬起状态,就结束了这一次的操作,所以就释放ADC资源的占有*/ 

53.            OwnADC = 0; 

54.            up(&ADC_LOCK); 

55.        } 

56.    } 

57. 

58.    return IRQ_HANDLED; 

59.} 

60. 

61.static void touch_timer_fire(unsigned long data) 

62.{ 

63.    /*用于记录这一次AD转换后的值*/ 

64.      unsigned long data0; 

65.      unsigned long data1; 

66. 

67.    /*用于记录触摸屏操作状态是按下还是抬起*/ 

68.    int updown; 

69. 

70.    /*读取这一次AD转换后的值,注意这次主要读的是状态*/ 

71.    data0 = readl(adc_base  S3C2410_ADCDAT0); 

72.    data1 = readl(adc_base  S3C2410_ADCDAT1); 

73. 

74./*记录这一次对触摸屏是压下还是抬起,该状态保存在数据寄存器的第15位,

75.所以与上 S3C2410_ADCDAT0_UPDOWN*/ 

76.updown = (!

(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!

(data1 & S3C2410_ADCDAT0_UPDOWN)); 

77. 

78.    /*判断触摸屏的操作状态*/ 

79.     if (updown) 

80.    { 

81.        /*如果状态是按下,并且ADC已经转换了就报告事件和数据*/ 

82.         if (count !

= 0) 

83.        { 

84.            long tmp; 

85.                                                                                                  

86.            tmp = xp; 

87.            xp = yp; 

88.            yp = tmp; 

89.                                                                                                  

90.            xp >>= 2; 

91.            yp >>= 2; 

92. 

93.#ifdef CONFIG_TOUCHSCREEN_MY2440_DEBUG 

94./*触摸屏调试信息,编译内核时选上此项后,点击触摸屏会在终端上打印出坐标信息*/ 

95.struct timeval tv; 

96.do_gettimeofday(&tv); 

97.printk(KERN_DEBUG "T:

 %06d, X:

 %03ld, Y:

 %03ld\n", (int)tv.tv_usec, xp, yp); 

98.#endif 

99. 

100./*报告X、Y的绝对坐标值*/ 

101.input_report_abs(ts_dev, ABS_X, xp); 

102.input_report_abs(ts_dev, ABS_Y, yp); 

103. 

104./*报告触摸屏的状态,1表明触摸屏被按下*/ 

105.input_report_abs(ts_dev, ABS_PRESSURE, 1); 

106. 

107./*报告按键事件,键值为1(代表触摸屏对应的按键被按下)*/ 

108.input_report_key(ts_dev, BTN_TOUCH, 1); 

109. 

110./*等待接收方受到数据后回复确认,用于同步*/ 

111.input_sync(ts_dev); 

112.} 

113. 

114./*如果状态是按下,并且ADC还没有开始转换就启动ADC进行转换*/ 

115.xp = 0; 

116.yp = 0; 

117.count = 0; 

118./*设置触摸屏的模式为自动转换模式*/ 

119.writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, adc_base  S3C2410_ADCTSC); 

120. 

121./*启动ADC转换*/ 

122.writel(readl(adc_base  S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,

123. adc_base  S3C2410_ADCCON); 

124.} 

125.    else 

126.    { 

127./*否则是抬起状态*/ 

128.count = 0; 

129./*报告按键事件,键值为0(代表触摸屏对应的按键被释放)*/ 

130.input_report_key(ts_dev, BTN_TOUCH, 0); 

131./*报告触摸屏的状态,0表明触摸屏没被按下*/ 

132.input_report_abs(ts_dev, ABS_PRESSURE, 0); 

133./*等待接收方受到数据后回复确认,用于同步*/ 

134.input_sync(ts_dev); 

135./*将触摸屏重新设置为等待中断状态*/ 

136.writel(WAIT4INT(0), adc_base  S3C2410_ADCTSC); 

137./*如果触摸屏抬起,就意味着这一次的操作结束,所以就释放ADC资源的占有*/ 

138.if (OwnADC) 

139.{ 

140.OwnADC = 0; 

141.up(&ADC_LOCK); 

142.} 

143.} 

144.} 

145. 

146./*定义并初始化了一个定时器touch_timer,定时器服务程序为touch_timer_fire*/ 

147.static struct timer_list touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0); 

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 设计艺术

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1