2006-11-17 01:07:26 -05:00
/*
* Philips UCB1400 touchscreen driver
*
* Author : Nicolas Pitre
* Created : September 25 , 2006
* Copyright : MontaVista Software , Inc .
*
2008-08-03 21:34:08 +01:00
* Spliting done by : Marek Vasut < marek . vasut @ gmail . com >
* If something doesnt work and it worked before spliting , e - mail me ,
* dont bother Nicolas please ; - )
*
2006-11-17 01:07:26 -05:00
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This code is heavily based on ucb1x00 - * . c copyrighted by Russell King
* covering the UCB1100 , UCB1200 and UCB1300 . . Support for the UCB1400 has
* been made separate from ucb1x00 - core / ucb1x00 - ts on Russell ' s request .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/completion.h>
# include <linux/delay.h>
# include <linux/input.h>
# include <linux/device.h>
# include <linux/interrupt.h>
# include <linux/suspend.h>
# include <linux/slab.h>
# include <linux/kthread.h>
2006-12-08 01:37:03 -05:00
# include <linux/freezer.h>
2008-08-03 21:34:08 +01:00
# include <linux/ucb1400.h>
2006-11-17 01:07:26 -05:00
static int adcsync ;
2007-04-12 01:35:43 -04:00
static int ts_delay = 55 ; /* us */
static int ts_delay_pressure ; /* us */
2006-11-17 01:07:26 -05:00
/* Switch to interrupt mode. */
2008-08-03 21:34:08 +01:00
static inline void ucb1400_ts_mode_int ( struct snd_ac97 * ac97 )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
UCB_TS_CR_MODE_INT ) ;
}
/*
* Switch to pressure mode , and read pressure . We don ' t need to wait
* here , since both plates are being driven .
*/
2008-08-03 21:34:08 +01:00
static inline unsigned int ucb1400_ts_read_pressure ( struct ucb1400_ts * ucb )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA ) ;
2007-04-12 01:35:43 -04:00
udelay ( ts_delay_pressure ) ;
2008-08-03 21:34:08 +01:00
return ucb1400_adc_read ( ucb - > ac97 , UCB_ADC_INP_TSPY , adcsync ) ;
2006-11-17 01:07:26 -05:00
}
/*
* Switch to X position mode and measure Y plate . We switch the plate
* configuration in pressure mode , then switch to position mode . This
* gives a faster response time . Even so , we need to wait about 55u s
* for things to stabilise .
*/
2008-08-03 21:34:08 +01:00
static inline unsigned int ucb1400_ts_read_xpos ( struct ucb1400_ts * ucb )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA ) ;
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA ) ;
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA ) ;
2007-04-12 01:35:43 -04:00
udelay ( ts_delay ) ;
2006-11-17 01:07:26 -05:00
2008-08-03 21:34:08 +01:00
return ucb1400_adc_read ( ucb - > ac97 , UCB_ADC_INP_TSPY , adcsync ) ;
2006-11-17 01:07:26 -05:00
}
/*
* Switch to Y position mode and measure X plate . We switch the plate
* configuration in pressure mode , then switch to position mode . This
* gives a faster response time . Even so , we need to wait about 55u s
* for things to stabilise .
*/
2008-08-03 21:34:08 +01:00
static inline unsigned int ucb1400_ts_read_ypos ( struct ucb1400_ts * ucb )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA ) ;
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA ) ;
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA ) ;
2007-04-12 01:35:43 -04:00
udelay ( ts_delay ) ;
2006-11-17 01:07:26 -05:00
2008-08-03 21:34:08 +01:00
return ucb1400_adc_read ( ucb - > ac97 , UCB_ADC_INP_TSPX , adcsync ) ;
2006-11-17 01:07:26 -05:00
}
/*
* Switch to X plate resistance mode . Set MX to ground , PX to
* supply . Measure current .
*/
2008-08-03 21:34:08 +01:00
static inline unsigned int ucb1400_ts_read_xres ( struct ucb1400_ts * ucb )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA ) ;
2008-08-03 21:34:08 +01:00
return ucb1400_adc_read ( ucb - > ac97 , 0 , adcsync ) ;
2006-11-17 01:07:26 -05:00
}
/*
* Switch to Y plate resistance mode . Set MY to ground , PY to
* supply . Measure current .
*/
2008-08-03 21:34:08 +01:00
static inline unsigned int ucb1400_ts_read_yres ( struct ucb1400_ts * ucb )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR ,
2006-11-17 01:07:26 -05:00
UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA ) ;
2008-08-03 21:34:08 +01:00
return ucb1400_adc_read ( ucb - > ac97 , 0 , adcsync ) ;
2006-11-17 01:07:26 -05:00
}
2009-07-12 20:51:25 -07:00
static inline int ucb1400_ts_pen_up ( struct snd_ac97 * ac97 )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
unsigned short val = ucb1400_reg_read ( ac97 , UCB_TS_CR ) ;
2009-07-12 20:51:25 -07:00
2008-08-03 21:34:08 +01:00
return val & ( UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW ) ;
2006-11-17 01:07:26 -05:00
}
2008-08-03 21:34:08 +01:00
static inline void ucb1400_ts_irq_enable ( struct snd_ac97 * ac97 )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ac97 , UCB_IE_CLEAR , UCB_IE_TSPX ) ;
ucb1400_reg_write ( ac97 , UCB_IE_CLEAR , 0 ) ;
ucb1400_reg_write ( ac97 , UCB_IE_FAL , UCB_IE_TSPX ) ;
2006-11-17 01:07:26 -05:00
}
2008-08-03 21:34:08 +01:00
static inline void ucb1400_ts_irq_disable ( struct snd_ac97 * ac97 )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ac97 , UCB_IE_FAL , 0 ) ;
2006-11-17 01:07:26 -05:00
}
static void ucb1400_ts_evt_add ( struct input_dev * idev , u16 pressure , u16 x , u16 y )
{
input_report_abs ( idev , ABS_X , x ) ;
input_report_abs ( idev , ABS_Y , y ) ;
input_report_abs ( idev , ABS_PRESSURE , pressure ) ;
2009-03-04 01:12:49 -08:00
input_report_key ( idev , BTN_TOUCH , 1 ) ;
2006-11-17 01:07:26 -05:00
input_sync ( idev ) ;
}
static void ucb1400_ts_event_release ( struct input_dev * idev )
{
input_report_abs ( idev , ABS_PRESSURE , 0 ) ;
2009-03-04 01:12:49 -08:00
input_report_key ( idev , BTN_TOUCH , 0 ) ;
2006-11-17 01:07:26 -05:00
input_sync ( idev ) ;
}
2008-08-03 21:34:08 +01:00
static void ucb1400_handle_pending_irq ( struct ucb1400_ts * ucb )
2006-11-17 01:07:26 -05:00
{
unsigned int isr ;
2008-08-03 21:34:08 +01:00
isr = ucb1400_reg_read ( ucb - > ac97 , UCB_IE_STATUS ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_CLEAR , isr ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_CLEAR , 0 ) ;
2006-11-17 01:07:26 -05:00
2008-08-03 21:34:08 +01:00
if ( isr & UCB_IE_TSPX ) {
ucb1400_ts_irq_disable ( ucb - > ac97 ) ;
enable_irq ( ucb - > irq ) ;
} else
2006-11-17 01:07:26 -05:00
printk ( KERN_ERR " ucb1400: unexpected IE_STATUS = %#x \n " , isr ) ;
}
static int ucb1400_ts_thread ( void * _ucb )
{
2008-08-03 21:34:08 +01:00
struct ucb1400_ts * ucb = _ucb ;
2006-11-17 01:07:26 -05:00
struct task_struct * tsk = current ;
int valid = 0 ;
2007-05-14 23:52:07 -04:00
struct sched_param param = { . sched_priority = 1 } ;
2006-11-17 01:07:26 -05:00
2007-05-14 23:52:07 -04:00
sched_setscheduler ( tsk , SCHED_FIFO , & param ) ;
2006-11-17 01:07:26 -05:00
2007-07-17 04:03:35 -07:00
set_freezable ( ) ;
2006-11-17 01:07:26 -05:00
while ( ! kthread_should_stop ( ) ) {
unsigned int x , y , p ;
long timeout ;
ucb - > ts_restart = 0 ;
if ( ucb - > irq_pending ) {
ucb - > irq_pending = 0 ;
ucb1400_handle_pending_irq ( ucb ) ;
}
2008-08-03 21:34:08 +01:00
ucb1400_adc_enable ( ucb - > ac97 ) ;
2006-11-17 01:07:26 -05:00
x = ucb1400_ts_read_xpos ( ucb ) ;
y = ucb1400_ts_read_ypos ( ucb ) ;
p = ucb1400_ts_read_pressure ( ucb ) ;
2008-08-03 21:34:08 +01:00
ucb1400_adc_disable ( ucb - > ac97 ) ;
2006-11-17 01:07:26 -05:00
/* Switch back to interrupt mode. */
2008-08-03 21:34:08 +01:00
ucb1400_ts_mode_int ( ucb - > ac97 ) ;
2006-11-17 01:07:26 -05:00
msleep ( 10 ) ;
2009-07-12 20:51:25 -07:00
if ( ucb1400_ts_pen_up ( ucb - > ac97 ) ) {
2008-08-03 21:34:08 +01:00
ucb1400_ts_irq_enable ( ucb - > ac97 ) ;
2006-11-17 01:07:26 -05:00
/*
* If we spat out a valid sample set last time ,
* spit out a " pen off " sample here .
*/
if ( valid ) {
ucb1400_ts_event_release ( ucb - > ts_idev ) ;
valid = 0 ;
}
timeout = MAX_SCHEDULE_TIMEOUT ;
} else {
valid = 1 ;
ucb1400_ts_evt_add ( ucb - > ts_idev , p , x , y ) ;
timeout = msecs_to_jiffies ( 10 ) ;
}
2007-10-18 03:04:45 -07:00
wait_event_freezable_timeout ( ucb - > ts_wait ,
2008-08-03 21:34:08 +01:00
ucb - > irq_pending | | ucb - > ts_restart | |
kthread_should_stop ( ) , timeout ) ;
2006-11-17 01:07:26 -05:00
}
/* Send the "pen off" if we are stopping with the pen still active */
if ( valid )
ucb1400_ts_event_release ( ucb - > ts_idev ) ;
ucb - > ts_task = NULL ;
return 0 ;
}
/*
* A restriction with interrupts exists when using the ucb1400 , as
* the codec read / write routines may sleep while waiting for codec
* access completion and uses semaphores for access control to the
* AC97 bus . A complete codec read cycle could take anywhere from
* 60 to 100u Sec so we * definitely * don ' t want to spin inside the
* interrupt handler waiting for codec access . So , we handle the
* interrupt by scheduling a RT kernel thread to run in process
* context instead of interrupt context .
*/
static irqreturn_t ucb1400_hard_irq ( int irqnr , void * devid )
{
2008-08-03 21:34:08 +01:00
struct ucb1400_ts * ucb = devid ;
2006-11-17 01:07:26 -05:00
if ( irqnr = = ucb - > irq ) {
2009-04-17 20:35:58 -07:00
disable_irq_nosync ( ucb - > irq ) ;
2006-11-17 01:07:26 -05:00
ucb - > irq_pending = 1 ;
wake_up ( & ucb - > ts_wait ) ;
return IRQ_HANDLED ;
}
return IRQ_NONE ;
}
static int ucb1400_ts_open ( struct input_dev * idev )
{
2008-08-03 21:34:08 +01:00
struct ucb1400_ts * ucb = input_get_drvdata ( idev ) ;
2006-11-17 01:07:26 -05:00
int ret = 0 ;
BUG_ON ( ucb - > ts_task ) ;
ucb - > ts_task = kthread_run ( ucb1400_ts_thread , ucb , " UCB1400_ts " ) ;
if ( IS_ERR ( ucb - > ts_task ) ) {
ret = PTR_ERR ( ucb - > ts_task ) ;
ucb - > ts_task = NULL ;
}
return ret ;
}
static void ucb1400_ts_close ( struct input_dev * idev )
{
2008-08-03 21:34:08 +01:00
struct ucb1400_ts * ucb = input_get_drvdata ( idev ) ;
2006-11-17 01:07:26 -05:00
if ( ucb - > ts_task )
kthread_stop ( ucb - > ts_task ) ;
2008-08-03 21:34:08 +01:00
ucb1400_ts_irq_disable ( ucb - > ac97 ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_TS_CR , 0 ) ;
2006-11-17 01:07:26 -05:00
}
# ifndef NO_IRQ
# define NO_IRQ 0
# endif
/*
* Try to probe our interrupt , rather than relying on lots of
* hard - coded machine dependencies .
*/
2008-08-03 21:34:08 +01:00
static int ucb1400_ts_detect_irq ( struct ucb1400_ts * ucb )
2006-11-17 01:07:26 -05:00
{
unsigned long mask , timeout ;
mask = probe_irq_on ( ) ;
/* Enable the ADC interrupt. */
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_RIS , UCB_IE_ADC ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_FAL , UCB_IE_ADC ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_CLEAR , 0xffff ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_CLEAR , 0 ) ;
2006-11-17 01:07:26 -05:00
/* Cause an ADC interrupt. */
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_ADC_CR , UCB_ADC_ENA ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_ADC_CR , UCB_ADC_ENA | UCB_ADC_START ) ;
2006-11-17 01:07:26 -05:00
/* Wait for the conversion to complete. */
timeout = jiffies + HZ / 2 ;
2008-08-03 21:34:08 +01:00
while ( ! ( ucb1400_reg_read ( ucb - > ac97 , UCB_ADC_DATA ) &
UCB_ADC_DAT_VALID ) ) {
2006-11-17 01:07:26 -05:00
cpu_relax ( ) ;
if ( time_after ( jiffies , timeout ) ) {
printk ( KERN_ERR " ucb1400: timed out in IRQ probe \n " ) ;
probe_irq_off ( mask ) ;
return - ENODEV ;
}
}
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_ADC_CR , 0 ) ;
2006-11-17 01:07:26 -05:00
/* Disable and clear interrupt. */
2008-08-03 21:34:08 +01:00
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_RIS , 0 ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_FAL , 0 ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_CLEAR , 0xffff ) ;
ucb1400_reg_write ( ucb - > ac97 , UCB_IE_CLEAR , 0 ) ;
2006-11-17 01:07:26 -05:00
/* Read triggered interrupt. */
ucb - > irq = probe_irq_off ( mask ) ;
if ( ucb - > irq < 0 | | ucb - > irq = = NO_IRQ )
return - ENODEV ;
return 0 ;
}
2008-08-03 21:34:08 +01:00
static int ucb1400_ts_probe ( struct platform_device * dev )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
int error , x_res , y_res ;
struct ucb1400_ts * ucb = dev - > dev . platform_data ;
2006-11-17 01:07:26 -05:00
2008-08-03 21:34:08 +01:00
ucb - > ts_idev = input_allocate_device ( ) ;
if ( ! ucb - > ts_idev ) {
2006-11-17 01:07:26 -05:00
error = - ENOMEM ;
2008-08-03 21:34:08 +01:00
goto err ;
2006-11-17 01:07:26 -05:00
}
2008-08-03 21:34:08 +01:00
error = ucb1400_ts_detect_irq ( ucb ) ;
2006-11-17 01:07:26 -05:00
if ( error ) {
printk ( KERN_ERR " UCB1400: IRQ probe failed \n " ) ;
goto err_free_devs ;
}
2008-08-03 21:34:08 +01:00
init_waitqueue_head ( & ucb - > ts_wait ) ;
2006-11-17 01:07:26 -05:00
error = request_irq ( ucb - > irq , ucb1400_hard_irq , IRQF_TRIGGER_RISING ,
" UCB1400 " , ucb ) ;
if ( error ) {
printk ( KERN_ERR " ucb1400: unable to grab irq%d: %d \n " ,
ucb - > irq , error ) ;
goto err_free_devs ;
}
printk ( KERN_DEBUG " UCB1400: found IRQ %d \n " , ucb - > irq ) ;
2008-08-03 21:34:08 +01:00
input_set_drvdata ( ucb - > ts_idev , ucb ) ;
2007-04-12 01:34:08 -04:00
2008-08-03 21:34:08 +01:00
ucb - > ts_idev - > dev . parent = & dev - > dev ;
ucb - > ts_idev - > name = " UCB1400 touchscreen interface " ;
ucb - > ts_idev - > id . vendor = ucb1400_reg_read ( ucb - > ac97 ,
AC97_VENDOR_ID1 ) ;
ucb - > ts_idev - > id . product = ucb - > id ;
ucb - > ts_idev - > open = ucb1400_ts_open ;
ucb - > ts_idev - > close = ucb1400_ts_close ;
2009-03-04 01:12:49 -08:00
ucb - > ts_idev - > evbit [ 0 ] = BIT_MASK ( EV_ABS ) | BIT_MASK ( EV_KEY ) ;
ucb - > ts_idev - > keybit [ BIT_WORD ( BTN_TOUCH ) ] = BIT_MASK ( BTN_TOUCH ) ;
2006-11-17 01:07:26 -05:00
2008-08-03 21:34:08 +01:00
ucb1400_adc_enable ( ucb - > ac97 ) ;
2006-11-17 01:07:26 -05:00
x_res = ucb1400_ts_read_xres ( ucb ) ;
y_res = ucb1400_ts_read_yres ( ucb ) ;
2008-08-03 21:34:08 +01:00
ucb1400_adc_disable ( ucb - > ac97 ) ;
2006-11-17 01:07:26 -05:00
printk ( KERN_DEBUG " UCB1400: x/y = %d/%d \n " , x_res , y_res ) ;
2008-08-03 21:34:08 +01:00
input_set_abs_params ( ucb - > ts_idev , ABS_X , 0 , x_res , 0 , 0 ) ;
input_set_abs_params ( ucb - > ts_idev , ABS_Y , 0 , y_res , 0 , 0 ) ;
input_set_abs_params ( ucb - > ts_idev , ABS_PRESSURE , 0 , 0 , 0 , 0 ) ;
2006-11-17 01:07:26 -05:00
2008-08-03 21:34:08 +01:00
error = input_register_device ( ucb - > ts_idev ) ;
2006-11-17 01:07:26 -05:00
if ( error )
goto err_free_irq ;
return 0 ;
2008-08-03 21:34:08 +01:00
err_free_irq :
2006-11-17 01:07:26 -05:00
free_irq ( ucb - > irq , ucb ) ;
2008-08-03 21:34:08 +01:00
err_free_devs :
input_free_device ( ucb - > ts_idev ) ;
err :
2006-11-17 01:07:26 -05:00
return error ;
2008-08-03 21:34:08 +01:00
2006-11-17 01:07:26 -05:00
}
2008-08-03 21:34:08 +01:00
static int ucb1400_ts_remove ( struct platform_device * dev )
2006-11-17 01:07:26 -05:00
{
2008-08-03 21:34:08 +01:00
struct ucb1400_ts * ucb = dev - > dev . platform_data ;
2006-11-17 01:07:26 -05:00
free_irq ( ucb - > irq , ucb ) ;
input_unregister_device ( ucb - > ts_idev ) ;
return 0 ;
}
2008-08-03 21:34:08 +01:00
# ifdef CONFIG_PM
static int ucb1400_ts_resume ( struct platform_device * dev )
{
2009-05-27 06:20:05 -07:00
struct ucb1400_ts * ucb = dev - > dev . platform_data ;
2008-08-03 21:34:08 +01:00
if ( ucb - > ts_task ) {
/*
* Restart the TS thread to ensure the
* TS interrupt mode is set up again
* after sleep .
*/
ucb - > ts_restart = 1 ;
wake_up ( & ucb - > ts_wait ) ;
}
return 0 ;
}
# else
# define ucb1400_ts_resume NULL
# endif
static struct platform_driver ucb1400_ts_driver = {
. probe = ucb1400_ts_probe ,
. remove = ucb1400_ts_remove ,
. resume = ucb1400_ts_resume ,
. driver = {
. name = " ucb1400_ts " ,
} ,
2006-11-17 01:07:26 -05:00
} ;
static int __init ucb1400_ts_init ( void )
{
2008-08-03 21:34:08 +01:00
return platform_driver_register ( & ucb1400_ts_driver ) ;
2006-11-17 01:07:26 -05:00
}
static void __exit ucb1400_ts_exit ( void )
{
2008-08-03 21:34:08 +01:00
platform_driver_unregister ( & ucb1400_ts_driver ) ;
2006-11-17 01:07:26 -05:00
}
2007-04-12 01:35:43 -04:00
module_param ( adcsync , bool , 0444 ) ;
MODULE_PARM_DESC ( adcsync , " Synchronize touch readings with ADCSYNC pin. " ) ;
module_param ( ts_delay , int , 0444 ) ;
2008-08-03 21:34:08 +01:00
MODULE_PARM_DESC ( ts_delay , " Delay between panel setup and "
" position read. Default = 55us. " ) ;
2007-04-12 01:35:43 -04:00
module_param ( ts_delay_pressure , int , 0444 ) ;
MODULE_PARM_DESC ( ts_delay_pressure ,
2008-08-03 21:34:08 +01:00
" delay between panel setup and pressure read. "
" Default = 0us. " ) ;
2006-11-17 01:07:26 -05:00
module_init ( ucb1400_ts_init ) ;
module_exit ( ucb1400_ts_exit ) ;
MODULE_DESCRIPTION ( " Philips UCB1400 touchscreen driver " ) ;
MODULE_LICENSE ( " GPL " ) ;