📄 ep93xx_ts.c
字号:
}/* * ep93xx_hw_shutdown * */static voidep93xx_hw_shutdown(void){ unsigned int uiKTDIV; DPRINTK("ep93xx_hw_shutdown\n"); sTouch.state = TS_STATE_STOPPED; Stop_Timer2(); /* * Disable the scanning engine. */ outl( 0, TSSetup ); outl( 0, TSSetup2 ); /* * Clear the TSEN bit in KTDIV so that we are disabling the clock * for the touchscreen. */ uiKTDIV = inl(SYSCON_KTDIV); uiKTDIV &= ~SYSCON_KTDIV_TSEN; SysconSetLocked( SYSCON_KTDIV, uiKTDIV ); } /* ep93xx_hw_shutdown */static void ep93xx_timer2_isr(int irq, void *dev_id, struct pt_regs *regs){ DPRINTK("%d", (int)sTouch.state ); switch( sTouch.state ) { case TS_STATE_STOPPED: TS_Hardware_Scan_Mode(); break; // // Get the Z1 value for pressure measurement and set up // the switch register for getting the Z2 measurement. // case TS_STATE_Z1: Set_Timer2_uSec( EP93XX_TS_ADC_DELAY_USEC ); sTouch.uiZ1 = ADCGetData( 2, 200 ); ep93xx_ts_set_direct( sSwitchSettings.uiSwitchZ2 ); sTouch.state = TS_STATE_Z2; break; // // Get the Z2 value for pressure measurement and set up // the switch register for getting the Y measurement. // case TS_STATE_Z2: sTouch.uiZ2 = ADCGetData( 2, 200 ); ep93xx_ts_set_direct( sSwitchSettings.uiYSample ); sTouch.state = TS_STATE_Y; break; // // Get the Y value and set up the switch register for // getting the X measurement. // case TS_STATE_Y: sTouch.uiY = ADCGetData( 4, 20 ); ep93xx_ts_set_direct( sSwitchSettings.uiXSample ); sTouch.state = TS_STATE_X; break; // // Read the X value. This is the last of the 4 adc values // we need so we continue on to process the data. // case TS_STATE_X: Stop_Timer2(); sTouch.uiX = ADCGetData( 4, 20 ); outl( 0xaa, TSSWLock ); outl( sSwitchSettings.uiDischarge, TSDirect ); sTouch.state = TS_STATE_DONE; /* * Process this set of ADC readings. */ ProcessPointData(); break; // // Shouldn't get here. But if we do, we can recover... // case TS_STATE_DONE: TS_Hardware_Scan_Mode(); break; } // // Clear the timer2 interrupt. // outl( 1, TIMER2CLEAR );}/*--------------------------------------------------------------------- * ProcessPointData * * This routine processes the ADC data into usable point data and then * puts the driver into hw or sw scanning mode before returning. * * We calculate inverse pressure (lower number = more pressure) then * do a hystheresis with the two pressure values 'light' and 'heavy'. * * If we are above the light, we have pen up. * If we are below the heavy we have pen down. * As long as the pressure stays below the light, pen stays down. * When we get above the light again, pen goes back up. * */static void ProcessPointData(void){ int bValidPoint = 0; unsigned int uiXDiff, uiYDiff, uiInvPressureDiff; unsigned int uiInvPressure; // // Calculate the current pressure. // uiInvPressure = CalculateInvPressure(); DPRINTK(" X=0x%x, Y=0x%x, Z1=0x%x, Z2=0x%x, InvPressure=0x%x", sTouch.uiX, sTouch.uiY, sTouch.uiZ1, sTouch.uiZ2, uiInvPressure ); // // If pen pressure is so light that it is greater than the 'max' setting // then we consider this to be a pen up. // if( uiInvPressure >= TS_LIGHT_INV_PRESSURE ) { DPRINTK(" -- up \n"); bCurrentPenDown = 0; ee93xx_ts_evt_add( 0, guiLastX, guiLastY ); TS_Hardware_Scan_Mode(); return; } // // Hystheresis: // If the pen pressure is hard enough to be less than the 'min' OR // the pen is already down and is still less than the 'max'... // if( (uiInvPressure < TS_HEAVY_INV_PRESSURE) || ( bCurrentPenDown && (uiInvPressure < TS_LIGHT_INV_PRESSURE) ) ) { if( bCurrentPenDown ) { // // If pen was previously down, check the difference between // the last sample and this one... if the difference between // samples is too great, ignore the sample. // uiXDiff = abs(guiLastX - sTouch.uiX); uiYDiff = abs(guiLastY - sTouch.uiY); uiInvPressureDiff = abs(guiLastInvPressure - uiInvPressure); if( (uiXDiff < TS_MAX_VALID_XY_CHANGE) && (uiYDiff < TS_MAX_VALID_XY_CHANGE) && (uiInvPressureDiff < TS_MAX_VALID_PRESSURE_CHANGE) ) { DPRINTK(" -- valid(two) \n"); bValidPoint = 1; } else { DPRINTK(" -- INvalid(two) \n"); } } else { DPRINTK(" -- valid \n"); bValidPoint = 1; } /* * If either the pen was put down or dragged make a note of it. */ if( bValidPoint ) { guiLastX = sTouch.uiX; guiLastY = sTouch.uiY; guiLastInvPressure = uiInvPressure; bCurrentPenDown = 1; ee93xx_ts_evt_add( 1, sTouch.uiX, sTouch.uiY ); } TS_Soft_Scan_Mode(); return; } DPRINTK(" -- fallout \n"); TS_Hardware_Scan_Mode();}static void ep93xx_ts_set_direct( unsigned int uiADCSwitch ){ unsigned int uiResult; // // Set the switch settings in the direct register. // outl( 0xaa, TSSWLock ); outl( uiADCSwitch, TSDirect ); // // Read and throw away the first sample. // do { uiResult = inl(TSXYResult); } while( !(uiResult & TSXYRESULT_SDR) ); }static unsigned int ADCGetData( unsigned int uiSamples, unsigned int uiMaxDiff ){ unsigned int uiResult, uiValue, uiCount, uiLowest, uiHighest, uiSum, uiAve; do { // //Initialize our values. // uiLowest = 0xfffffff; uiHighest = 0; uiSum = 0; for( uiCount = 0 ; uiCount < uiSamples ; uiCount++ ) { // // Read the touch screen four more times and average. // do { uiResult = inl(TSXYResult); } while( !(uiResult & TSXYRESULT_SDR) ); uiValue = (uiResult & TSXYRESULT_AD_MASK) >> TSXYRESULT_AD_SHIFT; uiValue = ((uiValue >> 4) + ((1 + TSXYRESULT_X_MASK)>>1)) & TSXYRESULT_X_MASK; // // Add up the values. // uiSum += uiValue; // // Get the lowest and highest values. // if( uiValue < uiLowest ) { uiLowest = uiValue; } if( uiValue > uiHighest ) { uiHighest = uiValue; } } } while( (uiHighest - uiLowest) > uiMaxDiff ); // // Calculate the Average value. // uiAve = uiSum / uiSamples; return uiAve; }//****************************************************************************// CalculateInvPressure//****************************************************************************// Is the Touch Valid. Touch is not valid if the X or Y value is not // in range and the pressure is not enough.// // Touch resistance can be measured by the following formula://// Rx * X * Z2// Rtouch = --------- * (-- - 1)// 4096 Z1//// This is simplified in the ration of Rtouch to Rx. The lower the value, the// higher the pressure.//// Z2// InvPressure = X * (-- - 1)// Z1//static unsigned int CalculateInvPressure(void){ unsigned int uiInvPressure; // // Check to see if the point is valid. // if( sTouch.uiZ1 < MIN_Z1_VALUE ) { uiInvPressure = 0x10000; } // // Can omit the pressure calculation if you need to get rid of the division. // else { uiInvPressure = ((sTouch.uiX * sTouch.uiZ2) / sTouch.uiZ1) - sTouch.uiX; } return uiInvPressure;}//****************************************************************************// TS_Hardware_Scan_Mode//****************************************************************************// Enables the ep93xx ts scanning engine so that when the pen goes down// we will get an interrupt.// //static void TS_Hardware_Scan_Mode(void){ unsigned int uiDevCfg; DPRINTK("S\n"); // // Disable the soft scanning engine. // sTouch.state = TS_STATE_STOPPED; Stop_Timer2(); // // Clear the TIN (Touchscreen INactive) bit so we can go to // automatic scanning mode. // uiDevCfg = inl( SYSCON_DEVCFG ); SysconSetLocked( SYSCON_DEVCFG, (uiDevCfg & ~SYSCON_DEVCFG_TIN) ); // // Enable the touch screen scanning state machine by setting // the ENABLE bit. // outl( (TSSETUP_DEFAULT | TSSETUP_ENABLE), TSSetup ); // // Set the flag to show that we are in interrupt mode. // gScanningMode = TS_MODE_HARDWARE_SCAN; // // Initialize TSSetup2 register. // outl( TSSETUP2_DEFAULT, TSSetup2 );}//****************************************************************************// TS_Soft_Scan_Mode//****************************************************************************// Sets the touch screen to manual polling mode.// //static void TS_Soft_Scan_Mode(void){ unsigned int uiDevCfg; DPRINTK("M\n"); if( gScanningMode != TS_MODE_SOFT_SCAN ) { // // Disable the touch screen scanning state machine by clearing // the ENABLE bit. // outl( TSSETUP_DEFAULT, TSSetup ); // // Set the TIN bit so we can do manual touchscreen polling. // uiDevCfg = inl( SYSCON_DEVCFG ); SysconSetLocked( SYSCON_DEVCFG, (uiDevCfg | SYSCON_DEVCFG_TIN) ); } // // Set the switch register up for the first ADC reading // ep93xx_ts_set_direct( sSwitchSettings.uiSwitchZ1 ); // // Initialize our software state machine to know which ADC // reading to take // sTouch.state = TS_STATE_Z1; // // Set the timer so after a mSec or two settling delay it will // take the first ADC reading. // Set_Timer2_uSec( EP93XX_TS_PER_POINT_DELAY_USEC ); // // Note that we are in sw scanning mode not hw scanning mode. // gScanningMode = TS_MODE_SOFT_SCAN;}static void Set_Timer2_uSec( unsigned int uiDelay_uSec ){ unsigned int uiClockTicks; /* * Stop timer 2 */ outl( 0, TIMER2CONTROL ); uiClockTicks = ((uiDelay_uSec * 508) + 999) / 1000; outl( uiClockTicks, TIMER2LOAD ); outl( uiClockTicks, TIMER2VALUE ); /* * Set up Timer 2 for 508 kHz clock and periodic mode. */ outl( 0xC8, TIMER2CONTROL );}static void Stop_Timer2(void){ outl( 0, TIMER2CONTROL );}/* * Initialization and exit routines */int __initep93xx_ts_init(void){ int retval; DPRINTK("ep93xx_ts_init\n"); retval = request_irq( IRQ_TOUCH, ep93xx_ts_isr, SA_INTERRUPT, "ep93xx_ts", 0); if( retval ) { printk(KERN_WARNING "ep93xx_ts: failed to get touchscreen IRQ\n"); return retval; } retval = request_irq( IRQ_TIMER2, ep93xx_timer2_isr, SA_INTERRUPT, "ep93xx_timer2", 0); if( retval ) { printk(KERN_WARNING "ep93xx_ts: failed to get timer2 IRQ\n"); return retval; } misc_register(&ep93xx_ts_miscdev); sTouch.state = TS_STATE_STOPPED; gScanningMode = TS_MODE_UN_INITIALIZED; printk(KERN_NOTICE "EP93xx touchscreen driver configured for 4-wire operation\n"); return 0;}void __exitep93xx_ts_exit(void){ DPRINTK("ep93xx_ts_exit\n"); Stop_Timer2(); free_irq(IRQ_TOUCH, 0); free_irq(IRQ_TIMER2, 0); misc_deregister(&ep93xx_ts_miscdev);}module_init(ep93xx_ts_init);module_exit(ep93xx_ts_exit);MODULE_DESCRIPTION("Cirrus EP93xx touchscreen driver");MODULE_SUPPORTED_DEVICE("touchscreen/ep93xx");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -