2011-03-17 08:07:36 +03:00
/*
* TSC2005 touchscreen driver
*
* Copyright ( C ) 2006 - 2010 Nokia Corporation
*
* Author : Lauri Leukkunen < lauri . leukkunen @ nokia . com >
* based on TSC2301 driver by Klaus K . Pedersen < klaus . k . pedersen @ nokia . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/input.h>
# include <linux/interrupt.h>
# include <linux/delay.h>
2011-03-17 08:08:26 +03:00
# include <linux/pm.h>
2011-03-17 08:07:36 +03:00
# include <linux/spi/spi.h>
# include <linux/spi/tsc2005.h>
/*
* The touchscreen interface operates as follows :
*
* 1 ) Pen is pressed against the touchscreen .
* 2 ) TSC2005 performs AD conversion .
* 3 ) After the conversion is done TSC2005 drives DAV line down .
* 4 ) GPIO IRQ is received and tsc2005_irq_thread ( ) is scheduled .
* 5 ) tsc2005_irq_thread ( ) queues up an spi transfer to fetch the x , y , z1 , z2
* values .
* 6 ) tsc2005_irq_thread ( ) reports coordinates to input layer and sets up
* tsc2005_penup_timer ( ) to be called after TSC2005_PENUP_TIME_MS ( 40 ms ) .
* 7 ) When the penup timer expires , there have not been touch or DAV interrupts
* during the last 40 ms which means the pen has been lifted .
*
* ESD recovery via a hardware reset is done if the TSC2005 doesn ' t respond
* after a configurable period ( in ms ) of activity . If esd_timeout is 0 , the
* watchdog is disabled .
*/
/* control byte 1 */
# define TSC2005_CMD 0x80
# define TSC2005_CMD_NORMAL 0x00
# define TSC2005_CMD_STOP 0x01
# define TSC2005_CMD_12BIT 0x04
/* control byte 0 */
# define TSC2005_REG_READ 0x0001
# define TSC2005_REG_PND0 0x0002
# define TSC2005_REG_X 0x0000
# define TSC2005_REG_Y 0x0008
# define TSC2005_REG_Z1 0x0010
# define TSC2005_REG_Z2 0x0018
# define TSC2005_REG_TEMP_HIGH 0x0050
# define TSC2005_REG_CFR0 0x0060
# define TSC2005_REG_CFR1 0x0068
# define TSC2005_REG_CFR2 0x0070
/* configuration register 0 */
# define TSC2005_CFR0_PRECHARGE_276US 0x0040
# define TSC2005_CFR0_STABTIME_1MS 0x0300
# define TSC2005_CFR0_CLOCK_1MHZ 0x1000
# define TSC2005_CFR0_RESOLUTION12 0x2000
# define TSC2005_CFR0_PENMODE 0x8000
# define TSC2005_CFR0_INITVALUE (TSC2005_CFR0_STABTIME_1MS | \
TSC2005_CFR0_CLOCK_1MHZ | \
TSC2005_CFR0_RESOLUTION12 | \
TSC2005_CFR0_PRECHARGE_276US | \
TSC2005_CFR0_PENMODE )
/* bits common to both read and write of configuration register 0 */
# define TSC2005_CFR0_RW_MASK 0x3fff
/* configuration register 1 */
# define TSC2005_CFR1_BATCHDELAY_4MS 0x0003
# define TSC2005_CFR1_INITVALUE TSC2005_CFR1_BATCHDELAY_4MS
/* configuration register 2 */
# define TSC2005_CFR2_MAVE_Z 0x0004
# define TSC2005_CFR2_MAVE_Y 0x0008
# define TSC2005_CFR2_MAVE_X 0x0010
# define TSC2005_CFR2_AVG_7 0x0800
# define TSC2005_CFR2_MEDIUM_15 0x3000
# define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_MAVE_X | \
TSC2005_CFR2_MAVE_Y | \
TSC2005_CFR2_MAVE_Z | \
TSC2005_CFR2_MEDIUM_15 | \
TSC2005_CFR2_AVG_7 )
# define MAX_12BIT 0xfff
# define TSC2005_SPI_MAX_SPEED_HZ 10000000
# define TSC2005_PENUP_TIME_MS 40
struct tsc2005_spi_rd {
struct spi_transfer spi_xfer ;
u32 spi_tx ;
u32 spi_rx ;
} ;
struct tsc2005 {
struct spi_device * spi ;
struct spi_message spi_read_msg ;
struct tsc2005_spi_rd spi_x ;
struct tsc2005_spi_rd spi_y ;
struct tsc2005_spi_rd spi_z1 ;
struct tsc2005_spi_rd spi_z2 ;
struct input_dev * idev ;
char phys [ 32 ] ;
struct mutex mutex ;
/* raw copy of previous x,y,z */
int in_x ;
int in_y ;
int in_z1 ;
int in_z2 ;
2011-03-17 08:11:08 +03:00
spinlock_t lock ;
2011-03-17 08:07:36 +03:00
struct timer_list penup_timer ;
unsigned int esd_timeout ;
2011-03-17 08:11:34 +03:00
struct delayed_work esd_work ;
unsigned long last_valid_interrupt ;
2011-03-17 08:07:36 +03:00
unsigned int x_plate_ohm ;
2011-03-17 08:11:34 +03:00
bool opened ;
bool suspended ;
2011-03-17 08:10:46 +03:00
bool pen_down ;
2011-03-17 08:07:36 +03:00
void ( * set_reset ) ( bool enable ) ;
} ;
2011-03-17 08:11:25 +03:00
static int tsc2005_cmd ( struct tsc2005 * ts , u8 cmd )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:10:52 +03:00
u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd ;
struct spi_transfer xfer = {
. tx_buf = & tx ,
. len = 1 ,
. bits_per_word = 8 ,
} ;
2011-03-17 08:07:36 +03:00
struct spi_message msg ;
2011-03-17 08:11:25 +03:00
int error ;
2011-03-17 08:07:36 +03:00
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
2011-03-17 08:11:25 +03:00
error = spi_sync ( ts - > spi , & msg ) ;
if ( error ) {
dev_err ( & ts - > spi - > dev , " %s: failed, command: %x, error: %d \n " ,
__func__ , cmd , error ) ;
return error ;
}
return 0 ;
2011-03-17 08:07:36 +03:00
}
2011-03-17 08:11:25 +03:00
static int tsc2005_write ( struct tsc2005 * ts , u8 reg , u16 value )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:10:52 +03:00
u32 tx = ( ( reg | TSC2005_REG_PND0 ) < < 16 ) | value ;
struct spi_transfer xfer = {
. tx_buf = & tx ,
. len = 4 ,
. bits_per_word = 24 ,
} ;
2011-03-17 08:07:36 +03:00
struct spi_message msg ;
2011-03-17 08:11:25 +03:00
int error ;
2011-03-17 08:07:36 +03:00
spi_message_init ( & msg ) ;
spi_message_add_tail ( & xfer , & msg ) ;
2011-03-17 08:11:25 +03:00
error = spi_sync ( ts - > spi , & msg ) ;
if ( error ) {
dev_err ( & ts - > spi - > dev ,
" %s: failed, register: %x, value: %x, error: %d \n " ,
__func__ , reg , value , error ) ;
return error ;
}
return 0 ;
2011-03-17 08:07:36 +03:00
}
static void tsc2005_setup_read ( struct tsc2005_spi_rd * rd , u8 reg , bool last )
{
2011-03-17 08:10:52 +03:00
memset ( rd , 0 , sizeof ( * rd ) ) ;
2011-03-17 08:07:36 +03:00
rd - > spi_tx = ( reg | TSC2005_REG_READ ) < < 16 ;
rd - > spi_xfer . tx_buf = & rd - > spi_tx ;
rd - > spi_xfer . rx_buf = & rd - > spi_rx ;
rd - > spi_xfer . len = 4 ;
rd - > spi_xfer . bits_per_word = 24 ;
rd - > spi_xfer . cs_change = ! last ;
}
2011-03-17 08:11:25 +03:00
static int tsc2005_read ( struct tsc2005 * ts , u8 reg , u16 * value )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:10:52 +03:00
struct tsc2005_spi_rd spi_rd ;
2011-03-17 08:07:36 +03:00
struct spi_message msg ;
2011-03-17 08:11:25 +03:00
int error ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:10:46 +03:00
tsc2005_setup_read ( & spi_rd , reg , true ) ;
2011-03-17 08:07:36 +03:00
spi_message_init ( & msg ) ;
spi_message_add_tail ( & spi_rd . spi_xfer , & msg ) ;
2011-03-17 08:11:25 +03:00
error = spi_sync ( ts - > spi , & msg ) ;
if ( error )
return error ;
2011-03-17 08:10:52 +03:00
2011-03-17 08:07:36 +03:00
* value = spi_rd . spi_rx ;
2011-03-17 08:11:25 +03:00
return 0 ;
2011-03-17 08:07:36 +03:00
}
static void tsc2005_update_pen_state ( struct tsc2005 * ts ,
int x , int y , int pressure )
{
if ( pressure ) {
input_report_abs ( ts - > idev , ABS_X , x ) ;
input_report_abs ( ts - > idev , ABS_Y , y ) ;
input_report_abs ( ts - > idev , ABS_PRESSURE , pressure ) ;
if ( ! ts - > pen_down ) {
input_report_key ( ts - > idev , BTN_TOUCH , ! ! pressure ) ;
2011-03-17 08:10:46 +03:00
ts - > pen_down = true ;
2011-03-17 08:07:36 +03:00
}
} else {
input_report_abs ( ts - > idev , ABS_PRESSURE , 0 ) ;
if ( ts - > pen_down ) {
input_report_key ( ts - > idev , BTN_TOUCH , 0 ) ;
2011-03-17 08:10:46 +03:00
ts - > pen_down = false ;
2011-03-17 08:07:36 +03:00
}
}
input_sync ( ts - > idev ) ;
dev_dbg ( & ts - > spi - > dev , " point(%4d,%4d), pressure (%4d) \n " , x , y ,
pressure ) ;
}
static irqreturn_t tsc2005_irq_thread ( int irq , void * _ts )
{
struct tsc2005 * ts = _ts ;
2011-03-17 08:11:08 +03:00
unsigned long flags ;
2011-03-17 08:07:36 +03:00
unsigned int pressure ;
2011-03-17 08:11:08 +03:00
u32 x , y ;
u32 z1 , z2 ;
2011-03-17 08:11:25 +03:00
int error ;
2011-03-17 08:07:36 +03:00
/* read the coordinates */
2011-03-17 08:11:25 +03:00
error = spi_sync ( ts - > spi , & ts - > spi_read_msg ) ;
if ( unlikely ( error ) )
goto out ;
2011-03-17 08:07:36 +03:00
x = ts - > spi_x . spi_rx ;
y = ts - > spi_y . spi_rx ;
z1 = ts - > spi_z1 . spi_rx ;
z2 = ts - > spi_z2 . spi_rx ;
/* validate position */
if ( unlikely ( x > MAX_12BIT | | y > MAX_12BIT ) )
goto out ;
2011-03-17 08:11:08 +03:00
/* Skip reading if the pressure components are out of range */
2011-03-17 08:07:36 +03:00
if ( unlikely ( z1 = = 0 | | z2 > MAX_12BIT | | z1 > = z2 ) )
goto out ;
2011-03-17 08:11:08 +03:00
/*
* Skip point if this is a pen down with the exact same values as
2011-03-17 08:07:36 +03:00
* the value before pen - up - that implies SPI fed us stale data
*/
if ( ! ts - > pen_down & &
2011-03-17 08:11:08 +03:00
ts - > in_x = = x & & ts - > in_y = = y & &
ts - > in_z1 = = z1 & & ts - > in_z2 = = z2 ) {
2011-03-17 08:07:36 +03:00
goto out ;
2011-03-17 08:11:08 +03:00
}
2011-03-17 08:07:36 +03:00
2011-03-17 08:11:08 +03:00
/*
* At this point we are happy we have a valid and useful reading .
* Remember it for later comparisons . We may now begin downsampling .
*/
2011-03-17 08:07:36 +03:00
ts - > in_x = x ;
ts - > in_y = y ;
ts - > in_z1 = z1 ;
ts - > in_z2 = z2 ;
2011-03-17 08:11:08 +03:00
/* Compute touch pressure resistance using equation #1 */
2011-03-17 08:07:36 +03:00
pressure = x * ( z2 - z1 ) / z1 ;
pressure = pressure * ts - > x_plate_ohm / 4096 ;
if ( unlikely ( pressure > MAX_12BIT ) )
goto out ;
2011-03-17 08:11:08 +03:00
spin_lock_irqsave ( & ts - > lock , flags ) ;
2011-03-17 08:07:36 +03:00
tsc2005_update_pen_state ( ts , x , y , pressure ) ;
mod_timer ( & ts - > penup_timer ,
jiffies + msecs_to_jiffies ( TSC2005_PENUP_TIME_MS ) ) ;
2011-03-17 08:11:08 +03:00
spin_unlock_irqrestore ( & ts - > lock , flags ) ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:11:34 +03:00
ts - > last_valid_interrupt = jiffies ;
2011-03-17 08:07:36 +03:00
out :
return IRQ_HANDLED ;
}
static void tsc2005_penup_timer ( unsigned long data )
{
struct tsc2005 * ts = ( struct tsc2005 * ) data ;
2011-03-17 08:11:08 +03:00
unsigned long flags ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:11:08 +03:00
spin_lock_irqsave ( & ts - > lock , flags ) ;
2011-03-17 08:07:36 +03:00
tsc2005_update_pen_state ( ts , 0 , 0 , 0 ) ;
2011-03-17 08:11:08 +03:00
spin_unlock_irqrestore ( & ts - > lock , flags ) ;
2011-03-17 08:07:36 +03:00
}
static void tsc2005_start_scan ( struct tsc2005 * ts )
{
tsc2005_write ( ts , TSC2005_REG_CFR0 , TSC2005_CFR0_INITVALUE ) ;
tsc2005_write ( ts , TSC2005_REG_CFR1 , TSC2005_CFR1_INITVALUE ) ;
tsc2005_write ( ts , TSC2005_REG_CFR2 , TSC2005_CFR2_INITVALUE ) ;
tsc2005_cmd ( ts , TSC2005_CMD_NORMAL ) ;
}
static void tsc2005_stop_scan ( struct tsc2005 * ts )
{
tsc2005_cmd ( ts , TSC2005_CMD_STOP ) ;
}
2011-03-17 08:11:34 +03:00
/* must be called with ts->mutex held */
static void __tsc2005_disable ( struct tsc2005 * ts )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:11:34 +03:00
tsc2005_stop_scan ( ts ) ;
2011-03-17 08:07:36 +03:00
disable_irq ( ts - > spi - > irq ) ;
del_timer_sync ( & ts - > penup_timer ) ;
2011-03-17 08:11:34 +03:00
cancel_delayed_work_sync ( & ts - > esd_work ) ;
enable_irq ( ts - > spi - > irq ) ;
2011-03-17 08:07:36 +03:00
}
2011-03-17 08:11:34 +03:00
/* must be called with ts->mutex held */
static void __tsc2005_enable ( struct tsc2005 * ts )
2011-03-17 08:07:36 +03:00
{
tsc2005_start_scan ( ts ) ;
2011-03-17 08:11:34 +03:00
if ( ts - > esd_timeout & & ts - > set_reset ) {
ts - > last_valid_interrupt = jiffies ;
schedule_delayed_work ( & ts - > esd_work ,
2011-03-24 09:45:11 +03:00
round_jiffies_relative (
2011-03-17 08:11:34 +03:00
msecs_to_jiffies ( ts - > esd_timeout ) ) ) ;
}
2011-03-17 08:07:36 +03:00
}
static ssize_t tsc2005_selftest_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
2011-03-17 08:08:08 +03:00
struct spi_device * spi = to_spi_device ( dev ) ;
struct tsc2005 * ts = spi_get_drvdata ( spi ) ;
2011-03-17 08:07:36 +03:00
u16 temp_high ;
u16 temp_high_orig ;
u16 temp_high_test ;
2011-03-17 08:11:25 +03:00
bool success = true ;
int error ;
2011-03-17 08:07:36 +03:00
mutex_lock ( & ts - > mutex ) ;
/*
* Test TSC2005 communications via temp high register .
*/
2011-03-17 08:11:34 +03:00
__tsc2005_disable ( ts ) ;
2011-03-17 08:11:25 +03:00
error = tsc2005_read ( ts , TSC2005_REG_TEMP_HIGH , & temp_high_orig ) ;
if ( error ) {
dev_warn ( dev , " selftest failed: read error %d \n " , error ) ;
success = false ;
goto out ;
}
2011-03-17 08:07:36 +03:00
temp_high_test = ( temp_high_orig - 1 ) & MAX_12BIT ;
2011-03-17 08:11:25 +03:00
error = tsc2005_write ( ts , TSC2005_REG_TEMP_HIGH , temp_high_test ) ;
if ( error ) {
dev_warn ( dev , " selftest failed: write error %d \n " , error ) ;
success = false ;
goto out ;
}
error = tsc2005_read ( ts , TSC2005_REG_TEMP_HIGH , & temp_high ) ;
if ( error ) {
dev_warn ( dev , " selftest failed: read error %d after write \n " ,
error ) ;
success = false ;
goto out ;
}
2011-03-17 08:07:36 +03:00
if ( temp_high ! = temp_high_test ) {
dev_warn ( dev , " selftest failed: %d != %d \n " ,
temp_high , temp_high_test ) ;
2011-03-17 08:11:25 +03:00
success = false ;
2011-03-17 08:07:36 +03:00
}
/* hardware reset */
2011-03-17 08:10:46 +03:00
ts - > set_reset ( false ) ;
2011-03-17 08:07:36 +03:00
usleep_range ( 100 , 500 ) ; /* only 10us required */
2011-03-17 08:10:46 +03:00
ts - > set_reset ( true ) ;
2011-03-17 08:11:25 +03:00
if ( ! success )
goto out ;
2011-03-17 08:07:36 +03:00
/* test that the reset really happened */
2011-03-17 08:11:25 +03:00
error = tsc2005_read ( ts , TSC2005_REG_TEMP_HIGH , & temp_high ) ;
if ( error ) {
dev_warn ( dev , " selftest failed: read error %d after reset \n " ,
error ) ;
success = false ;
goto out ;
}
2011-03-17 08:07:36 +03:00
if ( temp_high ! = temp_high_orig ) {
dev_warn ( dev , " selftest failed after reset: %d != %d \n " ,
temp_high , temp_high_orig ) ;
2011-03-17 08:11:25 +03:00
success = false ;
2011-03-17 08:07:36 +03:00
}
2011-03-17 08:11:25 +03:00
out :
2011-03-17 08:11:34 +03:00
__tsc2005_enable ( ts ) ;
2011-03-17 08:07:36 +03:00
mutex_unlock ( & ts - > mutex ) ;
2011-03-17 08:11:25 +03:00
return sprintf ( buf , " %d \n " , success ) ;
2011-03-17 08:07:36 +03:00
}
2011-03-17 08:10:37 +03:00
2011-03-17 08:07:36 +03:00
static DEVICE_ATTR ( selftest , S_IRUGO , tsc2005_selftest_show , NULL ) ;
2011-03-17 08:10:37 +03:00
static struct attribute * tsc2005_attrs [ ] = {
& dev_attr_selftest . attr ,
NULL
} ;
2011-07-24 07:11:19 +04:00
static umode_t tsc2005_attr_is_visible ( struct kobject * kobj ,
2011-03-17 08:10:37 +03:00
struct attribute * attr , int n )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct spi_device * spi = to_spi_device ( dev ) ;
struct tsc2005 * ts = spi_get_drvdata ( spi ) ;
2011-07-24 07:11:19 +04:00
umode_t mode = attr - > mode ;
2011-03-17 08:10:37 +03:00
if ( attr = = & dev_attr_selftest . attr ) {
if ( ! ts - > set_reset )
mode = 0 ;
}
return mode ;
}
static const struct attribute_group tsc2005_attr_group = {
. is_visible = tsc2005_attr_is_visible ,
. attrs = tsc2005_attrs ,
} ;
2011-03-17 08:07:36 +03:00
static void tsc2005_esd_work ( struct work_struct * work )
{
2011-03-17 08:11:34 +03:00
struct tsc2005 * ts = container_of ( work , struct tsc2005 , esd_work . work ) ;
2011-03-17 08:11:25 +03:00
int error ;
2011-03-17 08:07:36 +03:00
u16 r ;
2011-03-24 09:48:19 +03:00
if ( ! mutex_trylock ( & ts - > mutex ) ) {
/*
* If the mutex is taken , it means that disable or enable is in
* progress . In that case just reschedule the work . If the work
* is not needed , it will be canceled by disable .
*/
goto reschedule ;
}
2011-03-17 08:07:36 +03:00
2011-03-17 08:11:34 +03:00
if ( time_is_after_jiffies ( ts - > last_valid_interrupt +
msecs_to_jiffies ( ts - > esd_timeout ) ) )
2011-03-17 08:07:36 +03:00
goto out ;
2011-03-17 08:11:34 +03:00
/* We should be able to read register without disabling interrupts. */
2011-03-17 08:11:25 +03:00
error = tsc2005_read ( ts , TSC2005_REG_CFR0 , & r ) ;
2011-03-17 08:11:34 +03:00
if ( ! error & &
! ( ( r ^ TSC2005_CFR0_INITVALUE ) & TSC2005_CFR0_RW_MASK ) ) {
goto out ;
2011-03-17 08:07:36 +03:00
}
2011-03-17 08:11:34 +03:00
/*
* If we could not read our known value from configuration register 0
* then we should reset the controller as if from power - up and start
* scanning again .
*/
dev_info ( & ts - > spi - > dev , " TSC2005 not responding - resetting \n " ) ;
disable_irq ( ts - > spi - > irq ) ;
del_timer_sync ( & ts - > penup_timer ) ;
tsc2005_update_pen_state ( ts , 0 , 0 , 0 ) ;
ts - > set_reset ( false ) ;
usleep_range ( 100 , 500 ) ; /* only 10us required */
ts - > set_reset ( true ) ;
enable_irq ( ts - > spi - > irq ) ;
tsc2005_start_scan ( ts ) ;
2011-03-17 08:07:36 +03:00
out :
2011-03-24 09:48:19 +03:00
mutex_unlock ( & ts - > mutex ) ;
reschedule :
2011-03-17 08:11:34 +03:00
/* re-arm the watchdog */
schedule_delayed_work ( & ts - > esd_work ,
2011-03-24 09:45:11 +03:00
round_jiffies_relative (
2011-03-17 08:11:34 +03:00
msecs_to_jiffies ( ts - > esd_timeout ) ) ) ;
}
static int tsc2005_open ( struct input_dev * input )
{
struct tsc2005 * ts = input_get_drvdata ( input ) ;
mutex_lock ( & ts - > mutex ) ;
2011-03-17 08:11:41 +03:00
if ( ! ts - > suspended )
2011-03-17 08:11:34 +03:00
__tsc2005_enable ( ts ) ;
ts - > opened = true ;
mutex_unlock ( & ts - > mutex ) ;
return 0 ;
}
static void tsc2005_close ( struct input_dev * input )
{
struct tsc2005 * ts = input_get_drvdata ( input ) ;
mutex_lock ( & ts - > mutex ) ;
2011-03-17 08:11:41 +03:00
if ( ! ts - > suspended )
2011-03-17 08:11:34 +03:00
__tsc2005_disable ( ts ) ;
ts - > opened = false ;
2011-03-17 08:07:36 +03:00
mutex_unlock ( & ts - > mutex ) ;
}
2012-11-24 09:38:25 +04:00
static void tsc2005_setup_spi_xfer ( struct tsc2005 * ts )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:10:46 +03:00
tsc2005_setup_read ( & ts - > spi_x , TSC2005_REG_X , false ) ;
tsc2005_setup_read ( & ts - > spi_y , TSC2005_REG_Y , false ) ;
tsc2005_setup_read ( & ts - > spi_z1 , TSC2005_REG_Z1 , false ) ;
tsc2005_setup_read ( & ts - > spi_z2 , TSC2005_REG_Z2 , true ) ;
2011-03-17 08:07:36 +03:00
spi_message_init ( & ts - > spi_read_msg ) ;
spi_message_add_tail ( & ts - > spi_x . spi_xfer , & ts - > spi_read_msg ) ;
spi_message_add_tail ( & ts - > spi_y . spi_xfer , & ts - > spi_read_msg ) ;
spi_message_add_tail ( & ts - > spi_z1 . spi_xfer , & ts - > spi_read_msg ) ;
spi_message_add_tail ( & ts - > spi_z2 . spi_xfer , & ts - > spi_read_msg ) ;
}
2012-11-24 09:38:25 +04:00
static int tsc2005_probe ( struct spi_device * spi )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:09:38 +03:00
const struct tsc2005_platform_data * pdata = spi - > dev . platform_data ;
struct tsc2005 * ts ;
struct input_dev * input_dev ;
unsigned int max_x , max_y , max_p ;
unsigned int fudge_x , fudge_y , fudge_p ;
int error ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
if ( ! pdata ) {
dev_dbg ( & spi - > dev , " no platform data \n " ) ;
return - ENODEV ;
}
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
fudge_x = pdata - > ts_x_fudge ? : 4 ;
fudge_y = pdata - > ts_y_fudge ? : 8 ;
fudge_p = pdata - > ts_pressure_fudge ? : 2 ;
max_x = pdata - > ts_x_max ? : MAX_12BIT ;
max_y = pdata - > ts_y_max ? : MAX_12BIT ;
max_p = pdata - > ts_pressure_max ? : MAX_12BIT ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
if ( spi - > irq < = 0 ) {
dev_dbg ( & spi - > dev , " no irq \n " ) ;
return - ENODEV ;
}
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
spi - > mode = SPI_MODE_0 ;
spi - > bits_per_word = 8 ;
if ( ! spi - > max_speed_hz )
spi - > max_speed_hz = TSC2005_SPI_MAX_SPEED_HZ ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
error = spi_setup ( spi ) ;
if ( error )
return error ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
ts = kzalloc ( sizeof ( * ts ) , GFP_KERNEL ) ;
input_dev = input_allocate_device ( ) ;
if ( ! ts | | ! input_dev ) {
error = - ENOMEM ;
goto err_free_mem ;
2011-03-17 08:07:36 +03:00
}
2011-03-17 08:09:38 +03:00
ts - > spi = spi ;
ts - > idev = input_dev ;
ts - > x_plate_ohm = pdata - > ts_x_plate_ohm ? : 280 ;
ts - > esd_timeout = pdata - > esd_timeout_ms ;
ts - > set_reset = pdata - > set_reset ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
mutex_init ( & ts - > mutex ) ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:11:08 +03:00
spin_lock_init ( & ts - > lock ) ;
2011-03-17 08:09:38 +03:00
setup_timer ( & ts - > penup_timer , tsc2005_penup_timer , ( unsigned long ) ts ) ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:11:34 +03:00
INIT_DELAYED_WORK ( & ts - > esd_work , tsc2005_esd_work ) ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
tsc2005_setup_spi_xfer ( ts ) ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
snprintf ( ts - > phys , sizeof ( ts - > phys ) ,
" %s/input-ts " , dev_name ( & spi - > dev ) ) ;
input_dev - > name = " TSC2005 touchscreen " ;
input_dev - > phys = ts - > phys ;
input_dev - > id . bustype = BUS_SPI ;
input_dev - > dev . parent = & spi - > dev ;
input_dev - > evbit [ 0 ] = BIT ( EV_ABS ) | BIT ( EV_KEY ) ;
input_dev - > keybit [ BIT_WORD ( BTN_TOUCH ) ] = BIT_MASK ( BTN_TOUCH ) ;
input_set_abs_params ( input_dev , ABS_X , 0 , max_x , fudge_x , 0 ) ;
input_set_abs_params ( input_dev , ABS_Y , 0 , max_y , fudge_y , 0 ) ;
input_set_abs_params ( input_dev , ABS_PRESSURE , 0 , max_p , fudge_p , 0 ) ;
2011-03-17 08:11:34 +03:00
input_dev - > open = tsc2005_open ;
input_dev - > close = tsc2005_close ;
input_set_drvdata ( input_dev , ts ) ;
/* Ensure the touchscreen is off */
tsc2005_stop_scan ( ts ) ;
2011-03-17 08:11:14 +03:00
error = request_threaded_irq ( spi - > irq , NULL , tsc2005_irq_thread ,
2012-07-05 00:02:56 +04:00
IRQF_TRIGGER_RISING | IRQF_ONESHOT ,
" tsc2005 " , ts ) ;
2011-03-17 08:09:38 +03:00
if ( error ) {
dev_err ( & spi - > dev , " Failed to request irq, err: %d \n " , error ) ;
goto err_free_mem ;
2011-03-17 08:07:36 +03:00
}
2011-03-17 08:09:38 +03:00
spi_set_drvdata ( spi , ts ) ;
error = sysfs_create_group ( & spi - > dev . kobj , & tsc2005_attr_group ) ;
if ( error ) {
dev_err ( & spi - > dev ,
" Failed to create sysfs attributes, err: %d \n " , error ) ;
goto err_clear_drvdata ;
2011-03-17 08:07:36 +03:00
}
2011-03-17 08:09:38 +03:00
error = input_register_device ( ts - > idev ) ;
if ( error ) {
dev_err ( & spi - > dev ,
" Failed to register input device, err: %d \n " , error ) ;
goto err_remove_sysfs ;
}
2011-03-17 08:07:36 +03:00
2011-03-21 12:37:07 +03:00
irq_set_irq_wake ( spi - > irq , 1 ) ;
2011-03-17 08:09:38 +03:00
return 0 ;
err_remove_sysfs :
sysfs_remove_group ( & spi - > dev . kobj , & tsc2005_attr_group ) ;
err_clear_drvdata :
spi_set_drvdata ( spi , NULL ) ;
free_irq ( spi - > irq , ts ) ;
err_free_mem :
input_free_device ( input_dev ) ;
kfree ( ts ) ;
return error ;
2011-03-17 08:07:36 +03:00
}
2012-11-24 09:50:47 +04:00
static int tsc2005_remove ( struct spi_device * spi )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:08:08 +03:00
struct tsc2005 * ts = spi_get_drvdata ( spi ) ;
2011-03-17 08:07:36 +03:00
2011-03-17 08:09:38 +03:00
sysfs_remove_group ( & ts - > spi - > dev . kobj , & tsc2005_attr_group ) ;
2011-03-17 08:07:36 +03:00
free_irq ( ts - > spi - > irq , ts ) ;
input_unregister_device ( ts - > idev ) ;
kfree ( ts ) ;
2011-03-17 08:09:09 +03:00
spi_set_drvdata ( spi , NULL ) ;
2011-03-17 08:07:36 +03:00
return 0 ;
}
2011-03-17 08:08:26 +03:00
# ifdef CONFIG_PM_SLEEP
static int tsc2005_suspend ( struct device * dev )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:08:08 +03:00
struct spi_device * spi = to_spi_device ( dev ) ;
struct tsc2005 * ts = spi_get_drvdata ( spi ) ;
2011-03-17 08:07:36 +03:00
mutex_lock ( & ts - > mutex ) ;
2011-03-17 08:11:34 +03:00
2011-03-17 08:11:41 +03:00
if ( ! ts - > suspended & & ts - > opened )
2011-03-17 08:11:34 +03:00
__tsc2005_disable ( ts ) ;
ts - > suspended = true ;
2011-03-17 08:07:36 +03:00
mutex_unlock ( & ts - > mutex ) ;
return 0 ;
}
2011-03-17 08:08:26 +03:00
static int tsc2005_resume ( struct device * dev )
2011-03-17 08:07:36 +03:00
{
2011-03-17 08:08:08 +03:00
struct spi_device * spi = to_spi_device ( dev ) ;
struct tsc2005 * ts = spi_get_drvdata ( spi ) ;
2011-03-17 08:07:36 +03:00
mutex_lock ( & ts - > mutex ) ;
2011-03-17 08:11:34 +03:00
2011-03-17 08:11:41 +03:00
if ( ts - > suspended & & ts - > opened )
2011-03-17 08:11:34 +03:00
__tsc2005_enable ( ts ) ;
ts - > suspended = false ;
2011-03-17 08:07:36 +03:00
mutex_unlock ( & ts - > mutex ) ;
return 0 ;
}
# endif
2011-03-17 08:08:26 +03:00
static SIMPLE_DEV_PM_OPS ( tsc2005_pm_ops , tsc2005_suspend , tsc2005_resume ) ;
2011-03-17 08:07:36 +03:00
static struct spi_driver tsc2005_driver = {
2011-03-17 08:08:26 +03:00
. driver = {
. name = " tsc2005 " ,
. owner = THIS_MODULE ,
. pm = & tsc2005_pm_ops ,
2011-03-17 08:07:36 +03:00
} ,
2011-03-17 08:08:26 +03:00
. probe = tsc2005_probe ,
2012-11-24 09:27:39 +04:00
. remove = tsc2005_remove ,
2011-03-17 08:07:36 +03:00
} ;
2012-03-17 10:05:26 +04:00
module_spi_driver ( tsc2005_driver ) ;
2011-03-17 08:07:36 +03:00
MODULE_AUTHOR ( " Lauri Leukkunen <lauri.leukkunen@nokia.com> " ) ;
2011-03-17 08:09:03 +03:00
MODULE_DESCRIPTION ( " TSC2005 Touchscreen Driver " ) ;
2011-03-17 08:07:36 +03:00
MODULE_LICENSE ( " GPL " ) ;