2013-10-31 12:25:32 +04:00
/*
* Copyright ( C ) 2012 - 2013 MundoReader S . L .
* Author : Heiko Stuebner < heiko @ sntech . de >
*
* based in parts on Nook zforce driver
*
* Copyright ( C ) 2010 Barnes & Noble , Inc .
* Author : Pieter Truter < ptruter @ intrinsyc . com >
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* 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 .
*/
# include <linux/module.h>
# include <linux/hrtimer.h>
# include <linux/slab.h>
# include <linux/input.h>
# include <linux/interrupt.h>
# include <linux/i2c.h>
# include <linux/delay.h>
# include <linux/gpio.h>
# include <linux/device.h>
# include <linux/sysfs.h>
# include <linux/input/mt.h>
# include <linux/platform_data/zforce_ts.h>
# define WAIT_TIMEOUT msecs_to_jiffies(1000)
# define FRAME_START 0xee
/* Offsets of the different parts of the payload the controller sends */
# define PAYLOAD_HEADER 0
# define PAYLOAD_LENGTH 1
# define PAYLOAD_BODY 2
/* Response offsets */
# define RESPONSE_ID 0
# define RESPONSE_DATA 1
/* Commands */
# define COMMAND_DEACTIVATE 0x00
# define COMMAND_INITIALIZE 0x01
# define COMMAND_RESOLUTION 0x02
# define COMMAND_SETCONFIG 0x03
# define COMMAND_DATAREQUEST 0x04
# define COMMAND_SCANFREQ 0x08
# define COMMAND_STATUS 0X1e
/*
* Responses the controller sends as a result of
* command requests
*/
# define RESPONSE_DEACTIVATE 0x00
# define RESPONSE_INITIALIZE 0x01
# define RESPONSE_RESOLUTION 0x02
# define RESPONSE_SETCONFIG 0x03
# define RESPONSE_SCANFREQ 0x08
# define RESPONSE_STATUS 0X1e
/*
2014-01-28 00:27:06 +04:00
* Notifications are sent by the touch controller without
2013-10-31 12:25:32 +04:00
* being requested by the driver and include for example
* touch indications
*/
# define NOTIFICATION_TOUCH 0x04
# define NOTIFICATION_BOOTCOMPLETE 0x07
# define NOTIFICATION_OVERRUN 0x25
# define NOTIFICATION_PROXIMITY 0x26
# define NOTIFICATION_INVALID_COMMAND 0xfe
# define ZFORCE_REPORT_POINTS 2
# define ZFORCE_MAX_AREA 0xff
# define STATE_DOWN 0
# define STATE_MOVE 1
# define STATE_UP 2
# define SETCONFIG_DUALTOUCH (1 << 0)
struct zforce_point {
int coord_x ;
int coord_y ;
int state ;
int id ;
int area_major ;
int area_minor ;
int orientation ;
int pressure ;
int prblty ;
} ;
/*
* @ client the i2c_client
* @ input the input device
* @ suspending in the process of going to suspend ( don ' t emit wakeup
* events for commands executed to suspend the device )
* @ suspended device suspended
* @ access_mutex serialize i2c - access , to keep multipart reads together
* @ command_done completion to wait for the command result
2014-01-28 00:27:06 +04:00
* @ command_mutex serialize commands sent to the ic
* @ command_waiting the id of the command that is currently waiting
2013-10-31 12:25:32 +04:00
* for a result
* @ command_result returned result of the command
*/
struct zforce_ts {
struct i2c_client * client ;
struct input_dev * input ;
const struct zforce_ts_platdata * pdata ;
char phys [ 32 ] ;
bool suspending ;
bool suspended ;
bool boot_complete ;
/* Firmware version information */
u16 version_major ;
u16 version_minor ;
u16 version_build ;
u16 version_rev ;
struct mutex access_mutex ;
struct completion command_done ;
struct mutex command_mutex ;
int command_waiting ;
int command_result ;
} ;
static int zforce_command ( struct zforce_ts * ts , u8 cmd )
{
struct i2c_client * client = ts - > client ;
char buf [ 3 ] ;
int ret ;
dev_dbg ( & client - > dev , " %s: 0x%x \n " , __func__ , cmd ) ;
buf [ 0 ] = FRAME_START ;
buf [ 1 ] = 1 ; /* data size, command only */
buf [ 2 ] = cmd ;
mutex_lock ( & ts - > access_mutex ) ;
ret = i2c_master_send ( client , & buf [ 0 ] , ARRAY_SIZE ( buf ) ) ;
mutex_unlock ( & ts - > access_mutex ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " i2c send data request error: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
static int zforce_send_wait ( struct zforce_ts * ts , const char * buf , int len )
{
struct i2c_client * client = ts - > client ;
int ret ;
ret = mutex_trylock ( & ts - > command_mutex ) ;
if ( ! ret ) {
dev_err ( & client - > dev , " already waiting for a command \n " ) ;
return - EBUSY ;
}
dev_dbg ( & client - > dev , " sending %d bytes for command 0x%x \n " ,
buf [ 1 ] , buf [ 2 ] ) ;
ts - > command_waiting = buf [ 2 ] ;
mutex_lock ( & ts - > access_mutex ) ;
ret = i2c_master_send ( client , buf , len ) ;
mutex_unlock ( & ts - > access_mutex ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " i2c send data request error: %d \n " , ret ) ;
goto unlock ;
}
dev_dbg ( & client - > dev , " waiting for result for command 0x%x \n " , buf [ 2 ] ) ;
if ( wait_for_completion_timeout ( & ts - > command_done , WAIT_TIMEOUT ) = = 0 ) {
ret = - ETIME ;
goto unlock ;
}
ret = ts - > command_result ;
unlock :
mutex_unlock ( & ts - > command_mutex ) ;
return ret ;
}
static int zforce_command_wait ( struct zforce_ts * ts , u8 cmd )
{
struct i2c_client * client = ts - > client ;
char buf [ 3 ] ;
int ret ;
dev_dbg ( & client - > dev , " %s: 0x%x \n " , __func__ , cmd ) ;
buf [ 0 ] = FRAME_START ;
buf [ 1 ] = 1 ; /* data size, command only */
buf [ 2 ] = cmd ;
ret = zforce_send_wait ( ts , & buf [ 0 ] , ARRAY_SIZE ( buf ) ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " i2c send data request error: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
static int zforce_resolution ( struct zforce_ts * ts , u16 x , u16 y )
{
struct i2c_client * client = ts - > client ;
char buf [ 7 ] = { FRAME_START , 5 , COMMAND_RESOLUTION ,
( x & 0xff ) , ( ( x > > 8 ) & 0xff ) ,
( y & 0xff ) , ( ( y > > 8 ) & 0xff ) } ;
dev_dbg ( & client - > dev , " set resolution to (%d,%d) \n " , x , y ) ;
return zforce_send_wait ( ts , & buf [ 0 ] , ARRAY_SIZE ( buf ) ) ;
}
static int zforce_scan_frequency ( struct zforce_ts * ts , u16 idle , u16 finger ,
u16 stylus )
{
struct i2c_client * client = ts - > client ;
char buf [ 9 ] = { FRAME_START , 7 , COMMAND_SCANFREQ ,
( idle & 0xff ) , ( ( idle > > 8 ) & 0xff ) ,
( finger & 0xff ) , ( ( finger > > 8 ) & 0xff ) ,
( stylus & 0xff ) , ( ( stylus > > 8 ) & 0xff ) } ;
dev_dbg ( & client - > dev , " set scan frequency to (idle: %d, finger: %d, stylus: %d) \n " ,
idle , finger , stylus ) ;
return zforce_send_wait ( ts , & buf [ 0 ] , ARRAY_SIZE ( buf ) ) ;
}
static int zforce_setconfig ( struct zforce_ts * ts , char b1 )
{
struct i2c_client * client = ts - > client ;
char buf [ 7 ] = { FRAME_START , 5 , COMMAND_SETCONFIG ,
b1 , 0 , 0 , 0 } ;
dev_dbg ( & client - > dev , " set config to (%d) \n " , b1 ) ;
return zforce_send_wait ( ts , & buf [ 0 ] , ARRAY_SIZE ( buf ) ) ;
}
static int zforce_start ( struct zforce_ts * ts )
{
struct i2c_client * client = ts - > client ;
const struct zforce_ts_platdata * pdata = dev_get_platdata ( & client - > dev ) ;
int ret ;
dev_dbg ( & client - > dev , " starting device \n " ) ;
ret = zforce_command_wait ( ts , COMMAND_INITIALIZE ) ;
if ( ret ) {
dev_err ( & client - > dev , " Unable to initialize, %d \n " , ret ) ;
return ret ;
}
ret = zforce_resolution ( ts , pdata - > x_max , pdata - > y_max ) ;
if ( ret ) {
dev_err ( & client - > dev , " Unable to set resolution, %d \n " , ret ) ;
goto error ;
}
ret = zforce_scan_frequency ( ts , 10 , 50 , 50 ) ;
if ( ret ) {
dev_err ( & client - > dev , " Unable to set scan frequency, %d \n " ,
ret ) ;
goto error ;
}
2013-12-17 20:58:18 +04:00
ret = zforce_setconfig ( ts , SETCONFIG_DUALTOUCH ) ;
if ( ret ) {
2013-10-31 12:25:32 +04:00
dev_err ( & client - > dev , " Unable to set config \n " ) ;
goto error ;
}
/* start sending touch events */
ret = zforce_command ( ts , COMMAND_DATAREQUEST ) ;
if ( ret ) {
dev_err ( & client - > dev , " Unable to request data \n " ) ;
goto error ;
}
/*
* Per NN , initial cal . take max . of 200 msec .
* Allow time to complete this calibration
*/
msleep ( 200 ) ;
return 0 ;
error :
zforce_command_wait ( ts , COMMAND_DEACTIVATE ) ;
return ret ;
}
static int zforce_stop ( struct zforce_ts * ts )
{
struct i2c_client * client = ts - > client ;
int ret ;
dev_dbg ( & client - > dev , " stopping device \n " ) ;
/* Deactivates touch sensing and puts the device into sleep. */
ret = zforce_command_wait ( ts , COMMAND_DEACTIVATE ) ;
if ( ret ! = 0 ) {
dev_err ( & client - > dev , " could not deactivate device, %d \n " ,
ret ) ;
return ret ;
}
return 0 ;
}
static int zforce_touch_event ( struct zforce_ts * ts , u8 * payload )
{
struct i2c_client * client = ts - > client ;
const struct zforce_ts_platdata * pdata = dev_get_platdata ( & client - > dev ) ;
struct zforce_point point ;
int count , i , num = 0 ;
count = payload [ 0 ] ;
if ( count > ZFORCE_REPORT_POINTS ) {
2014-01-28 00:27:06 +04:00
dev_warn ( & client - > dev , " too many coordinates %d, expected max %d \n " ,
2013-10-31 12:25:32 +04:00
count , ZFORCE_REPORT_POINTS ) ;
count = ZFORCE_REPORT_POINTS ;
}
for ( i = 0 ; i < count ; i + + ) {
point . coord_x =
payload [ 9 * i + 2 ] < < 8 | payload [ 9 * i + 1 ] ;
point . coord_y =
payload [ 9 * i + 4 ] < < 8 | payload [ 9 * i + 3 ] ;
if ( point . coord_x > pdata - > x_max | |
point . coord_y > pdata - > y_max ) {
dev_warn ( & client - > dev , " coordinates (%d,%d) invalid \n " ,
point . coord_x , point . coord_y ) ;
point . coord_x = point . coord_y = 0 ;
}
point . state = payload [ 9 * i + 5 ] & 0x03 ;
point . id = ( payload [ 9 * i + 5 ] & 0xfc ) > > 2 ;
/* determine touch major, minor and orientation */
point . area_major = max ( payload [ 9 * i + 6 ] ,
payload [ 9 * i + 7 ] ) ;
point . area_minor = min ( payload [ 9 * i + 6 ] ,
payload [ 9 * i + 7 ] ) ;
point . orientation = payload [ 9 * i + 6 ] > payload [ 9 * i + 7 ] ;
point . pressure = payload [ 9 * i + 8 ] ;
point . prblty = payload [ 9 * i + 9 ] ;
dev_dbg ( & client - > dev ,
" point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d \n " ,
i , count , point . state , point . id ,
point . pressure , point . prblty ,
point . coord_x , point . coord_y ,
point . area_major , point . area_minor ,
point . orientation ) ;
/* the zforce id starts with "1", so needs to be decreased */
input_mt_slot ( ts - > input , point . id - 1 ) ;
input_mt_report_slot_state ( ts - > input , MT_TOOL_FINGER ,
point . state ! = STATE_UP ) ;
if ( point . state ! = STATE_UP ) {
input_report_abs ( ts - > input , ABS_MT_POSITION_X ,
point . coord_x ) ;
input_report_abs ( ts - > input , ABS_MT_POSITION_Y ,
point . coord_y ) ;
input_report_abs ( ts - > input , ABS_MT_TOUCH_MAJOR ,
point . area_major ) ;
input_report_abs ( ts - > input , ABS_MT_TOUCH_MINOR ,
point . area_minor ) ;
input_report_abs ( ts - > input , ABS_MT_ORIENTATION ,
point . orientation ) ;
num + + ;
}
}
input_mt_sync_frame ( ts - > input ) ;
input_mt_report_finger_count ( ts - > input , num ) ;
input_sync ( ts - > input ) ;
return 0 ;
}
static int zforce_read_packet ( struct zforce_ts * ts , u8 * buf )
{
struct i2c_client * client = ts - > client ;
int ret ;
mutex_lock ( & ts - > access_mutex ) ;
/* read 2 byte message header */
ret = i2c_master_recv ( client , buf , 2 ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " error reading header: %d \n " , ret ) ;
goto unlock ;
}
if ( buf [ PAYLOAD_HEADER ] ! = FRAME_START ) {
dev_err ( & client - > dev , " invalid frame start: %d \n " , buf [ 0 ] ) ;
ret = - EIO ;
goto unlock ;
}
if ( buf [ PAYLOAD_LENGTH ] < = 0 | | buf [ PAYLOAD_LENGTH ] > 255 ) {
dev_err ( & client - > dev , " invalid payload length: %d \n " ,
buf [ PAYLOAD_LENGTH ] ) ;
ret = - EIO ;
goto unlock ;
}
/* read the message */
ret = i2c_master_recv ( client , & buf [ PAYLOAD_BODY ] , buf [ PAYLOAD_LENGTH ] ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " error reading payload: %d \n " , ret ) ;
goto unlock ;
}
dev_dbg ( & client - > dev , " read %d bytes for response command 0x%x \n " ,
buf [ PAYLOAD_LENGTH ] , buf [ PAYLOAD_BODY ] ) ;
unlock :
mutex_unlock ( & ts - > access_mutex ) ;
return ret ;
}
static void zforce_complete ( struct zforce_ts * ts , int cmd , int result )
{
struct i2c_client * client = ts - > client ;
if ( ts - > command_waiting = = cmd ) {
dev_dbg ( & client - > dev , " completing command 0x%x \n " , cmd ) ;
ts - > command_result = result ;
complete ( & ts - > command_done ) ;
} else {
dev_dbg ( & client - > dev , " command %d not for us \n " , cmd ) ;
}
}
static irqreturn_t zforce_interrupt ( int irq , void * dev_id )
{
struct zforce_ts * ts = dev_id ;
struct i2c_client * client = ts - > client ;
const struct zforce_ts_platdata * pdata = dev_get_platdata ( & client - > dev ) ;
int ret ;
u8 payload_buffer [ 512 ] ;
u8 * payload ;
/*
* When suspended , emit a wakeup signal if necessary and return .
* Due to the level - interrupt we will get re - triggered later .
*/
if ( ts - > suspended ) {
if ( device_may_wakeup ( & client - > dev ) )
pm_wakeup_event ( & client - > dev , 500 ) ;
msleep ( 20 ) ;
return IRQ_HANDLED ;
}
dev_dbg ( & client - > dev , " handling interrupt \n " ) ;
/* Don't emit wakeup events from commands run by zforce_suspend */
if ( ! ts - > suspending & & device_may_wakeup ( & client - > dev ) )
pm_stay_awake ( & client - > dev ) ;
while ( ! gpio_get_value ( pdata - > gpio_int ) ) {
ret = zforce_read_packet ( ts , payload_buffer ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " could not read packet, ret: %d \n " ,
ret ) ;
break ;
}
payload = & payload_buffer [ PAYLOAD_BODY ] ;
switch ( payload [ RESPONSE_ID ] ) {
case NOTIFICATION_TOUCH :
/*
* Always report touch - events received while
* suspending , when being a wakeup source
*/
if ( ts - > suspending & & device_may_wakeup ( & client - > dev ) )
pm_wakeup_event ( & client - > dev , 500 ) ;
zforce_touch_event ( ts , & payload [ RESPONSE_DATA ] ) ;
break ;
case NOTIFICATION_BOOTCOMPLETE :
ts - > boot_complete = payload [ RESPONSE_DATA ] ;
zforce_complete ( ts , payload [ RESPONSE_ID ] , 0 ) ;
break ;
case RESPONSE_INITIALIZE :
case RESPONSE_DEACTIVATE :
case RESPONSE_SETCONFIG :
case RESPONSE_RESOLUTION :
case RESPONSE_SCANFREQ :
zforce_complete ( ts , payload [ RESPONSE_ID ] ,
payload [ RESPONSE_DATA ] ) ;
break ;
case RESPONSE_STATUS :
/*
* Version Payload Results
* [ 2 : major ] [ 2 : minor ] [ 2 : build ] [ 2 : rev ]
*/
ts - > version_major = ( payload [ RESPONSE_DATA + 1 ] < < 8 ) |
payload [ RESPONSE_DATA ] ;
ts - > version_minor = ( payload [ RESPONSE_DATA + 3 ] < < 8 ) |
payload [ RESPONSE_DATA + 2 ] ;
ts - > version_build = ( payload [ RESPONSE_DATA + 5 ] < < 8 ) |
payload [ RESPONSE_DATA + 4 ] ;
ts - > version_rev = ( payload [ RESPONSE_DATA + 7 ] < < 8 ) |
payload [ RESPONSE_DATA + 6 ] ;
dev_dbg ( & ts - > client - > dev , " Firmware Version %04x:%04x %04x:%04x \n " ,
ts - > version_major , ts - > version_minor ,
ts - > version_build , ts - > version_rev ) ;
zforce_complete ( ts , payload [ RESPONSE_ID ] , 0 ) ;
break ;
case NOTIFICATION_INVALID_COMMAND :
dev_err ( & ts - > client - > dev , " invalid command: 0x%x \n " ,
payload [ RESPONSE_DATA ] ) ;
break ;
default :
dev_err ( & ts - > client - > dev , " unrecognized response id: 0x%x \n " ,
payload [ RESPONSE_ID ] ) ;
break ;
}
}
if ( ! ts - > suspending & & device_may_wakeup ( & client - > dev ) )
pm_relax ( & client - > dev ) ;
dev_dbg ( & client - > dev , " finished interrupt \n " ) ;
return IRQ_HANDLED ;
}
static int zforce_input_open ( struct input_dev * dev )
{
struct zforce_ts * ts = input_get_drvdata ( dev ) ;
int ret ;
ret = zforce_start ( ts ) ;
if ( ret )
return ret ;
return 0 ;
}
static void zforce_input_close ( struct input_dev * dev )
{
struct zforce_ts * ts = input_get_drvdata ( dev ) ;
struct i2c_client * client = ts - > client ;
int ret ;
ret = zforce_stop ( ts ) ;
if ( ret )
dev_warn ( & client - > dev , " stopping zforce failed \n " ) ;
return ;
}
# ifdef CONFIG_PM_SLEEP
static int zforce_suspend ( struct device * dev )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct zforce_ts * ts = i2c_get_clientdata ( client ) ;
struct input_dev * input = ts - > input ;
int ret = 0 ;
mutex_lock ( & input - > mutex ) ;
ts - > suspending = true ;
/*
* When configured as a wakeup source device should always wake
* the system , therefore start device if necessary .
*/
if ( device_may_wakeup ( & client - > dev ) ) {
dev_dbg ( & client - > dev , " suspend while being a wakeup source \n " ) ;
/* Need to start device, if not open, to be a wakeup source. */
if ( ! input - > users ) {
ret = zforce_start ( ts ) ;
if ( ret )
goto unlock ;
}
enable_irq_wake ( client - > irq ) ;
} else if ( input - > users ) {
dev_dbg ( & client - > dev , " suspend without being a wakeup source \n " ) ;
ret = zforce_stop ( ts ) ;
if ( ret )
goto unlock ;
disable_irq ( client - > irq ) ;
}
ts - > suspended = true ;
unlock :
ts - > suspending = false ;
mutex_unlock ( & input - > mutex ) ;
return ret ;
}
static int zforce_resume ( struct device * dev )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct zforce_ts * ts = i2c_get_clientdata ( client ) ;
struct input_dev * input = ts - > input ;
int ret = 0 ;
mutex_lock ( & input - > mutex ) ;
ts - > suspended = false ;
if ( device_may_wakeup ( & client - > dev ) ) {
dev_dbg ( & client - > dev , " resume from being a wakeup source \n " ) ;
disable_irq_wake ( client - > irq ) ;
/* need to stop device if it was not open on suspend */
if ( ! input - > users ) {
ret = zforce_stop ( ts ) ;
if ( ret )
goto unlock ;
}
} else if ( input - > users ) {
dev_dbg ( & client - > dev , " resume without being a wakeup source \n " ) ;
enable_irq ( client - > irq ) ;
ret = zforce_start ( ts ) ;
if ( ret < 0 )
goto unlock ;
}
unlock :
mutex_unlock ( & input - > mutex ) ;
return ret ;
}
# endif
static SIMPLE_DEV_PM_OPS ( zforce_pm_ops , zforce_suspend , zforce_resume ) ;
static void zforce_reset ( void * data )
{
struct zforce_ts * ts = data ;
gpio_set_value ( ts - > pdata - > gpio_rst , 0 ) ;
}
static int zforce_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
const struct zforce_ts_platdata * pdata = dev_get_platdata ( & client - > dev ) ;
struct zforce_ts * ts ;
struct input_dev * input_dev ;
int ret ;
if ( ! pdata )
return - EINVAL ;
ts = devm_kzalloc ( & client - > dev , sizeof ( struct zforce_ts ) , GFP_KERNEL ) ;
if ( ! ts )
return - ENOMEM ;
ret = devm_gpio_request_one ( & client - > dev , pdata - > gpio_int , GPIOF_IN ,
" zforce_ts_int " ) ;
if ( ret ) {
dev_err ( & client - > dev , " request of gpio %d failed, %d \n " ,
pdata - > gpio_int , ret ) ;
return ret ;
}
ret = devm_gpio_request_one ( & client - > dev , pdata - > gpio_rst ,
GPIOF_OUT_INIT_LOW , " zforce_ts_rst " ) ;
if ( ret ) {
dev_err ( & client - > dev , " request of gpio %d failed, %d \n " ,
pdata - > gpio_rst , ret ) ;
return ret ;
}
ret = devm_add_action ( & client - > dev , zforce_reset , ts ) ;
if ( ret ) {
dev_err ( & client - > dev , " failed to register reset action, %d \n " ,
ret ) ;
return ret ;
}
snprintf ( ts - > phys , sizeof ( ts - > phys ) ,
" %s/input0 " , dev_name ( & client - > dev ) ) ;
input_dev = devm_input_allocate_device ( & client - > dev ) ;
if ( ! input_dev ) {
dev_err ( & client - > dev , " could not allocate input device \n " ) ;
return - ENOMEM ;
}
mutex_init ( & ts - > access_mutex ) ;
mutex_init ( & ts - > command_mutex ) ;
ts - > pdata = pdata ;
ts - > client = client ;
ts - > input = input_dev ;
input_dev - > name = " Neonode zForce touchscreen " ;
input_dev - > phys = ts - > phys ;
input_dev - > id . bustype = BUS_I2C ;
input_dev - > open = zforce_input_open ;
input_dev - > close = zforce_input_close ;
__set_bit ( EV_KEY , input_dev - > evbit ) ;
__set_bit ( EV_SYN , input_dev - > evbit ) ;
__set_bit ( EV_ABS , input_dev - > evbit ) ;
/* For multi touch */
input_set_abs_params ( input_dev , ABS_MT_POSITION_X , 0 ,
pdata - > x_max , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_MT_POSITION_Y , 0 ,
pdata - > y_max , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_MT_TOUCH_MAJOR , 0 ,
ZFORCE_MAX_AREA , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_MT_TOUCH_MINOR , 0 ,
ZFORCE_MAX_AREA , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_MT_ORIENTATION , 0 , 1 , 0 , 0 ) ;
input_mt_init_slots ( input_dev , ZFORCE_REPORT_POINTS , INPUT_MT_DIRECT ) ;
input_set_drvdata ( ts - > input , ts ) ;
init_completion ( & ts - > command_done ) ;
/*
* The zforce pulls the interrupt low when it has data ready .
* After it is triggered the isr thread runs until all the available
* packets have been read and the interrupt is high again .
* Therefore we can trigger the interrupt anytime it is low and do
* not need to limit it to the interrupt edge .
*/
ret = devm_request_threaded_irq ( & client - > dev , client - > irq , NULL ,
zforce_interrupt ,
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
input_dev - > name , ts ) ;
if ( ret ) {
dev_err ( & client - > dev , " irq %d request failed \n " , client - > irq ) ;
return ret ;
}
i2c_set_clientdata ( client , ts ) ;
/* let the controller boot */
gpio_set_value ( pdata - > gpio_rst , 1 ) ;
ts - > command_waiting = NOTIFICATION_BOOTCOMPLETE ;
if ( wait_for_completion_timeout ( & ts - > command_done , WAIT_TIMEOUT ) = = 0 )
dev_warn ( & client - > dev , " bootcomplete timed out \n " ) ;
/* need to start device to get version information */
ret = zforce_command_wait ( ts , COMMAND_INITIALIZE ) ;
if ( ret ) {
dev_err ( & client - > dev , " unable to initialize, %d \n " , ret ) ;
return ret ;
}
2014-01-28 00:27:06 +04:00
/* this gets the firmware version among other information */
2013-10-31 12:25:32 +04:00
ret = zforce_command_wait ( ts , COMMAND_STATUS ) ;
if ( ret < 0 ) {
dev_err ( & client - > dev , " couldn't get status, %d \n " , ret ) ;
zforce_stop ( ts ) ;
return ret ;
}
/* stop device and put it into sleep until it is opened */
ret = zforce_stop ( ts ) ;
if ( ret < 0 )
return ret ;
device_set_wakeup_capable ( & client - > dev , true ) ;
ret = input_register_device ( input_dev ) ;
if ( ret ) {
dev_err ( & client - > dev , " could not register input device, %d \n " ,
ret ) ;
return ret ;
}
return 0 ;
}
static struct i2c_device_id zforce_idtable [ ] = {
{ " zforce-ts " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , zforce_idtable ) ;
static struct i2c_driver zforce_driver = {
. driver = {
. owner = THIS_MODULE ,
. name = " zforce-ts " ,
. pm = & zforce_pm_ops ,
} ,
. probe = zforce_probe ,
. id_table = zforce_idtable ,
} ;
module_i2c_driver ( zforce_driver ) ;
MODULE_AUTHOR ( " Heiko Stuebner <heiko@sntech.de> " ) ;
MODULE_DESCRIPTION ( " zForce TouchScreen Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;