static irqreturn_t adc_irq(int irq, void *dev_id) { static int cnt = 0; int adcdat0, adcdat1; #if 1 /* 优化措施2: 如果ADC完成时, 发现触摸笔已经松开, 则丢弃此次结果 */ adcdat0 = s3c_ts_regs->adcdat0; adcdat1 = s3c_ts_regs->adcdat1; if (s3c_ts_regs->adcdat0 & (1<<15)) /* 已经松开 */ { enter_wait_pen_down_mode(); } else { printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, adcdat0 & 0xfff, adcdat1 & 0xfff); enter_wait_pen_up_mode(); } #endif #if 0 printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt,(int) (s3c_ts_regs->adcdat0 & 0xfff), (int) (s3c_ts_regs->adcdat1 & 0xfff)); enter_wait_pen_up_mode(); #endif return IRQ_HANDLED; }
static void s3c_ts_timer_function(unsigned long data) { int adcdat0, adcdat1; int updown; /* 优化措施2: 如果ADC完成时, 发现触摸笔已经松开, 则丢弃此次结果 */ adcdat0 = s3c_ts_regs->adcdat0; adcdat1 = s3c_ts_regs->adcdat1; /* dat0和dat1中bit15都是0, updown才是0, 0是down state */ updown =! (!(adcdat0 & (1<<15))) && (!(adcdat1 & (1<<15))); if (s3c_ts_regs->adcdat1 & (1<<15)) // if(updown) { /* 已经松开 */ enter_wait_pen_down_mode(); } else { /* 测量X/Y坐标 */ enter_measure_xy_mode(); start_adc(); } }
static int s3c_ts_init(void) { struct clk* clk; /* 1. 分配一个input_dev结构体 */ s3c_ts_dev = input_allocate_device(); /* 2. 设置 */ /* 2.1 能产生哪类事件 */ set_bit(EV_KEY, s3c_ts_dev->evbit); set_bit(EV_ABS, s3c_ts_dev->evbit); /* 2.2 能产生这类事件里的哪些事件 */ set_bit(BTN_TOUCH, s3c_ts_dev->keybit); input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0); input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0); /* 3. 注册 */ input_register_device(s3c_ts_dev); /* 4. 硬件相关的操作 */ /* 4.1 使能时钟(CLKCON[15]) */ clk = clk_get(NULL, "adc"); clk_enable(clk); /* 4.2 设置S3C2416的ADC/TS寄存器 */ s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs)); /* bit[14] : 1-A/D converter prescaler enable * bit[13:6]: A/D converter prescaler value, * 65, ADCCLK=PCLK/(49+1)=66.6MHz/(65+1)=1MHz * bit[0]: A/D conversion starts by enable. 先设为0 */ s3c_ts_regs->adccon = (1<<14)|(65<<6); // request_irq(IRQ_TC, pen_down_up_irq, SA_SAMPLE_RANDOM, "ts_pen", NULL); request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL); request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL); /* 优化错施1: * 设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断 */ s3c_ts_regs->adcdly = 0xffff; /* 优化措施5: 使用定时器处理长按,滑动的情况 * */ init_timer(&ts_timer); ts_timer.function = s3c_ts_timer_function; add_timer(&ts_timer); enter_wait_pen_down_mode(); return 0; }
static irqreturn_t adc_irq(int irq, void *dev_id) { static int cnt = 0; static int x[4], y[4]; int adcdat0, adcdat1; /* 优化措施2: 如果ADC完成时, 发现触摸笔已经松开, 则丢弃此次结果 */ adcdat0 = s3c_ts_regs->adcdat0; adcdat1 = s3c_ts_regs->adcdat1; if (s3c_ts_regs->adcdat0 & (1<<15)) { /* 已经松开 */ cnt = 0; input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); input_report_key(s3c_ts_dev, BTN_TOUCH, 0); input_sync(); enter_wait_pen_down_mode(); } else { // printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, adcdat0 & 0x3ff, adcdat1 & 0x3ff); /* 优化措施3: 多次测量求平均值 */ x[cnt] = adcdat0 & 0x3ff; y[cnt] = adcdat1 & 0x3ff; ++cnt; if (cnt == 4) { /* 优化措施4: 软件过滤 */ if (s3c_filter_ts(x, y)) { //printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4); input_report_abs(s3c_ts_dev, ABS_X, (x[0]+x[1]+x[2]+x[3])/4); input_report_abs(s3c_ts_dev, ABS_Y, (y[0]+y[1]+y[2]+y[3])/4); input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1); input_report_key(s3c_ts_dev, BTN_TOUCH, 1); input_sync(); } cnt = 0; enter_wait_pen_up_mode(); /* 启动定时器处理长按/滑动的情况 */ mod_timer(&ts_timer, jiffies + HZ/100); } else { enter_measure_xy_mode(); start_adc(); } } return IRQ_HANDLED; }
static irqreturn_t adc_irq(int irq, void *dev_id) { static int cnt = 0; int adcdat0, adcdat1; static int x[4], y[4]; int updown; #if 1 /* 优化措施2: 如果ADC完成时, 发现触摸笔已经松开, 则丢弃此次结果 */ adcdat0 = s3c_ts_regs->adcdat0; adcdat1 = s3c_ts_regs->adcdat1; /* dat0和dat1中bit15都是0, updown才是0, 0是down state */ updown =! (!(adcdat0 & (1<<15))) && (!(adcdat1 & (1<<15))); if (updown) /* 已经松开 */ { cnt = 0; enter_wait_pen_down_mode(); /* 进入等待按下模式 */ } else /* 已经按下 */ { // printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, adcdat0 & 0xfff, adcdat1 & 0xfff); // enter_wait_pen_up_mode(); /* 优化措施3: 多次测量求平均值 */ x[cnt] = adcdat0 & 0xfff; y[cnt] = adcdat1 & 0xfff; ++cnt; if (cnt == 4) { cnt = 0; printk("x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4); enter_wait_pen_up_mode(); /* 进入等待弹起模式 */ } else { enter_measure_xy_mode(); start_adc(); } } #endif #if 0 printk("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt,(int) (s3c_ts_regs->adcdat0 & 0xfff), (int) (s3c_ts_regs->adcdat1 & 0xfff)); enter_wait_pen_up_mode(); #endif return IRQ_HANDLED; }
// 3th里面的自动分离模式启动后需要的中断函数注册,具体函数内容在4.2里面 static irqreturn_t adc_irq(int irq, void *dev_id) { static int cnt = 0; static int x[4], y[4]; // 优化措施3 测量保存4次,然后求平均值 int adcdat0, adcdat1; // 寄存器的bit[15]是判断松开还是按下的 手册447 // X,Y的值存在ADCDAT0 AND ADCDAT1寄存器里面 手册442 part3 // 最低10位为x坐标值,不过这个值是电压值而已,和坐标值没有关系 // &&&&&&&&&&&&*********** 如果ADC启动完成时,发现触摸笔已经松开,则测量值已经不准确,丢弃此次结果。 adcdat0 = s3c_ts_regs->adcdat0 ; adcdat1 = s3c_ts_regs->adcdat1 ; if (s3c_ts_regs->adcdat0 & (1<<15)) { // 如果触摸笔已经松开 cnt = 0; // 优化3 中要每4次求一次平均值 enter_wait_pen_down_mode(); } else { //printk ("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, s3c_ts_regs->adcdat0 & 0x3ff, adcdat1 & 0x3ff); // *******运行到这里,如果没有等待松开操作,则开发板只进行一次测量后就没有反映了,所以在这里要加上如下语句。 // 优化措施3 多次测量求平均值 x[cnt] = s3c_ts_regs->adcdat0 & 0x3ff; y[cnt] = s3c_ts_regs->adcdat1 & 0x3ff; ++cnt; if (cnt == 4) { //printk ("adc_irq cnt = %d, x = %d, y = %d\n", ++cnt, (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4); // 上面这行错误代码,错误在 ++cnt. printk (" x = %d, y = %d\n", (x[0]+x[1]+x[2]+x[3])/4, (y[0]+y[1]+y[2]+y[3])/4); cnt = 0; enter_wait_pen_up_mode(); } else { enter_measure_xy_mode(); start_adc(); } enter_wait_pen_up_mode(); // 测量完毕要等待触摸笔松开 } return IRQ_HANDLED; }
static void s3c_ts_timer_function(unsigned long data) { if (s3c_ts_regs->adcdat0 & (1<<15)) { /* 已经松开 */ enter_wait_pen_down_mode(); } else { /* 测量X/Y坐标 */ enter_measure_xy_mode(); start_adc(); } }
static irqreturn_t pen_down_up_irq(int irq, void *dev_id) { if(s3c_ts_regs->adcdat0 & (1<<15)) { printk("pen up\n"); enter_wait_pen_down_mode(); } else { // printk("pen down\n"); // enter_wait_pen_up_mode(); enter_measure_xy_mode(); start_adc(); } return IRQ_HANDLED; }
static int s3c_ts_init(void) { struct clk *clk; /*1.分配一个input结构体*/ s3c_ts_dev = input_allocate_device(); /*2.设置*/ /*2.1.能产生哪类事件 */ set_bit(EV_KEY,s3c_ts_dev->evbit); set_bit(EV_ABS,s3c_ts_dev->evbit); /*2.2.能产生这类事件里的哪些事件 */ set_bit(BTN_TOUCH,s3c_ts_dev->keybit); input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0); input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0); /* 3. 注册 */ input_register_device(s3c_ts_dev); /* 4. 硬件相关的操作 */ /* 4.1 使能时钟(CLKCON[15]) */ clk = clk_get(NULL, "adc"); clk_enable(clk); /*4.2 设置S3C2440的ADC/TS寄存器 */ s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs)); /* bit[14] : 1-A/D converter prescaler enable * bit[13:6]: A/D converter prescaler value, * 49, ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz * bit[0]: A/D conversion starts by enable. 先设为0 */ s3c_ts_regs->adccon = (1<<14) | (49<<6); request_irq(IRQ_TC, pen_down_up_irq , IRQF_SAMPLE_RANDOM,"ts_pen", NULL); request_irq(IRQ_ADC, adc_irq , IRQF_SAMPLE_RANDOM,"ts_pen", NULL); /* 优化措施1: *设置ADCDELAY,使得ADC稳定后发出IRQ_TC中断 * */ s3c_ts_regs->adcdly = 0xffff; enter_wait_pen_down_mode(); return 0; }
static void tiny_ts_timer_function(unsigned long data) { if (tiny_ts_regs->tsdatx1 & (1<<15)) { /* 已经松开 */ input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); input_report_key(s3c_ts_dev, BTN_TOUCH, 0); input_sync(s3c_ts_dev); enter_wait_pen_down_mode(); } else { /* 测量X/Y坐标 */ enter_measure_xy_mode(); start_adc(); } }
static irqreturn_t pen_down_up_irq(int irq, void *dev_id) { if (tiny_ts_regs->tsdatx1 & (1<<15)) { //printk("pen up\n"); input_report_abs(s3c_ts_dev, ABS_PRESSURE, 0); input_report_key(s3c_ts_dev, BTN_TOUCH, 0); input_sync(s3c_ts_dev); enter_wait_pen_down_mode(); } else { //printk("pen down\n"); //enter_wait_pen_up_mode(); enter_measure_xy_mode(); start_adc(); } return IRQ_HANDLED; }
static irqreturn_t pen_down_up_irq(int irq, void *dev_id) { if (s3c_ts_regs->adcdat0 & (1<<15)) { printk("pen up\n"); //松开才能等待下一次等待模式 enter_wait_pen_down_mode(); } else { // 3th 开始,进行启动ADC,转换x,y坐标 //printk("pen down\n"); //按下进入等待松开模式 //enter_wait_pen_up_mode(); // 触摸屏有xy分别分离模式和自动分离模式,我们取后一种自动分离模式,这种简单。 enter_measure_xy_mode(); start_adc(); } return IRQ_HANDLED; }
static irqreturn_t pen_down_up_irq(int irq, void *dev_id) { enter_no_operation_mode(); if (s3c_ts_regs->adcdat0 & (1<<15)) { printk("pen up\n"); enter_wait_pen_down_mode(); } else { printk("pen down\n"); // enter_wait_pen_up_mode(); enter_measure_xy_mode(); start_adc(); } /* 2416数据手册P554,XY_PST=0 */ enter_no_operation_mode(); return IRQ_HANDLED; }
static int s3c_ts_init(void) { struct clk* clk; /* 1. 分配一个input_dev结构体 */ tiny_ts_dev = input_allocate_device(); /* 2. 设置 */ /* 2.1 能产生哪类事件 */ set_bit(EV_KEY, tiny_ts_dev->evbit); set_bit(EV_ABS, tiny_ts_dev->evbit); /* 2.2 能产生这类事件里的哪些事件 */ set_bit(BTN_TOUCH, tiny_ts_dev->keybit); input_set_abs_params(tiny_ts_dev, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(tiny_ts_dev, ABS_Y, 0, 0x3FF, 0, 0); input_set_abs_params(tiny_ts_dev, ABS_PRESSURE, 0, 1, 0, 0); /* 3. 注册 */ input_register_device(tiny_ts_dev); /* 4. 硬件相关的操作 */ /* 4.1 使能时钟(CLKCON[15]) */ clk = clk_get(NULL, "adc"); if (!clk || IS_ERR(clk)) { printk(KERN_INFO "failed to get adc clock source\n"); } clk_enable(clk); printk("Tiny_TS clock got enabled :: %ld.%03ld Mhz\n", PRINT_MHZ(clk_get_rate(tiny_clk))); /* 4.2 设置S3C2440的ADC/TS寄存器 */ tsadccon0 = ioremap(0xE1700000, 4); tiny_ts_regs = ioremap(0xE1701000, sizeof(struct tiny_ts_regs)); /* s5pv210有触摸屏接口0,1 * Tiny210开发板向外提供接口1 * 所以这里选择接口1 */ tsadccon0 |= 1<<17; /* bit[14] : 1-A/D converter prescaler enable * bit[13:6]: A/D converter prescaler value, * 65, ADCCLK=PCLKP/(65+1)=66.7MHz/(65+1)=1MHz * bit[2]: 默认为1,即Standby mode,我们要设置为0,正常模式 * bit[0]: A/D conversion starts by enable. 先设为0 */ tiny_ts_regs->tsadccon1 &= ~(1<<2); tiny_ts_regs->tsadccon1 |= (1<<14)|(65<<6); request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL); request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL); /* 优化措施1: * 设置ADCDLY为最大值, 这使得电压稳定后再发出IRQ_TC中断 */ tiny_ts_regs->tsdaty1 = 0xffff; /* 优化措施5: 使用定时器处理长按,滑动的情况 * */ init_timer(&ts_timer); ts_timer.function = tiny_ts_timer_function; add_timer(&ts_timer); enter_wait_pen_down_mode(); return 0; }
//第二步 开始写入口函数 static int s3c_ts_init(void) { struct clk* clk; //第五步 细化,把要做的东西写下来,以下框架为所有触摸屏程序的框架 // 1.分配一个input_dev结构体 s3c_ts_dev = input_allocate_device(); // 2.设置,分两大类 参考8th Driver buttons.c // 2.1 能产生哪类事件 set_bit(EV_KEY, s3c_ts_dev->evbit); //EV_KEY表示会产生按键类事件,buttons_dev->evbit表示设置数组总的某一位可以产生案件类事件。 set_bit(EV_ABS, s3c_ts_dev->evbit); //绝对位移 // 2.2 能产生这类操作中的哪些事件 set_bit(BTN_TOUCH, s3c_ts_dev->keybit); //能够产生按键类事件中的触摸屏事件 input_set_abs_params(s3c_ts_dev, ABS_X, 0, 0x3FF, 0, 0); //最大尺寸为0x3ff. input_set_abs_params(s3c_ts_dev, ABS_Y, 0, 0x3FF, 0, 0); input_set_abs_params(s3c_ts_dev, ABS_PRESSURE, 0, 1, 0, 0);// 笔压力仅设置为两种 0和1. // 3.注册 input_register_device (s3c_ts_dev); // 4. 硬件相关的操作 硬件手册16章 // 4.1 使能时钟(也就是设置CLKCON的bit[15]) clk = clk_get(NULL, "abc"); clk_enable(clk); // 4.2 设置s3c2440的ADC (TS寄存器) // 操作TS寄存器,需要进行ioremap. 这样一个个的进行ioremap多麻烦, // 写一个结构体就比较简单struct s3c_ts_regs. s3c_ts_regs = ioremap(0x58000000, sizeof(struct s3c_ts_regs)); //物理地址 // 以下参数设置参照手册 444页 // bit[14] 1-A/D converter prescaler enable 欲分频使能 // bit[13:6] 1-A/D converter prescaler value 欲分频系数 // 设为49 ADCCLK = PCLK/(49+1) = 50MHz/(49+1)= 1MHz.0 // bit[5:3] 模拟输入频道选择,暂时不设置 // bit[2] STDBM // bit[0] A/D conversion starts by enable 先设为0; s3c_ts_regs->adccon = (1<<14) | (49<<6); request_irq(IRQ_TC, pen_down_up_irq, IRQF_SAMPLE_RANDOM, "ts_pen", NULL); //先设置一个中断,看触摸屏是否有动作,参考笔记 // 3th增加的自动分离测量模式,需要注册启动后的中断 request_irq(IRQ_ADC, adc_irq, IRQF_SAMPLE_RANDOM, "adc", NULL); //&&&&&&&&&&%%%%%%% 优化措施1 // 手册446 触摸屏有一个ADCDLY寄存器,设置为最大值,这使得电压稳定后再发出中断 s3c_ts_regs->adcdly = 0xffff; enter_wait_pen_down_mode(); //增加该函数别忘了在前面声明,等待触摸笔按下模式 return 0; }