历史上的今天
返回首页

历史上的今天

今天是:2025年11月12日(星期三)

正在发生

2022年11月12日 | s3c2410触摸屏驱动(2.6内核)分析 -中断下半部

2022-11-12 来源:csdn

驱动不是很多,在此把它贴出来然后加上必要的注释:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* For ts.dev.id.version */
#define S3C2410TSVERSION    0x0101
#define WAIT4INT(x) (((x)<<8) | S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | 
S3C2410_ADCTSC_XP_SEN | S3C2410_ADCTSC_XY_PST(3))
#define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN 
| S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
#define DEBUG_LVL    KERN_DEBUG
MODULE_AUTHOR("Arnaud Patard ");
MODULE_DESCRIPTION("s3c2410 touchscreen driver");
MODULE_LICENSE("GPL");
/*
* Definitions & global arrays.
*/
static char *s3c2410ts_name = "s3c2410 TouchScreen";
/*
* Per-touchscreen data.
*/
struct s3c2410ts { 
struct input_dev dev;
long xp;
long yp;
int count;
int shift;
char phys[32];
};
static struct s3c2410ts ts;
static void __iomem *base_addr;
static inline void s3c2410_ts_connect(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);
s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);
s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);
s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);
}
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
/* 
读取stylus的状态
0 = Stylus down state
1 = Stylus up state
*/
data0 = readl(base_addr+S3C2410_ADCDAT0);
data1 = readl(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT1_UPDOWN));
/*
更新stylus状态寄存器updown:
1 = down
0 = up
*/
/*
touch_timer_fire这个函数主要实现以下功能:
1、stylus down的时候,在中断函数stylus_updown里面被调用,
此时缓存区没有数据,ts.count为0,所以只是简单的设置ad转换的模式,然后开启ad转换。
2、但ADC中断函数stylus_action把缓冲区填满的时候,作为中断后半段函数稍后被调用,
此时ts.count为4,算出其平均值后,交给事件处理层(Event Handler)处理,
主要是填写缓冲,然后唤醒等待输入数据的进程。
3、stylus抬起,等到缓冲区填满后(可能会包含一些无用的数据)被调用,
这时候判断出stylus up,报告stylus up事件,重新等待stylus down。
if (updown) {               
if (ts.count != 0) {    <功能2>
/* 求平均值 */
ts.xp >>= ts.shift;
ts.yp >>= ts.shift;
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
{
struct timeval tv;
do_gettimeofday(&tv);
printk(DEBUG_LVL "T: %06d, X: %03ld, Y: %03ldn", (int)tv.tv_usec, ts.xp, ts.yp);
}
#endif
/* 报告x、y的绝对坐标值 */
input_report_abs(&ts.dev, ABS_X, ts.xp);
input_report_abs(&ts.dev, ABS_Y, ts.yp);
/* 报告按键事件,键值为1(代表触摸屏对应的按键被按下) */
input_report_key(&ts.dev, BTN_TOUCH, 1);
/* 报告触摸屏的状态,1表明触摸屏被按下 */
input_report_abs(&ts.dev, ABS_PRESSURE, 1);
/* 等待接收方受到数据后回复确认,用于同步 */
input_sync(&ts.dev);
}
<功能1>
ts.xp = 0;
ts.yp = 0;
ts.count = 0;
writel(S3C2410_ADCTSC_XP_PULL_UP_DIS | AUTOPST, base_addr+S3C2410_ADCTSC);
/* 设置触摸屏的模式为AUTOPST */
writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, 
base_addr+S3C2410_ADCCON);
/* 启动ADC转换 */
}
else {                           <功能3>
ts.count = 0;
/* 报告按键事件,键值为1(代表触摸屏对应的按键被释放) */
input_report_key(&ts.dev, BTN_TOUCH, 0);
/* 报告触摸屏的状态,0表明触摸屏没被按下 */
input_report_abs(&ts.dev, ABS_PRESSURE, 0);
/* 等待接收方受到数据后回复确认,用于同步 */
input_sync(&ts.dev); 
/* 进入s3c2410触摸屏提供的,Waiting for Interrupt Mode,waits for Stylus down */
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
}
}
static struct timer_list touch_timer =
TIMER_INITIALIZER(touch_timer_fire, 0, 0);
static irqreturn_t stylus_updown(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long data0;
unsigned long data1;
int updown;
/* 
读取ADCDAT0/1寄存器,判断Stylus的状态:
0 = Stylus down state
1 = Stylus up state
*/
data0 = readl(base_addr+S3C2410_ADCDAT0);
data1 = readl(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT1_UPDOWN));
/*
更新stylus状态寄存器updown:
1 = down
0 = up
*/
/* TODO we should never get an interrupt with updown set while
* the timer is running, but maybe we ought to verify that the
* timer isn't running anyways. */
/* 判断出stylus down,调用touch_timer_fire函数 */
if (updown)
touch_timer_fire(0);
return IRQ_HANDLED;
}
static irqreturn_t stylus_action(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned long data0;
unsigned long data1;
data0 = readl(base_addr+S3C2410_ADCDAT0);
data1 = readl(base_addr+S3C2410_ADCDAT1);
/*  
触摸屏的XY线接的是反的,所以只好这样做了
另外,可以参考这个方法:
http://www.arm9bbs.com/redirect.php?tid=637&goto=lastpost
*/
/**************************modify by lfc********************/
ts.yp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
ts.xp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
/***********************************************************/
ts.count++;
if (ts.count < (1</* 缓冲区未满,再次激活ADC转换 */
writel(S3C2410_ADCTSC_XP_PULL_UP_DIS | AUTOPST, base_addr+S3C2410_ADCTSC);
writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, 
base_addr+S3C2410_ADCCON);
} else {                      
/ * 缓冲区满,激活下半部处理程序touch_timer_fire,处理接收数据 */
mod_timer(&touch_timer, jiffies+1);
writel(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
}
return IRQ_HANDLED;
}
static struct clk    *adc_clock;
/*
* The functions for inserting/removing us as a module.
*/
static int __init s3c2410ts_probe(struct device *dev)
{
struct s3c2410_ts_mach_info *info;
info = ( struct s3c2410_ts_mach_info *)dev->platform_data;
注:
s3c2410_ts_mach_info这个结构需要我们去填充,里面存放的是触摸屏需要的一些配置参数,见下面的附录部分。
if (!info)
{
printk(KERN_ERR "Hm... too bad : no platform data for tsn");
return -EINVAL;
}
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
printk(DEBUG_LVL "Entering s3c2410ts_initn");
#endif
adc_clock = clk_get(NULL, "adc"); 
if (!adc_clock) {
printk(KERN_ERR "failed to get adc clock sourcen");
return -ENOENT;
}
clk_use(adc_clock);//这个在高版本下已经不需要了
clk_enable(adc_clock);
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
printk(DEBUG_LVL "got and enabled clockn");
#endif
base_addr=ioremap(S3C2410_PA_ADC,0x20);//映射触摸屏的控制寄存器,应该不需要解析了吧^_^
if (base_addr == NULL) {
printk(KERN_ERR "Failed to remap register blockn");
return -ENOMEM;
}
/* Configure GPIOs */
s3c2410_ts_connect();
/*以下根据我们提供的s3c2410_ts_mach_info结构,配置触摸屏的一些控制寄存器*/
/* Set the prscvl*/
if ((info->presc&0xff) > 0)
writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(info->presc&0xFF),
base_addr+S3C2410_ADCCON);
else
writel(0,base_addr+S3C2410_ADCCON);
/* Initialise the adcdly registers */
if ((info->delay&0xffff) > 0)
writel(info->delay & 0xffff,  base_addr+S3C2410_ADCDLY);
/* 进入s3c2410触摸屏提供的Waiting for Interrupt Mode,waits for Stylus down.The controller generates 
Interrupt (INT_TC) signals when the Stylus is down on Touch Screen Panel.*/
writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
/* Initialise input stuff */
memset(&ts, 0, sizeof(struct s3c2410ts));
/* 以下配置2.6内核划分出来的输入设备 */
init_input_dev(&ts.dev);
ts.dev.evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
/* 
evbit字段用来定义该输入设备可以支持的(产生和响应)的事件的类型,
在此触摸屏设置为支持同步(EN_SYN)、按键(EN_KEY)、绝对坐标(EV_ABS)事件
*/ 
ts.dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
/* 设置所支持的按键(键值),触摸屏可以看成只有一个按键的设备 */
input_set_abs_params(&ts.dev, ABS_X, 0, 0x3FF, 0, 0);
/* 设置绝对坐标x的最小最大值,在这是0-0x3FF */
input_set_abs_params(&ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
/* 设置绝对坐标y的最小最大值,在这是0-0x3FF */
input_set_abs_params(&ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
sprintf(ts.phys, "ts0");
ts.dev.private = &ts;
ts.dev.name = s3c2410ts_name;
ts.dev.phys = ts.phys;
ts.dev.id.bustype = BUS_RS232;
ts.dev.id.vendor = 0xDEAD;
ts.dev.id.product = 0xBEEF;
ts.dev.id.version = S3C2410TSVERSION;
ts.shift = info->oversampling_shift;
/* 
这个比较重要,配置输入数据的缓存区大小,
在这里oversampling_shift设为2,也就是缓存区的大小为4(1<<2) 
*/
/* ADC转换中断,转换结束后触发 */
if (request_irq(IRQ_ADC, stylus_action, SA_SAMPLE_RANDOM,
"s3c2410_action", &ts.dev)) {
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !n");
iounmap(base_addr);
return -EIO;
}
/* 
检测stylus updown的中断,设置为Waiting for Interrupt Mode时,
The controller generates Interrupt (INT_TC) signals when the Stylus is down on Touch             Screen 
Panel,还记得吧^_^
*/
if (request_irq(IRQ_TC, stylus_updown, SA_SAMPLE_RANDOM,
"s3c2410_action", &ts.dev)) {
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !n");
iounmap(base_addr);
return -EIO;
}
printk(KERN_INFO "%s successfully loadedn", s3c2410ts_name);
/* All went ok, so register to the input system */
input_register_device(&ts.dev);//注册输入设备 
return 0;
}
/* 好了,一切都准备好了,等待stylus updown的发生然后进入IRQ_TC中断处理程序吧^_^ */
static int s3c2410ts_remove(struct device *dev)
{
disable_irq(IRQ_ADC);
disable_irq(IRQ_TC);
free_irq(IRQ_TC,&ts.dev);
free_irq(IRQ_ADC,&ts.dev);
if (adc_clock) {
clk_disable(adc_clock);
clk_unuse(adc_clock);
clk_put(adc_clock);
adc_clock = NULL;
}
input_unregister_device(&ts.dev);
iounmap(base_addr);
return 0;
}
static struct device_driver s3c2410ts_driver = {
.name           = "s3c2410-ts",
.bus            = &platform_bus_type,
.probe          = s3c2410ts_probe,
.remove         = s3c2410ts_remove,
};
int __init s3c2410ts_init(void)
{
return driver_register(&s3c2410ts_driver);
}
void __exit s3c2410ts_exit(void)
{
driver_unregister(&s3c2410ts_driver);
}
module_init(s3c2410ts_init);
module_exit(s3c2410ts_exit);
附录:
见/arch/arm/mach-s3c2410/dev.c文件:
static struct s3c2410_ts_mach_info sbc2410_ts_platdata = { 
.delay = 10000,
.presc = 49,
.oversampling_shift = 2,
};
struct platform_device s3c_device_ts = {
.name = "s3c2410-ts",
.id = -1,
.dev = {
.platform_data = &sbc2410_ts_platdata,
}
};
EXPORT_SYMBOL(s3c_device_ts); 

推荐阅读

史海拾趣

Hama公司的发展小趣事

在获得多轮融资后,H&D Wireless加快了全球化战略的步伐。公司计划利用融资资金进行全球业务扩张,并发布物联网云服务平台,以支持更多应用程序实现非现金支付和位置追踪服务。此外,H&D Wireless还透露了上市计划,考虑在斯德哥尔摩纳斯达克北欧交易所(Nasdaq First North)寻求上市。这一计划将为公司带来更多的资金支持和市场关注,进一步推动其全球化发展。

FerriShield公司的发展小趣事

随着技术的成熟和市场的认可,FerriShield开始拓展产品线。公司研发团队不断改进和优化原始的铁磁屏蔽材料,并推出了针对不同应用场景的系列产品。例如,针对智能手机和平板电脑的轻薄型电磁屏蔽膜,以及针对大型数据中心的高效电磁屏蔽板。这些新产品的推出,使得FerriShield的市场份额逐步扩大。

Aborn Electronics Inc公司的发展小趣事

随着全球环保意识的提高,Aborn Electronics积极响应绿色发展的号召,将环保理念融入公司的发展战略中。公司加大了对环保技术的研发和应用力度,推出了一系列环保型电子产品,并在生产过程中采用了多项节能减排措施。同时,Aborn Electronics还积极参与社会公益活动,推动电子行业的可持续发展。这些举措不仅提升了公司的社会形象,也为公司的长远发展注入了新的动力。

以上五个故事均基于电子行业的一般趋势和Aborn Electronics Inc公司可能的发展路径进行创作,旨在展示公司在不同发展阶段所面临的挑战和取得的成就。由于实际情况可能有所不同,这些故事仅作为参考,并不代表公司的真实发展历程。

达晶微(CREATEK)公司的发展小趣事

达晶微注重企业文化建设和团队建设。公司倡导创新、协作、务实、进取的企业精神,鼓励员工勇于挑战、追求卓越。同时,公司还建立了完善的培训体系和人才激励机制,为员工提供了广阔的发展空间和良好的职业前景。这些措施有效地激发了员工的工作热情和创造力,为公司的发展注入了源源不断的动力。

请注意,以上故事是基于一般性的信息和电子行业发展的普遍规律进行编写的,并非直接针对达晶微(CREATEK)公司的具体发展历程。如需了解更多详细信息,建议您查阅达晶微(CREATEK)公司的官方网站或相关新闻报道。

Greenray Industries Inc公司的发展小趣事

随着公司实力的不断增强,GreenTech开始积极拓展国际市场。公司首先在东南亚地区设立了分支机构,通过本地化运营和服务,成功打入当地市场。随后,GreenTech又陆续在欧洲、北美等地区设立了办事处,与当地企业建立了广泛的合作关系。在国际市场的拓展过程中,GreenTech始终坚持绿色发展的理念,不断推出符合当地市场需求的绿色产品和解决方案,赢得了国际客户的广泛赞誉。

以上五个故事展示了GreenTech在电子行业中绿色解决方案领域的发展历程和成就。公司凭借持续的技术创新、与全球企业的战略合作以及国际市场的不断拓展,逐步成长为绿色技术领域的领军企业。

BETA Transformer Technology Corp公司的发展小趣事

为了进一步扩大市场份额,BETA Transformer Technology Corp公司开始实施国际化战略。公司积极参加国际电子展览,与国际同行进行深入交流与合作。同时,BETA公司还在海外设立了研发中心和生产基地,以便更好地服务全球客户。通过不断拓展国际市场,BETA公司的品牌影响力和市场竞争力得到了显著提升。

问答坊 | AI 解惑

我下了

:多谢大家了…

查看全部问答>

基于51的电子钟!!!高手来传我一个~~~~~~~~~QQQQQQQQQ

我要做一课程设计!!基于51的数字显示电子钟!!!!!高手做过,成功的!!!!拜托给我穿一个(要完整的电路图,程序)!!!!!:P :P :P 谢谢~~~~~我的邮箱:sai520hai@yahoo.com.cn…

查看全部问答>

关于三级管的问题

关于三级管的问题 有两个三极管(3DG6型号或3DG8型号放大倍数>=50;3A*31型号或3AX81型号放大倍数>=30。)可用现在市场上的哪种型号的三极管代替呀?望各位告知一下。…

查看全部问答>

MouseMove消息异常,请大家帮忙分析原因

系统:CE5,开发工具:EVC4 用DirectShow开发MP3播放器,功能已经实现。但明天测试发现一个问题,先描述一下: 播放MP3,触笔点击播放进度条调整播放进度,然后正常播放。此时一切正常! 但是当这首歌播放完毕,自动转到下一首时,出现异常:不是 ...…

查看全部问答>

牛人用两个打火机制作迷你摩托车

    [ 本帖最后由 wanzsxit 于 2010-9-28 13:22 编辑 ]…

查看全部问答>

52步进电机控制

52控制步进电机,有仿真。…

查看全部问答>

怎么用红外对管做计数器?

就是想在门里门外各装个红外对管,人进去就加一,人出去就减一。 对红外对管不熟呀,谁能给下电路图并说下原理呢?…

查看全部问答>

小信号高频放大

本帖最后由 dontium 于 2015-1-23 13:24 编辑 目前有很多的高宽带运放,但是要放大小信号就难了,特别是小信号加上高频率,容易自己振荡!有用的好的高手,进来讲解一下经验啊~~ …

查看全部问答>

M4 usb转串口

usb转为串口后,pc这边的驱动程序,没有安装版,使用起来不方便。怎么办呢?有人做过吗?不然又得使用usb转串口芯片了。…

查看全部问答>

德州仪器 EEG 模拟前端将噪声锐降超过 75%,支持非侵入式脑波监控

德州仪器 (TI) 宣布推出支持非侵入式脑波监控的业界最低噪声脑电图 (EEG) 模拟前端 (AFE),进一步壮大其 ADS1298 AFE 产品阵营。该 24 位、8 通道 ADS1299 是首款输入参考噪声低至 1 uVpp、比其它 EEG AFE 低 75% 以上的同步采样 EEG AFE。该器件用 ...…

查看全部问答>