Reference: http://blog.chinaunix.net/uid-22174347-id-1786941.html
========================================================== ============================
Development Environment
Compilation System: fedora9
Compiler: arm-linux-4.4.3
Master chip: S3C2440
Development Board: mini2440
========================================================== ============================
I. Working Principle of resistive touch screen
Ii. S3C2440 resistive touch screen interface and internal ADC Structure
3. inputsubsystem)
Iv. mini2440 touch screen Driver Analysis
========================================================== ============================
(This part is transferred from:Http://blog.chinaunix.net/uid-22174347-id-1786941.html article well written)
Iv. mini2440 touch screen Driver Analysis
1. hardware schematic analysis
The internal touch screen interface of the S3C2440 chip is integrated with the ADC interface. For the hardware structure schematic, see the diagram in the development of the ADC Driver instance on the S3C2440, where Channel 7 (XP or ain7) X coordinate input for the touch screen interface and Channel 5 (YP or ain5) as the Y coordinate input for the touch screen interface. In the "Development of ADC Driver instances on S3C2440", the analog signal of the AD conversion is generated by a potentiometer on the Development Board and input through channel 1 (ain0, the analog signal here is the X coordinate and Y coordinate analog signals generated by the touch screen, which are input through Channel 7 and Channel 5 respectively. The touch screen interface provided by S3C2440 has four processing modes: Normal conversion mode, separate x/y position conversion mode, automatic x/y position conversion mode, and waiting for interruption mode, for detailed requirements for working in each mode, see the description of the data manual. The driver instance adopts the automatic x/y position conversion mode and the waiting for interruption mode.
Note: In each step, in order to make the code logic more organized and easy to understand, the order of the Code is not considered. For example, a function must be defined before calling. To compile this code, adjust the code order strictly in accordance with the C language specifications.
2. Create the touch screen driver my2440_ts.c. First, load and unload the driver. In the driver load part, we mainly do the following: enable the clock, ing IO port, initialization register, applying for interruption, initializing the input device, and registering the input device to the input subsystem required by the ADC. The Code is as follows:
# Include <Linux/module. h> # include <Linux/kernel. h> # include <Linux/CLK. h> # include <Linux/init. h> # include <Linux/input. h> # include <Linux/Serio. h> # include <plat/regs-adc.h> # include <ASM/IRQ. h> # include <ASM/Io. h>/* used to save the ADC clock obtained from the platform clock list */static struct CLK * adc_clk; /* defines a memory address used to save the virtual ing */static void _ iomem * adc_base; /* define an input device to represent our touch screen device */static struct input_dev * ts_dev;/* device name */# define device_name "My 2440_touchscreen "/* defines a wait4int macro that operates the ADC touch screen control register s3c2410_adctsc_ym_sen these macros are defined in the regs-adc.h */# define wait4int (x) <8) | s3c2410_adctsc_ym_sen | s3c2410_adctsc_yp_sen | \ s3c2410_adctsc_xp_sen | s3c2410_adctsc_xy_pst (3) Static int _ init ts_init (void) {int ret; /* obtain the ADC clock from the platform clock queue. Why is this clock obtained here, because the ADC conversion frequency is related to the clock. Some clock of the system is defined in arch/ARM/plat-s3c24xx/s3c2410-clock.c */adc_clk = clk_get (null, "ADC"); If (! Adc_clk) {/* error handling */printk (kern_err "falied to find ADC clock source \ n"); Return-enoent ;} /* Clock to be able to use after obtaining, clk_enable defined in arch/ARM/plat-s3c/clock. C */clk_enable (adc_clk);/* map the IO space occupied by the adc io port to the virtual address of the memory. ioremap is defined in Io. h. Note: Io space can be used after ing, the operation of the virtual address is the operation of the IO space, s3c2410_pa_adc is the base address of the ADC controller, defined in mach-s3c2410/include/Mach/map. in H, 0x20 is the virtual address length */adc_base = ioremap (s3c2410_pa_adc, 0x20); If (adc_base = NULL) {/* error handling */printk (kern_err "failed to remap register block \ n"); ret =-einval; goto err_noclk ;} /* initialize the ADC control register and the ADC touch screen control register */adc_initialize ();/* request the ADC interruption, which is triggered after the adswitch is complete. Here, the shared interrupt irqf_shared is used because the interrupt number is also used in the ADC Driver. The last parameter 1 is a random value, because if the value is not set to null, application fails if the request is interrupted */ret = request_irq (irq_adc, adc_irq, ir1__shared | ir1__sample_random, device_name, 1); If (RET) {printk (kern_err "IRQ % d error % d \ n", irq_adc, RET); ret =-einval; goto err_nomap;}/* apply for touch screen interruption, trigger */ret = request_irq (irq_tc, tc_irq, ir1__sample_random, device_name, 1) when the touch screen is pressed or pulled; If (RET) {printk (kern_err "IRQ % d error % d \ N ", irq_tc, RET); ret =-einval; goto err_noirq;}/* apply for a space for the input device. input_allocate_device is defined in input. in H, */ts_dev = input_allocate_device ();/* initialize the input device, that is, set the value for the member of the input device struct input_dev. The evbit field is used to describe supported events. Synchronization events, key events, and absolute coordinate events are supported here. The bit macro actually performs a bit operation on 1, which is defined in Linux/bitops. in H, */ts_dev-> evbit [0] = bit (ev_syn) | bit (ev_key) | bit (ev_abs);/* The keybit field is used to describe the type of the key in input. h defines a lot. btn_touch is used here to represent the touch screen click */ts_dev-> keybit [bits_to_longs (btn_touch)] = bit (btn_touch);/* For the touch screen, the absolute coordinate system is used. Set the minimum and maximum values of the X and Y coordinates in the coordinate system (0-1023 range) abs_x and abs_y to represent the X and Y coordinates, abs_pressure indicates whether the touch screen is pressed or raised */input_set_abs_params (ts_dev, abs_x, 0, 0x3ff, 0, 0); input_set_abs_params (ts_dev, abs_y, 0, 0x3ff, 0, 0); input_set_abs_params (ts_dev, abs_pressure, 0, 1, 0, 0);/* set the identity information of the touch screen input device. This information can be viewed in */ts_dev-> name = device_name;/* device name */ts_dev-> ID in/proc/bus/input/devices after the driver is mounted. bustype = bus_rs232;/* bus type */ts_dev-> ID. vendor = 0 xdead;/* dealer ID */ts_dev-> ID. product = 0 xbeef;/* product ID */ts_dev-> ID. version = 0x0101;/* version ID * // * ready, and some are ready. register the ts_dev touch screen device to the input subsystem */input_register_device (ts_dev ); return 0;/* handle error redirection */err_noclk: clk_disable (adc_clk); clk_put (adc_clk); err_nomap: iounmap (adc_base); lost: free_irq (irq_adc, 1 ); return ret;}/* initialize the ADC control register and ADC touch screen control register */static void adc_initialize (void) {/* calculate the result as (Binary): 111111111000000, according to the data manual, we learned that the value of the ad-converted pre-timer is set to 255. The value of the ad-converted pre-timer is valid */writel (optional | s3c2410_adccon_prscvl (0xff), adc_base + s3c2410_adccon ); /* set the ADC start delay register. The delay value is 0xffff */writel (0 xFFFF, adc_base + s3c2410_adcdly)./* wait4int macro calculation result is (Binary): 11010011, according to the data manual, the ADC touch screen control register is set to the pending interrupt mode */writel (wait4int (0), adc_base + s3c2410_adctsc );} static void _ exit ts_exit (void) {/* block and release interruptions */disable_irq (irq_adc); disable_irq (irq_tc); free_irq (irq_adc, 1); free_irq (irq_tc, 1);/* release the virtual address ing space */iounmap (adc_base);/* block and destroy the clock */If (adc_clk) {clk_disable (adc_clk); clk_put (adc_clk ); adc_clk = NULL;}/* cancel the touch screen device from the input subsystem */input_unregister_device (ts_dev);} module_init (ts_init); module_exit (ts_exit); module_license ("GPL "); module_author ("S3C2440 TP"); module_description ("my2440 touch screen driver ");
2. The next step is to convert the touch screen status and coordinates in two interrupt service programs. First read the Code as follows:
/* Define an external semaphore adc_lock, because adc_lock has been stated in the ADC Driver, this ensures that the ADC resources are mutually exclusive in the ADC Driver and touch screen driver */extern struct semaphore adc_lock;/* as a label, convert X and Y coordinates only after touch screen operations */static int ownadc = 0; /* used to record the converted X and Y coordinate values */static long XP; static long YP; /* used to count the number of times the input is converted when the touch screen is pressed or lifted */static int count;/* defines an autopst macro, set the ADC touch screen control register to automatic conversion mode */# define autopst (s3c2410_adctsc_ym_sen | s3c2410_adctsc_yp_sen | s3c2410_adctsc_xp_sen | \ s3c2410_adctsc_a Uto_pst | s3c2410_adctsc_xy_pst (0)/* the touch screen interrupts the service program and triggers the execution of */static irqreturn_t tc_irq (int irq, void * dev_id) when the touch screen is pressed or pulled) {/* is used to record the value after this ad conversion */unsigned long data0; unsigned long data1;/* is used to record whether the touch screen operation status is pressed or lifted */INT updown; /* ADC resources can be obtained, that is, locks */If (down_trylock (& adc_lock) = 0) {/* The identifier performs operations on the touch screen */ownadc = 1; /* read the value after this adswitch. Note that the primary read is the status */data0 = readl (adc_base + s3c2410_adcdat0); data1 = readl (adc_base + s3c2410_adcd 1);/* record whether the touch screen is pressed or lifted this time, and the status is stored in the 15th-bit data register. Therefore, it is consistent with s3c2410_adcdat0_updown */updown = (! (Data0 & s3c2410_adcdat0_updown ))&&(! (Data1 & s3c2410_adcdat0_updown);/* determine the operation status of the touch screen */If (updown) {/* if it is pressed, call the touch_timer_fire function to start the ADC conversion, this function definition will be followed by */touch_timer_fire (0);} else {/*. If it is in the lift state, this operation is completed, therefore, the possession of ADC resources is released */ownadc = 0; up (& adc_lock) ;}} return irq_handled;} static void touch_timer_fire (unsigned long data) {/* is used to record the value after this ad conversion */unsigned long data0; unsigned long data1;/* is used to record whether the touch screen operation status is pressed or lifted */INT updown; /* read the value after this adconversion. Note that Read status */data0 = readl (adc_base + s3c2410_adcdat0); data1 = readl (adc_base + s3c2410_adcdat1);/* record whether the touch screen is pressed down or lifted, this status is stored in the 15th bits of the data register, so it is consistent with that of the last s3c2410_adcdat0_updown */updown = (! (Data0 & s3c2410_adcdat0_updown ))&&(! (Data1 & s3c2410_adcdat0_updown);/* determine the operation status of the touch screen */If (updown) {/* If the status is pressed, when the ADC has been converted, report events and Data */If (count! = 0) {long TMP; TMP = XP; XP = YP; Yp = TMP; XP >>= 2; YP >>=2; # ifdef config_touchscreen_my2440_debug/* Touch Screen debugging information, after this option is selected during kernel compilation, click the touch screen to print the coordinate information on the terminal */struct timeval TV; do_gettimeofday (& TV); printk (kern_debug "T: % 06d, X: % 03ld, Y: % 03ld \ n ", (INT) TV. TV _usec, XP, YP); # endif/* Report the absolute coordinate values of x and y */input_report_abs (ts_dev, abs_x, XP); input_report_abs (ts_dev, abs_y, YP ); /* report the status of the touch screen. 1 indicates that the touch screen is pressed */input_report_abs (ts_dev, abs_pressure, 1);/* Report the button event, the key value is 1, which indicates that the button corresponding to the touch screen is pressed. */input_report_key (ts_dev, btn_touch, 1);/* Wait for the receiver to receive the data and then reply to the confirmation, used for synchronization */input_sync (ts_dev);}/* If the status is pressed and the ADC has not started conversion, start the ADC for conversion */XP = 0; Yp = 0; count = 0;/* set the touch screen mode to automatic conversion mode */writel (s3c2410_adctsc_pull_up_disable | autopst, adc_base + s3c2410_adctsc ); /* Start ADC conversion */writel (readl (adc_base + s3c2410_adccon) | s3c2410_adccon_enable_start, adc_base + s3c2410_adccon);} else {/* Otherwise, the status is lifted */COUNT = 0; /* Report the button event. The key value is 0 (indicating that the button corresponding to the touch screen is released) */input_report_key (ts_dev, btn_touch, 0);/* report the status of the touch screen, 0 indicates that the touch screen is not pressed */input_report_abs (ts_dev, abs_pressure, 0);/* Wait for the receiver to receive data and send a response for confirmation. It is used to synchronize */input_sync (ts_dev ); /* reset the touch screen to the waiting for interruption status */writel (wait4int (0), adc_base + s3c2410_adctsc);/* If the touch screen is lifted, this operation ends, therefore, the possession of ADC resources is released. */If (ownadc) {ownadc = 0; up (& adc_lock) ;}}/* defines and initializes a timer touch_timer, the timer service program is touch_timer_fire */static struct timer_list touch_timer = timer_initializer (touch_timer_fire, 0, 0);/* The ADC interrupts the service program, run the */static irqreturn_t adc_irq (int irq, void * dev_id) {/* to record the value after this adconversion */unsigned long data0; unsigned long data1; if (ownadc) {/* reads the value after the AD conversion. Note that the main read is the coordinate */data0 = readl (adc_base + s3c2410_adcdat0 ); data1 = readl (adc_base + s3c2410_adcdat1);/* records the X and Y coordinate values after the AD conversion. According to the data manual, the X and Y coordinates are stored in the 0-9 bits of the Data Registers 0 and 1 respectively. Therefore, here we use the 0-9 bits of the X and Y coordinates as the value of the X/XP + = data0 & s3c2410_adcdat0_xpdata_mask; YP + = data1 & s3c2410_adcdat1_ypdata_mask;/* count the number of ad vers */count ++; If (count <(1 <2 )) {/* if the number of conversions is less than 4, restart the ADC conversion */writel (convert | autopst, adc_base + s3c2410_adctsc); writel (readl (adc_base + s3c2410_adccon) | s3c2410_adccon_enable_start, adc_base + s3c2410_adccon);} else {/* Otherwise, start a time-tick timer, which will execute the timer service program to report events and Data */mod_timer (& touch_timer, jiffies + 1); writel (wait4int (1), adc_base + s3c2410_adctsc) ;}} return irq_handled ;}
3. The process of conversion is described as follows:
(1) If the touch screen is touched, the touch screen interruption is triggered to enter tc_irq. After obtaining adc_lock and judging that the touch screen status is pressed, touch_timer_fire is called to start the ADC conversion;
(2) When the ADC conversion starts, the ADC interruption is triggered to enter adc_irq. If the number of conversions is less than 4, restart the ADC for conversion. If the conversion is completed four times, start a time tick timer to stop the ADC conversion. That is to say, the ADC conversion stops during this time tick;
(3) Why do we need to stop the ADC conversion before one tick answer arrives? This is to prevent screen jitter.
(4) If one tick arrives, the system enters the timer service program touch_timer_fire. If the touch screen is still pressed, the system reports the event and converted data, restarts the ADC conversion, and repeats step (2) step;
(5) If the touch is lifted, the release event is reported and the touch screen is reset to the waiting for interruption status.
4. shows the overall process.