2010-07-15 08:55:30 +04:00
/*
2011-02-03 10:21:58 +03:00
* Atmel maXTouch Touchscreen driver
2010-07-15 08:55:30 +04:00
*
* Copyright ( C ) 2010 Samsung Electronics Co . Ltd
* Author : Joonyoung Shim < jy0922 . shim @ samsung . 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 .
*
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/firmware.h>
# include <linux/i2c.h>
2011-02-03 10:21:58 +03:00
# include <linux/i2c/atmel_mxt_ts.h>
2011-04-13 10:18:59 +04:00
# include <linux/input/mt.h>
2010-07-15 08:55:30 +04:00
# include <linux/interrupt.h>
# include <linux/slab.h>
/* Version */
2011-02-03 10:21:58 +03:00
# define MXT_VER_20 20
# define MXT_VER_21 21
# define MXT_VER_22 22
2010-07-15 08:55:30 +04:00
/* Slave addresses */
2011-02-03 10:21:58 +03:00
# define MXT_APP_LOW 0x4a
# define MXT_APP_HIGH 0x4b
# define MXT_BOOT_LOW 0x24
# define MXT_BOOT_HIGH 0x25
2010-07-15 08:55:30 +04:00
/* Firmware */
2011-02-03 10:21:58 +03:00
# define MXT_FW_NAME "maxtouch.fw"
2010-07-15 08:55:30 +04:00
/* Registers */
2011-02-03 10:21:58 +03:00
# define MXT_FAMILY_ID 0x00
# define MXT_VARIANT_ID 0x01
# define MXT_VERSION 0x02
# define MXT_BUILD 0x03
# define MXT_MATRIX_X_SIZE 0x04
# define MXT_MATRIX_Y_SIZE 0x05
# define MXT_OBJECT_NUM 0x06
# define MXT_OBJECT_START 0x07
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
# define MXT_OBJECT_SIZE 6
2010-07-15 08:55:30 +04:00
/* Object types */
2011-07-04 14:08:25 +04:00
# define MXT_DEBUG_DIAGNOSTIC_T37 37
# define MXT_GEN_MESSAGE_T5 5
# define MXT_GEN_COMMAND_T6 6
# define MXT_GEN_POWER_T7 7
# define MXT_GEN_ACQUIRE_T8 8
# define MXT_GEN_DATASOURCE_T53 53
# define MXT_TOUCH_MULTI_T9 9
# define MXT_TOUCH_KEYARRAY_T15 15
# define MXT_TOUCH_PROXIMITY_T23 23
# define MXT_TOUCH_PROXKEY_T52 52
# define MXT_PROCI_GRIPFACE_T20 20
# define MXT_PROCG_NOISE_T22 22
# define MXT_PROCI_ONETOUCH_T24 24
# define MXT_PROCI_TWOTOUCH_T27 27
# define MXT_PROCI_GRIP_T40 40
# define MXT_PROCI_PALM_T41 41
# define MXT_PROCI_TOUCHSUPPRESSION_T42 42
# define MXT_PROCI_STYLUS_T47 47
# define MXT_PROCG_NOISESUPPRESSION_T48 48
# define MXT_SPT_COMMSCONFIG_T18 18
# define MXT_SPT_GPIOPWM_T19 19
# define MXT_SPT_SELFTEST_T25 25
# define MXT_SPT_CTECONFIG_T28 28
# define MXT_SPT_USERDATA_T38 38
# define MXT_SPT_DIGITIZER_T43 43
# define MXT_SPT_MESSAGECOUNT_T44 44
# define MXT_SPT_CTECONFIG_T46 46
/* MXT_GEN_COMMAND_T6 field */
2011-02-03 10:21:58 +03:00
# define MXT_COMMAND_RESET 0
# define MXT_COMMAND_BACKUPNV 1
# define MXT_COMMAND_CALIBRATE 2
# define MXT_COMMAND_REPORTALL 3
# define MXT_COMMAND_DIAGNOSTIC 5
2011-07-04 14:08:25 +04:00
/* MXT_GEN_POWER_T7 field */
2011-02-03 10:21:58 +03:00
# define MXT_POWER_IDLEACQINT 0
# define MXT_POWER_ACTVACQINT 1
# define MXT_POWER_ACTV2IDLETO 2
2011-07-04 14:08:25 +04:00
/* MXT_GEN_ACQUIRE_T8 field */
2011-02-03 10:21:58 +03:00
# define MXT_ACQUIRE_CHRGTIME 0
# define MXT_ACQUIRE_TCHDRIFT 2
# define MXT_ACQUIRE_DRIFTST 3
# define MXT_ACQUIRE_TCHAUTOCAL 4
# define MXT_ACQUIRE_SYNC 5
# define MXT_ACQUIRE_ATCHCALST 6
# define MXT_ACQUIRE_ATCHCALSTHR 7
2011-07-04 14:08:25 +04:00
/* MXT_TOUCH_MULTI_T9 field */
2011-02-03 10:21:58 +03:00
# define MXT_TOUCH_CTRL 0
# define MXT_TOUCH_XORIGIN 1
# define MXT_TOUCH_YORIGIN 2
# define MXT_TOUCH_XSIZE 3
# define MXT_TOUCH_YSIZE 4
# define MXT_TOUCH_BLEN 6
# define MXT_TOUCH_TCHTHR 7
# define MXT_TOUCH_TCHDI 8
# define MXT_TOUCH_ORIENT 9
# define MXT_TOUCH_MOVHYSTI 11
# define MXT_TOUCH_MOVHYSTN 12
# define MXT_TOUCH_NUMTOUCH 14
# define MXT_TOUCH_MRGHYST 15
# define MXT_TOUCH_MRGTHR 16
# define MXT_TOUCH_AMPHYST 17
# define MXT_TOUCH_XRANGE_LSB 18
# define MXT_TOUCH_XRANGE_MSB 19
# define MXT_TOUCH_YRANGE_LSB 20
# define MXT_TOUCH_YRANGE_MSB 21
# define MXT_TOUCH_XLOCLIP 22
# define MXT_TOUCH_XHICLIP 23
# define MXT_TOUCH_YLOCLIP 24
# define MXT_TOUCH_YHICLIP 25
# define MXT_TOUCH_XEDGECTRL 26
# define MXT_TOUCH_XEDGEDIST 27
# define MXT_TOUCH_YEDGECTRL 28
# define MXT_TOUCH_YEDGEDIST 29
2011-03-15 07:41:34 +03:00
# define MXT_TOUCH_JUMPLIMIT 30
2011-02-03 10:21:58 +03:00
2011-07-04 14:08:25 +04:00
/* MXT_PROCI_GRIPFACE_T20 field */
2011-02-03 10:21:58 +03:00
# define MXT_GRIPFACE_CTRL 0
# define MXT_GRIPFACE_XLOGRIP 1
# define MXT_GRIPFACE_XHIGRIP 2
# define MXT_GRIPFACE_YLOGRIP 3
# define MXT_GRIPFACE_YHIGRIP 4
# define MXT_GRIPFACE_MAXTCHS 5
# define MXT_GRIPFACE_SZTHR1 7
# define MXT_GRIPFACE_SZTHR2 8
# define MXT_GRIPFACE_SHPTHR1 9
# define MXT_GRIPFACE_SHPTHR2 10
# define MXT_GRIPFACE_SUPEXTTO 11
/* MXT_PROCI_NOISE field */
# define MXT_NOISE_CTRL 0
# define MXT_NOISE_OUTFLEN 1
# define MXT_NOISE_GCAFUL_LSB 3
# define MXT_NOISE_GCAFUL_MSB 4
# define MXT_NOISE_GCAFLL_LSB 5
# define MXT_NOISE_GCAFLL_MSB 6
# define MXT_NOISE_ACTVGCAFVALID 7
# define MXT_NOISE_NOISETHR 8
# define MXT_NOISE_FREQHOPSCALE 10
# define MXT_NOISE_FREQ0 11
# define MXT_NOISE_FREQ1 12
# define MXT_NOISE_FREQ2 13
# define MXT_NOISE_FREQ3 14
# define MXT_NOISE_FREQ4 15
# define MXT_NOISE_IDLEGCAFVALID 16
2011-07-04 14:08:25 +04:00
/* MXT_SPT_COMMSCONFIG_T18 */
2011-02-03 10:21:58 +03:00
# define MXT_COMMS_CTRL 0
# define MXT_COMMS_CMD 1
2011-07-04 14:08:25 +04:00
/* MXT_SPT_CTECONFIG_T28 field */
2011-02-03 10:21:58 +03:00
# define MXT_CTE_CTRL 0
# define MXT_CTE_CMD 1
# define MXT_CTE_MODE 2
# define MXT_CTE_IDLEGCAFDEPTH 3
# define MXT_CTE_ACTVGCAFDEPTH 4
2011-03-15 07:41:34 +03:00
# define MXT_CTE_VOLTAGE 5
2011-02-03 10:21:58 +03:00
# define MXT_VOLTAGE_DEFAULT 2700000
# define MXT_VOLTAGE_STEP 10000
2011-07-04 14:08:25 +04:00
/* Define for MXT_GEN_COMMAND_T6 */
2011-02-03 10:21:58 +03:00
# define MXT_BOOT_VALUE 0xa5
# define MXT_BACKUP_VALUE 0x55
# define MXT_BACKUP_TIME 25 /* msec */
# define MXT_RESET_TIME 65 /* msec */
# define MXT_FWRESET_TIME 175 /* msec */
2010-07-15 08:55:30 +04:00
/* Command to unlock bootloader */
2011-02-03 10:21:58 +03:00
# define MXT_UNLOCK_CMD_MSB 0xaa
# define MXT_UNLOCK_CMD_LSB 0xdc
2010-07-15 08:55:30 +04:00
/* Bootloader mode status */
2011-02-03 10:21:58 +03:00
# define MXT_WAITING_BOOTLOAD_CMD 0xc0 /* valid 7 6 bit only */
# define MXT_WAITING_FRAME_DATA 0x80 /* valid 7 6 bit only */
# define MXT_FRAME_CRC_CHECK 0x02
# define MXT_FRAME_CRC_FAIL 0x03
# define MXT_FRAME_CRC_PASS 0x04
# define MXT_APP_CRC_FAIL 0x40 /* valid 7 8 bit only */
# define MXT_BOOT_STATUS_MASK 0x3f
2010-07-15 08:55:30 +04:00
/* Touch status */
2011-02-03 10:21:58 +03:00
# define MXT_SUPPRESS (1 << 1)
# define MXT_AMP (1 << 2)
# define MXT_VECTOR (1 << 3)
# define MXT_MOVE (1 << 4)
# define MXT_RELEASE (1 << 5)
# define MXT_PRESS (1 << 6)
# define MXT_DETECT (1 << 7)
2010-07-15 08:55:30 +04:00
2011-04-13 10:14:38 +04:00
/* Touch orient bits */
# define MXT_XY_SWITCH (1 << 0)
# define MXT_X_INVERT (1 << 1)
# define MXT_Y_INVERT (1 << 2)
2010-07-15 08:55:30 +04:00
/* Touchscreen absolute values */
2011-02-03 10:21:58 +03:00
# define MXT_MAX_AREA 0xff
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
# define MXT_MAX_FINGER 10
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
struct mxt_info {
2010-07-15 08:55:30 +04:00
u8 family_id ;
u8 variant_id ;
u8 version ;
u8 build ;
u8 matrix_xsize ;
u8 matrix_ysize ;
u8 object_num ;
} ;
2011-02-03 10:21:58 +03:00
struct mxt_object {
2010-07-15 08:55:30 +04:00
u8 type ;
u16 start_address ;
u8 size ;
u8 instances ;
u8 num_report_ids ;
/* to map object and message */
u8 max_reportid ;
} ;
2011-02-03 10:21:58 +03:00
struct mxt_message {
2010-07-15 08:55:30 +04:00
u8 reportid ;
u8 message [ 7 ] ;
} ;
2011-02-03 10:21:58 +03:00
struct mxt_finger {
2010-07-15 08:55:30 +04:00
int status ;
int x ;
int y ;
int area ;
2011-08-16 11:40:54 +04:00
int pressure ;
2010-07-15 08:55:30 +04:00
} ;
/* Each client has this additional data */
2011-02-03 10:21:58 +03:00
struct mxt_data {
2010-07-15 08:55:30 +04:00
struct i2c_client * client ;
struct input_dev * input_dev ;
2011-02-03 10:21:58 +03:00
const struct mxt_platform_data * pdata ;
struct mxt_object * object_table ;
struct mxt_info info ;
struct mxt_finger finger [ MXT_MAX_FINGER ] ;
2010-07-15 08:55:30 +04:00
unsigned int irq ;
2011-04-13 10:14:38 +04:00
unsigned int max_x ;
unsigned int max_y ;
2010-07-15 08:55:30 +04:00
} ;
2011-02-03 10:21:58 +03:00
static bool mxt_object_readable ( unsigned int type )
2010-07-15 08:55:30 +04:00
{
switch ( type ) {
2011-07-04 14:08:25 +04:00
case MXT_GEN_MESSAGE_T5 :
case MXT_GEN_COMMAND_T6 :
case MXT_GEN_POWER_T7 :
case MXT_GEN_ACQUIRE_T8 :
case MXT_GEN_DATASOURCE_T53 :
case MXT_TOUCH_MULTI_T9 :
case MXT_TOUCH_KEYARRAY_T15 :
case MXT_TOUCH_PROXIMITY_T23 :
case MXT_TOUCH_PROXKEY_T52 :
case MXT_PROCI_GRIPFACE_T20 :
case MXT_PROCG_NOISE_T22 :
case MXT_PROCI_ONETOUCH_T24 :
case MXT_PROCI_TWOTOUCH_T27 :
case MXT_PROCI_GRIP_T40 :
case MXT_PROCI_PALM_T41 :
case MXT_PROCI_TOUCHSUPPRESSION_T42 :
case MXT_PROCI_STYLUS_T47 :
case MXT_PROCG_NOISESUPPRESSION_T48 :
case MXT_SPT_COMMSCONFIG_T18 :
case MXT_SPT_GPIOPWM_T19 :
case MXT_SPT_SELFTEST_T25 :
case MXT_SPT_CTECONFIG_T28 :
case MXT_SPT_USERDATA_T38 :
case MXT_SPT_DIGITIZER_T43 :
case MXT_SPT_CTECONFIG_T46 :
2010-07-15 08:55:30 +04:00
return true ;
default :
return false ;
}
}
2011-02-03 10:21:58 +03:00
static bool mxt_object_writable ( unsigned int type )
2010-07-15 08:55:30 +04:00
{
switch ( type ) {
2011-07-04 14:08:25 +04:00
case MXT_GEN_COMMAND_T6 :
case MXT_GEN_POWER_T7 :
case MXT_GEN_ACQUIRE_T8 :
case MXT_TOUCH_MULTI_T9 :
case MXT_TOUCH_KEYARRAY_T15 :
case MXT_TOUCH_PROXIMITY_T23 :
case MXT_TOUCH_PROXKEY_T52 :
case MXT_PROCI_GRIPFACE_T20 :
case MXT_PROCG_NOISE_T22 :
case MXT_PROCI_ONETOUCH_T24 :
case MXT_PROCI_TWOTOUCH_T27 :
case MXT_PROCI_GRIP_T40 :
case MXT_PROCI_PALM_T41 :
case MXT_PROCI_TOUCHSUPPRESSION_T42 :
case MXT_PROCI_STYLUS_T47 :
case MXT_PROCG_NOISESUPPRESSION_T48 :
case MXT_SPT_COMMSCONFIG_T18 :
case MXT_SPT_GPIOPWM_T19 :
case MXT_SPT_SELFTEST_T25 :
case MXT_SPT_CTECONFIG_T28 :
case MXT_SPT_DIGITIZER_T43 :
case MXT_SPT_CTECONFIG_T46 :
2010-07-15 08:55:30 +04:00
return true ;
default :
return false ;
}
}
2011-02-03 10:21:58 +03:00
static void mxt_dump_message ( struct device * dev ,
2012-05-09 09:40:29 +04:00
struct mxt_message * message )
2010-07-15 08:55:30 +04:00
{
2012-05-09 09:40:29 +04:00
dev_dbg ( dev , " reportid: %u \t message: %02x %02x %02x %02x %02x %02x %02x \n " ,
message - > reportid , message - > message [ 0 ] , message - > message [ 1 ] ,
message - > message [ 2 ] , message - > message [ 3 ] , message - > message [ 4 ] ,
message - > message [ 5 ] , message - > message [ 6 ] ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static int mxt_check_bootloader ( struct i2c_client * client ,
2010-07-15 08:55:30 +04:00
unsigned int state )
{
u8 val ;
recheck :
if ( i2c_master_recv ( client , & val , 1 ) ! = 1 ) {
dev_err ( & client - > dev , " %s: i2c recv failed \n " , __func__ ) ;
return - EIO ;
}
switch ( state ) {
2011-02-03 10:21:58 +03:00
case MXT_WAITING_BOOTLOAD_CMD :
case MXT_WAITING_FRAME_DATA :
val & = ~ MXT_BOOT_STATUS_MASK ;
2010-07-15 08:55:30 +04:00
break ;
2011-02-03 10:21:58 +03:00
case MXT_FRAME_CRC_PASS :
if ( val = = MXT_FRAME_CRC_CHECK )
2010-07-15 08:55:30 +04:00
goto recheck ;
break ;
default :
return - EINVAL ;
}
if ( val ! = state ) {
dev_err ( & client - > dev , " Unvalid bootloader mode state \n " ) ;
return - EINVAL ;
}
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int mxt_unlock_bootloader ( struct i2c_client * client )
2010-07-15 08:55:30 +04:00
{
u8 buf [ 2 ] ;
2011-02-03 10:21:58 +03:00
buf [ 0 ] = MXT_UNLOCK_CMD_LSB ;
buf [ 1 ] = MXT_UNLOCK_CMD_MSB ;
2010-07-15 08:55:30 +04:00
if ( i2c_master_send ( client , buf , 2 ) ! = 2 ) {
dev_err ( & client - > dev , " %s: i2c send failed \n " , __func__ ) ;
return - EIO ;
}
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int mxt_fw_write ( struct i2c_client * client ,
2010-07-15 08:55:30 +04:00
const u8 * data , unsigned int frame_size )
{
if ( i2c_master_send ( client , data , frame_size ) ! = frame_size ) {
dev_err ( & client - > dev , " %s: i2c send failed \n " , __func__ ) ;
return - EIO ;
}
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int __mxt_read_reg ( struct i2c_client * client ,
2010-07-15 08:55:30 +04:00
u16 reg , u16 len , void * val )
{
struct i2c_msg xfer [ 2 ] ;
u8 buf [ 2 ] ;
buf [ 0 ] = reg & 0xff ;
buf [ 1 ] = ( reg > > 8 ) & 0xff ;
/* Write register */
xfer [ 0 ] . addr = client - > addr ;
xfer [ 0 ] . flags = 0 ;
xfer [ 0 ] . len = 2 ;
xfer [ 0 ] . buf = buf ;
/* Read data */
xfer [ 1 ] . addr = client - > addr ;
xfer [ 1 ] . flags = I2C_M_RD ;
xfer [ 1 ] . len = len ;
xfer [ 1 ] . buf = val ;
if ( i2c_transfer ( client - > adapter , xfer , 2 ) ! = 2 ) {
dev_err ( & client - > dev , " %s: i2c transfer failed \n " , __func__ ) ;
return - EIO ;
}
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int mxt_read_reg ( struct i2c_client * client , u16 reg , u8 * val )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
return __mxt_read_reg ( client , reg , 1 , val ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static int mxt_write_reg ( struct i2c_client * client , u16 reg , u8 val )
2010-07-15 08:55:30 +04:00
{
u8 buf [ 3 ] ;
buf [ 0 ] = reg & 0xff ;
buf [ 1 ] = ( reg > > 8 ) & 0xff ;
buf [ 2 ] = val ;
if ( i2c_master_send ( client , buf , 3 ) ! = 3 ) {
dev_err ( & client - > dev , " %s: i2c send failed \n " , __func__ ) ;
return - EIO ;
}
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int mxt_read_object_table ( struct i2c_client * client ,
2010-07-15 08:55:30 +04:00
u16 reg , u8 * object_buf )
{
2011-02-03 10:21:58 +03:00
return __mxt_read_reg ( client , reg , MXT_OBJECT_SIZE ,
2010-07-15 08:55:30 +04:00
object_buf ) ;
}
2011-02-03 10:21:58 +03:00
static struct mxt_object *
mxt_get_object ( struct mxt_data * data , u8 type )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_object * object ;
2010-07-15 08:55:30 +04:00
int i ;
for ( i = 0 ; i < data - > info . object_num ; i + + ) {
object = data - > object_table + i ;
if ( object - > type = = type )
return object ;
}
dev_err ( & data - > client - > dev , " Invalid object type \n " ) ;
return NULL ;
}
2011-02-03 10:21:58 +03:00
static int mxt_read_message ( struct mxt_data * data ,
struct mxt_message * message )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_object * object ;
2010-07-15 08:55:30 +04:00
u16 reg ;
2011-07-04 14:08:25 +04:00
object = mxt_get_object ( data , MXT_GEN_MESSAGE_T5 ) ;
2010-07-15 08:55:30 +04:00
if ( ! object )
return - EINVAL ;
reg = object - > start_address ;
2011-02-03 10:21:58 +03:00
return __mxt_read_reg ( data - > client , reg ,
sizeof ( struct mxt_message ) , message ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static int mxt_read_object ( struct mxt_data * data ,
2010-07-15 08:55:30 +04:00
u8 type , u8 offset , u8 * val )
{
2011-02-03 10:21:58 +03:00
struct mxt_object * object ;
2010-07-15 08:55:30 +04:00
u16 reg ;
2011-02-03 10:21:58 +03:00
object = mxt_get_object ( data , type ) ;
2010-07-15 08:55:30 +04:00
if ( ! object )
return - EINVAL ;
reg = object - > start_address ;
2011-02-03 10:21:58 +03:00
return __mxt_read_reg ( data - > client , reg + offset , 1 , val ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static int mxt_write_object ( struct mxt_data * data ,
2010-07-15 08:55:30 +04:00
u8 type , u8 offset , u8 val )
{
2011-02-03 10:21:58 +03:00
struct mxt_object * object ;
2010-07-15 08:55:30 +04:00
u16 reg ;
2011-02-03 10:21:58 +03:00
object = mxt_get_object ( data , type ) ;
2012-05-09 09:38:52 +04:00
if ( ! object | | offset > = object - > size + 1 )
2010-07-15 08:55:30 +04:00
return - EINVAL ;
reg = object - > start_address ;
2011-02-03 10:21:58 +03:00
return mxt_write_reg ( data - > client , reg + offset , val ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static void mxt_input_report ( struct mxt_data * data , int single_id )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_finger * finger = data - > finger ;
2010-07-15 08:55:30 +04:00
struct input_dev * input_dev = data - > input_dev ;
int status = finger [ single_id ] . status ;
int finger_num = 0 ;
int id ;
2011-02-03 10:21:58 +03:00
for ( id = 0 ; id < MXT_MAX_FINGER ; id + + ) {
2010-07-15 08:55:30 +04:00
if ( ! finger [ id ] . status )
continue ;
2011-04-13 10:18:59 +04:00
input_mt_slot ( input_dev , id ) ;
input_mt_report_slot_state ( input_dev , MT_TOOL_FINGER ,
finger [ id ] . status ! = MXT_RELEASE ) ;
2010-07-15 08:55:30 +04:00
2011-04-13 10:18:59 +04:00
if ( finger [ id ] . status ! = MXT_RELEASE ) {
2010-07-15 08:55:30 +04:00
finger_num + + ;
2011-04-13 10:18:59 +04:00
input_report_abs ( input_dev , ABS_MT_TOUCH_MAJOR ,
finger [ id ] . area ) ;
input_report_abs ( input_dev , ABS_MT_POSITION_X ,
finger [ id ] . x ) ;
input_report_abs ( input_dev , ABS_MT_POSITION_Y ,
finger [ id ] . y ) ;
2011-08-16 11:40:54 +04:00
input_report_abs ( input_dev , ABS_MT_PRESSURE ,
finger [ id ] . pressure ) ;
2011-04-13 10:18:59 +04:00
} else {
finger [ id ] . status = 0 ;
}
2010-07-15 08:55:30 +04:00
}
input_report_key ( input_dev , BTN_TOUCH , finger_num > 0 ) ;
2011-02-03 10:21:58 +03:00
if ( status ! = MXT_RELEASE ) {
2010-07-15 08:55:30 +04:00
input_report_abs ( input_dev , ABS_X , finger [ single_id ] . x ) ;
input_report_abs ( input_dev , ABS_Y , finger [ single_id ] . y ) ;
2011-08-16 11:40:54 +04:00
input_report_abs ( input_dev ,
ABS_PRESSURE , finger [ single_id ] . pressure ) ;
2010-07-15 08:55:30 +04:00
}
input_sync ( input_dev ) ;
}
2011-02-03 10:21:58 +03:00
static void mxt_input_touchevent ( struct mxt_data * data ,
struct mxt_message * message , int id )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_finger * finger = data - > finger ;
2010-07-15 08:55:30 +04:00
struct device * dev = & data - > client - > dev ;
u8 status = message - > message [ 0 ] ;
int x ;
int y ;
int area ;
2011-08-16 11:40:54 +04:00
int pressure ;
2010-07-15 08:55:30 +04:00
/* Check the touch is present on the screen */
2011-02-03 10:21:58 +03:00
if ( ! ( status & MXT_DETECT ) ) {
if ( status & MXT_RELEASE ) {
2010-07-15 08:55:30 +04:00
dev_dbg ( dev , " [%d] released \n " , id ) ;
2011-02-03 10:21:58 +03:00
finger [ id ] . status = MXT_RELEASE ;
mxt_input_report ( data , id ) ;
2010-07-15 08:55:30 +04:00
}
return ;
}
/* Check only AMP detection */
2011-02-03 10:21:58 +03:00
if ( ! ( status & ( MXT_PRESS | MXT_MOVE ) ) )
2010-07-15 08:55:30 +04:00
return ;
2011-04-13 10:14:38 +04:00
x = ( message - > message [ 1 ] < < 4 ) | ( ( message - > message [ 3 ] > > 4 ) & 0xf ) ;
y = ( message - > message [ 2 ] < < 4 ) | ( ( message - > message [ 3 ] & 0xf ) ) ;
if ( data - > max_x < 1024 )
x = x > > 2 ;
if ( data - > max_y < 1024 )
y = y > > 2 ;
2010-07-15 08:55:30 +04:00
area = message - > message [ 4 ] ;
2011-08-16 11:40:54 +04:00
pressure = message - > message [ 5 ] ;
2010-07-15 08:55:30 +04:00
dev_dbg ( dev , " [%d] %s x: %d, y: %d, area: %d \n " , id ,
2011-02-03 10:21:58 +03:00
status & MXT_MOVE ? " moved " : " pressed " ,
2010-07-15 08:55:30 +04:00
x , y , area ) ;
2011-02-03 10:21:58 +03:00
finger [ id ] . status = status & MXT_MOVE ?
MXT_MOVE : MXT_PRESS ;
2010-07-15 08:55:30 +04:00
finger [ id ] . x = x ;
finger [ id ] . y = y ;
finger [ id ] . area = area ;
2011-08-16 11:40:54 +04:00
finger [ id ] . pressure = pressure ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
mxt_input_report ( data , id ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static irqreturn_t mxt_interrupt ( int irq , void * dev_id )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_data * data = dev_id ;
struct mxt_message message ;
struct mxt_object * object ;
2010-07-15 08:55:30 +04:00
struct device * dev = & data - > client - > dev ;
int id ;
u8 reportid ;
u8 max_reportid ;
u8 min_reportid ;
do {
2011-02-03 10:21:58 +03:00
if ( mxt_read_message ( data , & message ) ) {
2010-07-15 08:55:30 +04:00
dev_err ( dev , " Failed to read message \n " ) ;
goto end ;
}
reportid = message . reportid ;
2011-07-04 14:08:25 +04:00
/* whether reportid is thing of MXT_TOUCH_MULTI_T9 */
object = mxt_get_object ( data , MXT_TOUCH_MULTI_T9 ) ;
2010-07-15 08:55:30 +04:00
if ( ! object )
goto end ;
max_reportid = object - > max_reportid ;
min_reportid = max_reportid - object - > num_report_ids + 1 ;
id = reportid - min_reportid ;
if ( reportid > = min_reportid & & reportid < = max_reportid )
2011-02-03 10:21:58 +03:00
mxt_input_touchevent ( data , & message , id ) ;
2010-07-15 08:55:30 +04:00
else
2011-02-03 10:21:58 +03:00
mxt_dump_message ( dev , & message ) ;
2010-07-15 08:55:30 +04:00
} while ( reportid ! = 0xff ) ;
end :
return IRQ_HANDLED ;
}
2011-02-03 10:21:58 +03:00
static int mxt_check_reg_init ( struct mxt_data * data )
2010-07-15 08:55:30 +04:00
{
2011-02-16 00:36:52 +03:00
const struct mxt_platform_data * pdata = data - > pdata ;
2011-02-03 10:21:58 +03:00
struct mxt_object * object ;
2010-07-15 08:55:30 +04:00
struct device * dev = & data - > client - > dev ;
int index = 0 ;
2011-02-16 00:36:52 +03:00
int i , j , config_offset ;
2010-07-15 08:55:30 +04:00
2011-02-16 00:36:52 +03:00
if ( ! pdata - > config ) {
dev_dbg ( dev , " No cfg data defined, skipping reg init \n " ) ;
return 0 ;
2010-07-15 08:55:30 +04:00
}
for ( i = 0 ; i < data - > info . object_num ; i + + ) {
object = data - > object_table + i ;
2011-02-03 10:21:58 +03:00
if ( ! mxt_object_writable ( object - > type ) )
2010-07-15 08:55:30 +04:00
continue ;
2011-07-04 14:16:25 +04:00
for ( j = 0 ;
j < ( object - > size + 1 ) * ( object - > instances + 1 ) ;
j + + ) {
2011-02-16 00:36:52 +03:00
config_offset = index + j ;
if ( config_offset > pdata - > config_length ) {
dev_err ( dev , " Not enough config data! \n " ) ;
return - EINVAL ;
}
2011-02-03 10:21:58 +03:00
mxt_write_object ( data , object - > type , j ,
2011-02-16 00:36:52 +03:00
pdata - > config [ config_offset ] ) ;
}
2011-07-04 14:16:25 +04:00
index + = ( object - > size + 1 ) * ( object - > instances + 1 ) ;
2010-07-15 08:55:30 +04:00
}
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int mxt_make_highchg ( struct mxt_data * data )
2010-07-15 08:55:30 +04:00
{
struct device * dev = & data - > client - > dev ;
2011-02-04 11:51:05 +03:00
struct mxt_message message ;
2010-07-15 08:55:30 +04:00
int count = 10 ;
int error ;
/* Read dummy message to make high CHG pin */
do {
2011-02-04 11:51:05 +03:00
error = mxt_read_message ( data , & message ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
2011-02-04 11:51:05 +03:00
} while ( message . reportid ! = 0xff & & - - count ) ;
2010-07-15 08:55:30 +04:00
if ( ! count ) {
dev_err ( dev , " CHG pin isn't cleared \n " ) ;
return - EBUSY ;
}
return 0 ;
}
2011-02-03 10:21:58 +03:00
static void mxt_handle_pdata ( struct mxt_data * data )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
const struct mxt_platform_data * pdata = data - > pdata ;
2010-07-15 08:55:30 +04:00
u8 voltage ;
/* Set touchscreen lines */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 , MXT_TOUCH_XSIZE ,
2010-07-15 08:55:30 +04:00
pdata - > x_line ) ;
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 , MXT_TOUCH_YSIZE ,
2010-07-15 08:55:30 +04:00
pdata - > y_line ) ;
/* Set touchscreen orient */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 , MXT_TOUCH_ORIENT ,
2010-07-15 08:55:30 +04:00
pdata - > orient ) ;
/* Set touchscreen burst length */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 ,
2011-02-03 10:21:58 +03:00
MXT_TOUCH_BLEN , pdata - > blen ) ;
2010-07-15 08:55:30 +04:00
/* Set touchscreen threshold */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 ,
2011-02-03 10:21:58 +03:00
MXT_TOUCH_TCHTHR , pdata - > threshold ) ;
2010-07-15 08:55:30 +04:00
/* Set touchscreen resolution */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 ,
2011-02-03 10:21:58 +03:00
MXT_TOUCH_XRANGE_LSB , ( pdata - > x_size - 1 ) & 0xff ) ;
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 ,
2011-02-03 10:21:58 +03:00
MXT_TOUCH_XRANGE_MSB , ( pdata - > x_size - 1 ) > > 8 ) ;
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 ,
2011-02-03 10:21:58 +03:00
MXT_TOUCH_YRANGE_LSB , ( pdata - > y_size - 1 ) & 0xff ) ;
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_TOUCH_MULTI_T9 ,
2011-02-03 10:21:58 +03:00
MXT_TOUCH_YRANGE_MSB , ( pdata - > y_size - 1 ) > > 8 ) ;
2010-07-15 08:55:30 +04:00
/* Set touchscreen voltage */
2011-03-15 07:41:34 +03:00
if ( pdata - > voltage ) {
2011-02-03 10:21:58 +03:00
if ( pdata - > voltage < MXT_VOLTAGE_DEFAULT ) {
voltage = ( MXT_VOLTAGE_DEFAULT - pdata - > voltage ) /
MXT_VOLTAGE_STEP ;
2010-07-15 08:55:30 +04:00
voltage = 0xff - voltage + 1 ;
} else
2011-02-03 10:21:58 +03:00
voltage = ( pdata - > voltage - MXT_VOLTAGE_DEFAULT ) /
MXT_VOLTAGE_STEP ;
2010-07-15 08:55:30 +04:00
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_SPT_CTECONFIG_T28 ,
2011-02-03 10:21:58 +03:00
MXT_CTE_VOLTAGE , voltage ) ;
2010-07-15 08:55:30 +04:00
}
}
2011-02-03 10:21:58 +03:00
static int mxt_get_info ( struct mxt_data * data )
2010-07-15 08:55:30 +04:00
{
struct i2c_client * client = data - > client ;
2011-02-03 10:21:58 +03:00
struct mxt_info * info = & data - > info ;
2010-07-15 08:55:30 +04:00
int error ;
u8 val ;
2011-02-03 10:21:58 +03:00
error = mxt_read_reg ( client , MXT_FAMILY_ID , & val ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
info - > family_id = val ;
2011-02-03 10:21:58 +03:00
error = mxt_read_reg ( client , MXT_VARIANT_ID , & val ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
info - > variant_id = val ;
2011-02-03 10:21:58 +03:00
error = mxt_read_reg ( client , MXT_VERSION , & val ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
info - > version = val ;
2011-02-03 10:21:58 +03:00
error = mxt_read_reg ( client , MXT_BUILD , & val ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
info - > build = val ;
2011-02-03 10:21:58 +03:00
error = mxt_read_reg ( client , MXT_OBJECT_NUM , & val ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
info - > object_num = val ;
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int mxt_get_object_table ( struct mxt_data * data )
2010-07-15 08:55:30 +04:00
{
int error ;
int i ;
u16 reg ;
u8 reportid = 0 ;
2011-02-03 10:21:58 +03:00
u8 buf [ MXT_OBJECT_SIZE ] ;
2010-07-15 08:55:30 +04:00
for ( i = 0 ; i < data - > info . object_num ; i + + ) {
2011-02-03 10:21:58 +03:00
struct mxt_object * object = data - > object_table + i ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
reg = MXT_OBJECT_START + MXT_OBJECT_SIZE * i ;
error = mxt_read_object_table ( data - > client , reg , buf ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
object - > type = buf [ 0 ] ;
object - > start_address = ( buf [ 2 ] < < 8 ) | buf [ 1 ] ;
object - > size = buf [ 3 ] ;
object - > instances = buf [ 4 ] ;
object - > num_report_ids = buf [ 5 ] ;
if ( object - > num_report_ids ) {
reportid + = object - > num_report_ids *
( object - > instances + 1 ) ;
object - > max_reportid = reportid ;
}
}
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int mxt_initialize ( struct mxt_data * data )
2010-07-15 08:55:30 +04:00
{
struct i2c_client * client = data - > client ;
2011-02-03 10:21:58 +03:00
struct mxt_info * info = & data - > info ;
2010-07-15 08:55:30 +04:00
int error ;
u8 val ;
2011-02-03 10:21:58 +03:00
error = mxt_get_info ( data ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
data - > object_table = kcalloc ( info - > object_num ,
2011-02-03 10:21:58 +03:00
sizeof ( struct mxt_object ) ,
2010-07-15 08:55:30 +04:00
GFP_KERNEL ) ;
if ( ! data - > object_table ) {
dev_err ( & client - > dev , " Failed to allocate memory \n " ) ;
return - ENOMEM ;
}
/* Get object table information */
2011-02-03 10:21:58 +03:00
error = mxt_get_object_table ( data ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
/* Check register init values */
2011-02-03 10:21:58 +03:00
error = mxt_check_reg_init ( data ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
2011-02-03 10:21:58 +03:00
mxt_handle_pdata ( data ) ;
2010-07-15 08:55:30 +04:00
/* Backup to memory */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_GEN_COMMAND_T6 ,
2011-02-03 10:21:58 +03:00
MXT_COMMAND_BACKUPNV ,
MXT_BACKUP_VALUE ) ;
msleep ( MXT_BACKUP_TIME ) ;
2010-07-15 08:55:30 +04:00
/* Soft reset */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_GEN_COMMAND_T6 ,
2011-02-03 10:21:58 +03:00
MXT_COMMAND_RESET , 1 ) ;
msleep ( MXT_RESET_TIME ) ;
2010-07-15 08:55:30 +04:00
/* Update matrix size at info struct */
2011-02-03 10:21:58 +03:00
error = mxt_read_reg ( client , MXT_MATRIX_X_SIZE , & val ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
info - > matrix_xsize = val ;
2011-02-03 10:21:58 +03:00
error = mxt_read_reg ( client , MXT_MATRIX_Y_SIZE , & val ) ;
2010-07-15 08:55:30 +04:00
if ( error )
return error ;
info - > matrix_ysize = val ;
dev_info ( & client - > dev ,
" Family ID: %d Variant ID: %d Version: %d Build: %d \n " ,
info - > family_id , info - > variant_id , info - > version ,
info - > build ) ;
dev_info ( & client - > dev ,
" Matrix X Size: %d Matrix Y Size: %d Object Num: %d \n " ,
info - > matrix_xsize , info - > matrix_ysize ,
info - > object_num ) ;
return 0 ;
}
2011-04-13 10:14:38 +04:00
static void mxt_calc_resolution ( struct mxt_data * data )
{
unsigned int max_x = data - > pdata - > x_size - 1 ;
unsigned int max_y = data - > pdata - > y_size - 1 ;
if ( data - > pdata - > orient & MXT_XY_SWITCH ) {
data - > max_x = max_y ;
data - > max_y = max_x ;
} else {
data - > max_x = max_x ;
data - > max_y = max_y ;
}
}
2011-02-03 10:21:58 +03:00
static ssize_t mxt_object_show ( struct device * dev ,
2010-07-15 08:55:30 +04:00
struct device_attribute * attr , char * buf )
{
2011-02-03 10:21:58 +03:00
struct mxt_data * data = dev_get_drvdata ( dev ) ;
struct mxt_object * object ;
2010-07-15 08:55:30 +04:00
int count = 0 ;
int i , j ;
int error ;
u8 val ;
for ( i = 0 ; i < data - > info . object_num ; i + + ) {
object = data - > object_table + i ;
2011-10-07 02:43:20 +04:00
count + = snprintf ( buf + count , PAGE_SIZE - count ,
" Object[%d] (Type %d) \n " ,
2010-07-15 08:55:30 +04:00
i + 1 , object - > type ) ;
2011-10-07 02:43:20 +04:00
if ( count > = PAGE_SIZE )
return PAGE_SIZE - 1 ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
if ( ! mxt_object_readable ( object - > type ) ) {
2011-10-07 02:43:20 +04:00
count + = snprintf ( buf + count , PAGE_SIZE - count ,
" \n " ) ;
if ( count > = PAGE_SIZE )
return PAGE_SIZE - 1 ;
2010-07-15 08:55:30 +04:00
continue ;
}
for ( j = 0 ; j < object - > size + 1 ; j + + ) {
2011-02-03 10:21:58 +03:00
error = mxt_read_object ( data ,
2010-07-15 08:55:30 +04:00
object - > type , j , & val ) ;
if ( error )
return error ;
2011-10-07 02:43:20 +04:00
count + = snprintf ( buf + count , PAGE_SIZE - count ,
" \t [%2d]: %02x (%d) \n " , j , val , val ) ;
if ( count > = PAGE_SIZE )
return PAGE_SIZE - 1 ;
2010-07-15 08:55:30 +04:00
}
2011-10-07 02:43:20 +04:00
count + = snprintf ( buf + count , PAGE_SIZE - count , " \n " ) ;
if ( count > = PAGE_SIZE )
return PAGE_SIZE - 1 ;
2010-07-15 08:55:30 +04:00
}
return count ;
}
2011-02-03 10:21:58 +03:00
static int mxt_load_fw ( struct device * dev , const char * fn )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_data * data = dev_get_drvdata ( dev ) ;
2010-07-15 08:55:30 +04:00
struct i2c_client * client = data - > client ;
const struct firmware * fw = NULL ;
unsigned int frame_size ;
unsigned int pos = 0 ;
int ret ;
ret = request_firmware ( & fw , fn , dev ) ;
if ( ret ) {
dev_err ( dev , " Unable to open firmware %s \n " , fn ) ;
return ret ;
}
/* Change to the bootloader mode */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_GEN_COMMAND_T6 ,
2011-02-03 10:21:58 +03:00
MXT_COMMAND_RESET , MXT_BOOT_VALUE ) ;
msleep ( MXT_RESET_TIME ) ;
2010-07-15 08:55:30 +04:00
/* Change to slave address of bootloader */
2011-02-03 10:21:58 +03:00
if ( client - > addr = = MXT_APP_LOW )
client - > addr = MXT_BOOT_LOW ;
2010-07-15 08:55:30 +04:00
else
2011-02-03 10:21:58 +03:00
client - > addr = MXT_BOOT_HIGH ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
ret = mxt_check_bootloader ( client , MXT_WAITING_BOOTLOAD_CMD ) ;
2010-07-15 08:55:30 +04:00
if ( ret )
goto out ;
/* Unlock bootloader */
2011-02-03 10:21:58 +03:00
mxt_unlock_bootloader ( client ) ;
2010-07-15 08:55:30 +04:00
while ( pos < fw - > size ) {
2011-02-03 10:21:58 +03:00
ret = mxt_check_bootloader ( client ,
MXT_WAITING_FRAME_DATA ) ;
2010-07-15 08:55:30 +04:00
if ( ret )
goto out ;
frame_size = ( ( * ( fw - > data + pos ) < < 8 ) | * ( fw - > data + pos + 1 ) ) ;
/* We should add 2 at frame size as the the firmware data is not
* included the CRC bytes .
*/
frame_size + = 2 ;
/* Write one frame to device */
2011-02-03 10:21:58 +03:00
mxt_fw_write ( client , fw - > data + pos , frame_size ) ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
ret = mxt_check_bootloader ( client ,
MXT_FRAME_CRC_PASS ) ;
2010-07-15 08:55:30 +04:00
if ( ret )
goto out ;
pos + = frame_size ;
dev_dbg ( dev , " Updated %d bytes / %zd bytes \n " , pos , fw - > size ) ;
}
out :
release_firmware ( fw ) ;
/* Change to slave address of application */
2011-02-03 10:21:58 +03:00
if ( client - > addr = = MXT_BOOT_LOW )
client - > addr = MXT_APP_LOW ;
2010-07-15 08:55:30 +04:00
else
2011-02-03 10:21:58 +03:00
client - > addr = MXT_APP_HIGH ;
2010-07-15 08:55:30 +04:00
return ret ;
}
2011-02-03 10:21:58 +03:00
static ssize_t mxt_update_fw_store ( struct device * dev ,
2010-07-15 08:55:30 +04:00
struct device_attribute * attr ,
const char * buf , size_t count )
{
2011-02-03 10:21:58 +03:00
struct mxt_data * data = dev_get_drvdata ( dev ) ;
2010-07-15 08:55:30 +04:00
int error ;
disable_irq ( data - > irq ) ;
2011-02-03 10:21:58 +03:00
error = mxt_load_fw ( dev , MXT_FW_NAME ) ;
2010-07-15 08:55:30 +04:00
if ( error ) {
dev_err ( dev , " The firmware update failed(%d) \n " , error ) ;
count = error ;
} else {
dev_dbg ( dev , " The firmware update succeeded \n " ) ;
/* Wait for reset */
2011-02-03 10:21:58 +03:00
msleep ( MXT_FWRESET_TIME ) ;
2010-07-15 08:55:30 +04:00
kfree ( data - > object_table ) ;
data - > object_table = NULL ;
2011-02-03 10:21:58 +03:00
mxt_initialize ( data ) ;
2010-07-15 08:55:30 +04:00
}
enable_irq ( data - > irq ) ;
2011-04-13 10:16:40 +04:00
error = mxt_make_highchg ( data ) ;
if ( error )
return error ;
2010-07-15 08:55:30 +04:00
return count ;
}
2012-05-09 09:30:14 +04:00
static DEVICE_ATTR ( object , S_IRUGO , mxt_object_show , NULL ) ;
static DEVICE_ATTR ( update_fw , S_IWUSR , NULL , mxt_update_fw_store ) ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
static struct attribute * mxt_attrs [ ] = {
2010-07-15 08:55:30 +04:00
& dev_attr_object . attr ,
& dev_attr_update_fw . attr ,
NULL
} ;
2011-02-03 10:21:58 +03:00
static const struct attribute_group mxt_attr_group = {
. attrs = mxt_attrs ,
2010-07-15 08:55:30 +04:00
} ;
2011-02-03 10:21:58 +03:00
static void mxt_start ( struct mxt_data * data )
2010-07-15 08:55:30 +04:00
{
/* Touch enable */
2011-02-03 10:21:58 +03:00
mxt_write_object ( data ,
2011-07-04 14:08:25 +04:00
MXT_TOUCH_MULTI_T9 , MXT_TOUCH_CTRL , 0x83 ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static void mxt_stop ( struct mxt_data * data )
2010-07-15 08:55:30 +04:00
{
/* Touch disable */
2011-02-03 10:21:58 +03:00
mxt_write_object ( data ,
2011-07-04 14:08:25 +04:00
MXT_TOUCH_MULTI_T9 , MXT_TOUCH_CTRL , 0 ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static int mxt_input_open ( struct input_dev * dev )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_data * data = input_get_drvdata ( dev ) ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
mxt_start ( data ) ;
2010-07-15 08:55:30 +04:00
return 0 ;
}
2011-02-03 10:21:58 +03:00
static void mxt_input_close ( struct input_dev * dev )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_data * data = input_get_drvdata ( dev ) ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
mxt_stop ( data ) ;
2010-07-15 08:55:30 +04:00
}
2011-02-03 10:21:58 +03:00
static int __devinit mxt_probe ( struct i2c_client * client ,
2010-07-15 08:55:30 +04:00
const struct i2c_device_id * id )
{
2011-02-16 00:36:52 +03:00
const struct mxt_platform_data * pdata = client - > dev . platform_data ;
2011-02-03 10:21:58 +03:00
struct mxt_data * data ;
2010-07-15 08:55:30 +04:00
struct input_dev * input_dev ;
int error ;
2011-02-16 00:36:52 +03:00
if ( ! pdata )
2010-07-15 08:55:30 +04:00
return - EINVAL ;
2011-02-03 10:21:58 +03:00
data = kzalloc ( sizeof ( struct mxt_data ) , GFP_KERNEL ) ;
2010-07-15 08:55:30 +04:00
input_dev = input_allocate_device ( ) ;
if ( ! data | | ! input_dev ) {
dev_err ( & client - > dev , " Failed to allocate memory \n " ) ;
error = - ENOMEM ;
goto err_free_mem ;
}
2011-02-03 10:21:58 +03:00
input_dev - > name = " Atmel maXTouch Touchscreen " ;
2010-07-15 08:55:30 +04:00
input_dev - > id . bustype = BUS_I2C ;
input_dev - > dev . parent = & client - > dev ;
2011-02-03 10:21:58 +03:00
input_dev - > open = mxt_input_open ;
input_dev - > close = mxt_input_close ;
2010-07-15 08:55:30 +04:00
2011-04-13 10:14:38 +04:00
data - > client = client ;
data - > input_dev = input_dev ;
data - > pdata = pdata ;
data - > irq = client - > irq ;
mxt_calc_resolution ( data ) ;
2010-07-15 08:55:30 +04:00
__set_bit ( EV_ABS , input_dev - > evbit ) ;
__set_bit ( EV_KEY , input_dev - > evbit ) ;
__set_bit ( BTN_TOUCH , input_dev - > keybit ) ;
/* For single touch */
input_set_abs_params ( input_dev , ABS_X ,
2011-04-13 10:14:38 +04:00
0 , data - > max_x , 0 , 0 ) ;
2010-07-15 08:55:30 +04:00
input_set_abs_params ( input_dev , ABS_Y ,
2011-04-13 10:14:38 +04:00
0 , data - > max_y , 0 , 0 ) ;
2011-08-16 11:40:54 +04:00
input_set_abs_params ( input_dev , ABS_PRESSURE ,
0 , 255 , 0 , 0 ) ;
2010-07-15 08:55:30 +04:00
/* For multi touch */
2011-04-13 10:18:59 +04:00
input_mt_init_slots ( input_dev , MXT_MAX_FINGER ) ;
2010-07-15 08:55:30 +04:00
input_set_abs_params ( input_dev , ABS_MT_TOUCH_MAJOR ,
2011-02-03 10:21:58 +03:00
0 , MXT_MAX_AREA , 0 , 0 ) ;
2010-07-15 08:55:30 +04:00
input_set_abs_params ( input_dev , ABS_MT_POSITION_X ,
2011-04-13 10:14:38 +04:00
0 , data - > max_x , 0 , 0 ) ;
2010-07-15 08:55:30 +04:00
input_set_abs_params ( input_dev , ABS_MT_POSITION_Y ,
2011-04-13 10:14:38 +04:00
0 , data - > max_y , 0 , 0 ) ;
2011-08-16 11:40:54 +04:00
input_set_abs_params ( input_dev , ABS_MT_PRESSURE ,
0 , 255 , 0 , 0 ) ;
2010-07-15 08:55:30 +04:00
input_set_drvdata ( input_dev , data ) ;
i2c_set_clientdata ( client , data ) ;
2011-02-03 10:21:58 +03:00
error = mxt_initialize ( data ) ;
2010-07-15 08:55:30 +04:00
if ( error )
goto err_free_object ;
2011-02-03 10:21:58 +03:00
error = request_threaded_irq ( client - > irq , NULL , mxt_interrupt ,
2011-02-16 00:36:52 +03:00
pdata - > irqflags , client - > dev . driver - > name , data ) ;
2010-07-15 08:55:30 +04:00
if ( error ) {
dev_err ( & client - > dev , " Failed to register interrupt \n " ) ;
goto err_free_object ;
}
2011-04-13 10:16:40 +04:00
error = mxt_make_highchg ( data ) ;
if ( error )
goto err_free_irq ;
2010-07-15 08:55:30 +04:00
error = input_register_device ( input_dev ) ;
if ( error )
goto err_free_irq ;
2011-02-03 10:21:58 +03:00
error = sysfs_create_group ( & client - > dev . kobj , & mxt_attr_group ) ;
2010-07-15 08:55:30 +04:00
if ( error )
goto err_unregister_device ;
return 0 ;
err_unregister_device :
input_unregister_device ( input_dev ) ;
input_dev = NULL ;
err_free_irq :
free_irq ( client - > irq , data ) ;
err_free_object :
kfree ( data - > object_table ) ;
err_free_mem :
input_free_device ( input_dev ) ;
kfree ( data ) ;
return error ;
}
2011-02-03 10:21:58 +03:00
static int __devexit mxt_remove ( struct i2c_client * client )
2010-07-15 08:55:30 +04:00
{
2011-02-03 10:21:58 +03:00
struct mxt_data * data = i2c_get_clientdata ( client ) ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
sysfs_remove_group ( & client - > dev . kobj , & mxt_attr_group ) ;
2010-07-15 08:55:30 +04:00
free_irq ( data - > irq , data ) ;
input_unregister_device ( data - > input_dev ) ;
kfree ( data - > object_table ) ;
kfree ( data ) ;
return 0 ;
}
2012-05-09 09:29:14 +04:00
# ifdef CONFIG_PM_SLEEP
2011-02-03 10:21:58 +03:00
static int mxt_suspend ( struct device * dev )
2010-07-15 08:55:30 +04:00
{
2010-11-18 11:14:03 +03:00
struct i2c_client * client = to_i2c_client ( dev ) ;
2011-02-03 10:21:58 +03:00
struct mxt_data * data = i2c_get_clientdata ( client ) ;
2010-07-15 08:55:30 +04:00
struct input_dev * input_dev = data - > input_dev ;
mutex_lock ( & input_dev - > mutex ) ;
if ( input_dev - > users )
2011-02-03 10:21:58 +03:00
mxt_stop ( data ) ;
2010-07-15 08:55:30 +04:00
mutex_unlock ( & input_dev - > mutex ) ;
return 0 ;
}
2011-02-03 10:21:58 +03:00
static int mxt_resume ( struct device * dev )
2010-07-15 08:55:30 +04:00
{
2010-11-18 11:14:03 +03:00
struct i2c_client * client = to_i2c_client ( dev ) ;
2011-02-03 10:21:58 +03:00
struct mxt_data * data = i2c_get_clientdata ( client ) ;
2010-07-15 08:55:30 +04:00
struct input_dev * input_dev = data - > input_dev ;
/* Soft reset */
2011-07-04 14:08:25 +04:00
mxt_write_object ( data , MXT_GEN_COMMAND_T6 ,
2011-02-03 10:21:58 +03:00
MXT_COMMAND_RESET , 1 ) ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
msleep ( MXT_RESET_TIME ) ;
2010-07-15 08:55:30 +04:00
mutex_lock ( & input_dev - > mutex ) ;
if ( input_dev - > users )
2011-02-03 10:21:58 +03:00
mxt_start ( data ) ;
2010-07-15 08:55:30 +04:00
mutex_unlock ( & input_dev - > mutex ) ;
return 0 ;
}
# endif
2012-05-09 09:29:14 +04:00
static SIMPLE_DEV_PM_OPS ( mxt_pm_ops , mxt_suspend , mxt_resume ) ;
2011-02-03 10:21:58 +03:00
static const struct i2c_device_id mxt_id [ ] = {
2010-07-15 08:55:30 +04:00
{ " qt602240_ts " , 0 } ,
2011-02-03 10:21:58 +03:00
{ " atmel_mxt_ts " , 0 } ,
2011-02-16 00:36:52 +03:00
{ " mXT224 " , 0 } ,
2010-07-15 08:55:30 +04:00
{ }
} ;
2011-02-03 10:21:58 +03:00
MODULE_DEVICE_TABLE ( i2c , mxt_id ) ;
2010-07-15 08:55:30 +04:00
2011-02-03 10:21:58 +03:00
static struct i2c_driver mxt_driver = {
2010-07-15 08:55:30 +04:00
. driver = {
2011-02-03 10:21:58 +03:00
. name = " atmel_mxt_ts " ,
2010-07-15 08:55:30 +04:00
. owner = THIS_MODULE ,
2011-02-03 10:21:58 +03:00
. pm = & mxt_pm_ops ,
2010-07-15 08:55:30 +04:00
} ,
2011-02-03 10:21:58 +03:00
. probe = mxt_probe ,
. remove = __devexit_p ( mxt_remove ) ,
. id_table = mxt_id ,
2010-07-15 08:55:30 +04:00
} ;
2012-03-17 10:05:41 +04:00
module_i2c_driver ( mxt_driver ) ;
2010-07-15 08:55:30 +04:00
/* Module information */
MODULE_AUTHOR ( " Joonyoung Shim <jy0922.shim@samsung.com> " ) ;
2011-02-03 10:21:58 +03:00
MODULE_DESCRIPTION ( " Atmel maXTouch Touchscreen driver " ) ;
2010-07-15 08:55:30 +04:00
MODULE_LICENSE ( " GPL " ) ;