触摸屏驱动程序框架与上一片文章的输入子系统类似,只是底层驱动由按键变成了触摸屏。
S3C2440的ADC相关寄存器:
struct s3c_ts_regs { unsigned long adccon; unsigned long adctsc; unsigned long adcdly; unsigned long adcdat0; unsigned long adcdat1; unsigned long adcupdn; };
1.分配input_dev结构体
struct input_dev *s3c_ts_dev = input_allocate_device();
set_bit(EV_KEY, s3c_ts_dev->evbit);
set_bit(EV_ABS, s3c_ts_dev->evbit);
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);
inpute_register_device(s3c_ts_dev);
struct clk *clk = clk_get(NULL, "adc"); clk_enable(clk);
s3c_ts_regs = ioremap((0x58000000, sizeof(struct s3c_ts_regs)); /* converter prescaler enable , ADCCLK=PCLK/(49+1)=50MHz/(49+1)=1MHz */ s3c_ts_regs->adccon = (1<<14)|(49<<6); s3c_ts_regs->adcdly = 0xffff;//为了确保ADC转换的精度,将这个寄存器设置成最大值
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);
init_timer(&ts_timer); ts_timer.function = s3c_ts_timer_function; add_timer(&ts_timer);
enter_wait_pen_dowm_mode();
void enter_wait_pen_down_mode(void) { s3c_ts_regs->adctsc = 0xd3; } void enter_wait_pen_up_mode(void) { s3c_ts_regs->adctsc = 0x1d3; } void enter_measure_xy_mode(void) { s3c_ts_regs->adctsc = (1<<3) | (1<<2); } void start_adc(void) { s3c_ts_regs->adccon |= (1<<0); }
void s3c_ts_timer_function(void) { if (s3c_ts_regs->adcdat0 & (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 { /* 按下 */ enter_measure_xy_mode(); start_adc(); } }
irqreturn_t pen_down_up_irq(int irq, void *dev_id) { if (s3c_ts_regs->adcdat0 & (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 { /* 按下 */ enter_measure_xy_mode(); start_adc(); } return IRQ_HANDLED; } irqreturn_t adc_irq(int irq, void *dev_id) { static int cnt = 0; static int x[4], y[4]; int adcdat0, adcdat1; 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(s3c_ts_dev); enter_wait_pen_down_mode(); } else { x[cnt] = adcdat0 & 0x3FFF; y[cnt] = adcdat1 & 0x3FFF; ++cnt; if (cnt == 4) { if (s3c_filter_ts(x, y)) { input_report_abs(s3c_ts_dev, ABS_X, (x[1]+x[2]+x[3]+x[4])/4); input_report_abs(s3c_ts_dev, ABS_Y, (y[1]+y[2]+y[3]+y[4])/4); input_report_abs(s3c_ts_dev, ABS_PRESSURE, 1); input_report_key(s3c_ts_dev, BTN_TOUCH, 1); input_sync(s3c_ts_dev); } 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 int s3c_filter_ts(int x[], int y[]) { #define ERR_LIMIT 10 int avr_x, avr_y; int det_x, det_y; avr_x = (x[0] + x[1])/2; avr_y = (y[0] + y[1])/2; det_x = (x[2] > avr_x) ? (x[2] - avr_x) : (avr_x - x[2]); det_y = (y[2] > avr_y) ? (y[2] - avr_y) : (avr_y - y[2]); if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT)) return 0; avr_x = (x[1] + x[2])/2; avr_y = (y[1] + y[2])/2; det_x = (x[3] > avr_x) ? (x[3] - avr_x) : (avr_x - x[3]); det_y = (y[3] > avr_y) ? (y[3] - avr_y) : (avr_y - y[3]); if ((det_x > ERR_LIMIT) || (det_y > ERR_LIMIT)) return 0; return 1; }
原文:http://www.cnblogs.com/zpehome/p/3819051.html