The Touch Screen driver framework is similar to the input subsystem in the previous article, but the underlying driver is changed from buttons to touch screens.
ADC registers of S3C2440:
struct s3c_ts_regs { unsigned long adccon; unsigned long adctsc; unsigned long adcdly; unsigned long adcdat0; unsigned long adcdat1; unsigned long adcupdn;};
1. Allocate the input_dev struct
struct input_dev *s3c_ts_dev = input_allocate_device();
2. Set 2.1 to set the Event Type
set_bit(EV_KEY, s3c_ts_dev->evbit);set_bit(EV_ABS, s3c_ts_dev->evbit);
2.2 events that can generate such events
set_bit(BTN_TOUCH, s3c_ts_dev->keybit);
// Supports absolute value X coordinates, and sets the maximum and minimum values in the coordinate system, as well as interference values and welding positions.
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. Registration
inpute_register_device(s3c_ts_dev);
4. Hardware-related operations 4.1 enable ADC clock
struct clk *clk = clk_get(NULL, "adc");clk_enable(clk);
4.2 set the relevant registers of the ADC
Initi_ts_regs = ioremap (0x58000000, sizeof (struct initi_ts_regs);/* converter prescaler enable, adcclk = pclk/(49 + 1) = 50 MHz/(49 + 1) = 1 MHz */initi_ts_regs-> adccon = (1 <14) | (49 <6); initi_ts_regs-> adcdly = 0 xFFFF; // set this register to the maximum value to ensure the accuracy of the ADC conversion.
4.3 request interruption, ADC conversion completed interruption and touch screen press or lift interruption
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);
4.4 initialize the timer to handle sliding on the touch screen
init_timer(&ts_timer);ts_timer.function = s3c_ts_timer_function;add_timer(&ts_timer);
4.5 let the touch screen wait for the pen tip to press
enter_wait_pen_dowm_mode();
5. Touch Screen mode settings
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);}
6. The timer processing function reports events.
Void Merge (void) {If (initi_ts_regs-> adcdat0 & (1 <15) {/* release */input_report_abs (initi_ts_dev, abs_pressure, 0); input_report_key (initi_ts_dev, btn_touch, 0); input_sync (initi_ts_dev); enter_wait_pen_down_mode () ;}else {/* press */enter_measure_xy_mode (); start_adc ();}}
7. interrupt handling functions
Irqreturn_t release (int irq, void * dev_id) {If (initi_ts_regs-> adcdat0 & (1 <15) {/* release */input_report_abs (initi_ts_dev, abs_pressure, 0 ); input_report_key (cloud_ts_dev, btn_touch, 0); input_sync (cloud_ts_dev); reset () ;}else {/* press */RESET (); 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 = cloud_ts_regs-> adcdat0; adcdat1 = cloud_ts_regs-> adcdat1; If (cloud_ts_regs-> adcdat0 & (1 <15) {/* release */CNT = 0; values (maid, abs_pressure, 0); values (maid, btn_touch, 0); input_sync (FIG); values () ;}else {x [CNT] = adcdat0 & 0x3fff; Y [CNT] = adcdat1 & 0x3fff; ++ CNT; If (CNT = 4) {If (initi_filter_ts (x, y) {input_report_abs (initi_ts_dev, abs_x, (X [1] + X [2] + X [3] + X [4])/4); input_report_abs (initi_ts_dev, abs_y, (Y [1] + Y [2] + Y [3] + Y [4])/4); input_report_abs (initi_ts_dev, abs_pressure, 1); input_report_key (initi_ts_dev, btn_touch, 1); input_sync (initi_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 ;}
8. filter the data converted by the ADC.
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;}