2012-07-24 23:29:36 -07:00
/*
* Copyright ( C ) 2012 Simon Budig , < simon . budig @ kernelconcepts . de >
2014-03-28 09:31:14 -07:00
* Daniel Wagener < daniel . wagener @ kernelconcepts . de > ( M09 firmware support )
2014-03-28 09:23:02 -07:00
* Lothar Waßmann < LW @ KARO - electronics . de > ( DT support )
2012-07-24 23:29:36 -07:00
*
* 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 .
*
* You should have received a copy of the GNU General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
/*
* This is a driver for the EDT " Polytouch " family of touch controllers
* based on the FocalTech FT5x06 line of chips .
*
* Development of this driver has been sponsored by Glyn :
* http : //www.glyn.com/Products/Displays
*/
# include <linux/module.h>
# include <linux/ratelimit.h>
2015-09-12 10:11:09 -07:00
# include <linux/irq.h>
2012-07-24 23:29:36 -07:00
# include <linux/interrupt.h>
# include <linux/input.h>
# include <linux/i2c.h>
# include <linux/uaccess.h>
# include <linux/delay.h>
# include <linux/debugfs.h>
# include <linux/slab.h>
2015-09-11 17:30:34 -07:00
# include <linux/gpio/consumer.h>
2012-07-24 23:29:36 -07:00
# include <linux/input/mt.h>
2015-03-21 20:18:06 -07:00
# include <linux/input/touchscreen.h>
2015-10-16 15:34:16 -07:00
# include <linux/of_device.h>
2012-07-24 23:29:36 -07:00
# define WORK_REGISTER_THRESHOLD 0x00
# define WORK_REGISTER_REPORT_RATE 0x08
# define WORK_REGISTER_GAIN 0x30
# define WORK_REGISTER_OFFSET 0x31
# define WORK_REGISTER_NUM_X 0x33
# define WORK_REGISTER_NUM_Y 0x34
2014-03-28 09:31:14 -07:00
# define M09_REGISTER_THRESHOLD 0x80
# define M09_REGISTER_GAIN 0x92
# define M09_REGISTER_OFFSET 0x93
# define M09_REGISTER_NUM_X 0x94
# define M09_REGISTER_NUM_Y 0x95
# define NO_REGISTER 0xff
2012-07-24 23:29:36 -07:00
# define WORK_REGISTER_OPMODE 0x3c
# define FACTORY_REGISTER_OPMODE 0x01
# define TOUCH_EVENT_DOWN 0x00
# define TOUCH_EVENT_UP 0x01
# define TOUCH_EVENT_ON 0x02
# define TOUCH_EVENT_RESERVED 0x03
# define EDT_NAME_LEN 23
# define EDT_SWITCH_MODE_RETRIES 10
# define EDT_SWITCH_MODE_DELAY 5 /* msec */
# define EDT_RAW_DATA_RETRIES 100
2017-01-04 10:57:51 -08:00
# define EDT_RAW_DATA_DELAY 1000 /* usec */
2012-07-24 23:29:36 -07:00
2014-03-28 09:31:14 -07:00
enum edt_ver {
2017-10-09 20:58:11 -07:00
EDT_M06 ,
EDT_M09 ,
2017-10-09 21:00:16 -07:00
EDT_M12 ,
2017-10-09 20:58:11 -07:00
GENERIC_FT ,
2014-03-28 09:31:14 -07:00
} ;
struct edt_reg_addr {
int reg_threshold ;
int reg_report_rate ;
int reg_gain ;
int reg_offset ;
int reg_num_x ;
int reg_num_y ;
} ;
2012-07-24 23:29:36 -07:00
struct edt_ft5x06_ts_data {
struct i2c_client * client ;
struct input_dev * input ;
2016-07-15 14:26:53 -07:00
struct touchscreen_properties prop ;
2012-07-24 23:29:36 -07:00
u16 num_x ;
u16 num_y ;
2015-09-11 17:30:34 -07:00
struct gpio_desc * reset_gpio ;
struct gpio_desc * wake_gpio ;
2014-03-28 09:23:02 -07:00
2012-07-24 23:29:36 -07:00
# if defined(CONFIG_DEBUG_FS)
struct dentry * debug_dir ;
u8 * raw_buffer ;
size_t raw_bufsize ;
# endif
struct mutex mutex ;
bool factory_mode ;
int threshold ;
int gain ;
int offset ;
int report_rate ;
2015-10-16 15:34:16 -07:00
int max_support_points ;
2012-07-24 23:29:36 -07:00
char name [ EDT_NAME_LEN ] ;
2014-03-28 09:31:14 -07:00
struct edt_reg_addr reg_addr ;
enum edt_ver version ;
2012-07-24 23:29:36 -07:00
} ;
2015-10-16 15:34:16 -07:00
struct edt_i2c_chip_data {
int max_support_points ;
} ;
2012-07-24 23:29:36 -07:00
static int edt_ft5x06_ts_readwrite ( struct i2c_client * client ,
u16 wr_len , u8 * wr_buf ,
u16 rd_len , u8 * rd_buf )
{
struct i2c_msg wrmsg [ 2 ] ;
int i = 0 ;
int ret ;
if ( wr_len ) {
wrmsg [ i ] . addr = client - > addr ;
wrmsg [ i ] . flags = 0 ;
wrmsg [ i ] . len = wr_len ;
wrmsg [ i ] . buf = wr_buf ;
i + + ;
}
if ( rd_len ) {
wrmsg [ i ] . addr = client - > addr ;
wrmsg [ i ] . flags = I2C_M_RD ;
wrmsg [ i ] . len = rd_len ;
wrmsg [ i ] . buf = rd_buf ;
i + + ;
}
ret = i2c_transfer ( client - > adapter , wrmsg , i ) ;
if ( ret < 0 )
return ret ;
if ( ret ! = i )
return - EIO ;
return 0 ;
}
static bool edt_ft5x06_ts_check_crc ( struct edt_ft5x06_ts_data * tsdata ,
u8 * buf , int buflen )
{
int i ;
u8 crc = 0 ;
for ( i = 0 ; i < buflen - 1 ; i + + )
crc ^ = buf [ i ] ;
if ( crc ! = buf [ buflen - 1 ] ) {
dev_err_ratelimited ( & tsdata - > client - > dev ,
" crc error: 0x%02x expected, got 0x%02x \n " ,
crc , buf [ buflen - 1 ] ) ;
return false ;
}
return true ;
}
static irqreturn_t edt_ft5x06_ts_isr ( int irq , void * dev_id )
{
struct edt_ft5x06_ts_data * tsdata = dev_id ;
struct device * dev = & tsdata - > client - > dev ;
2014-03-28 09:31:14 -07:00
u8 cmd ;
2015-10-16 15:34:41 -07:00
u8 rdbuf [ 63 ] ;
2012-07-24 23:29:36 -07:00
int i , type , x , y , id ;
2015-10-16 15:34:05 -07:00
int offset , tplen , datalen , crclen ;
2012-07-24 23:29:36 -07:00
int error ;
2014-03-28 09:31:14 -07:00
switch ( tsdata - > version ) {
2017-10-09 20:58:11 -07:00
case EDT_M06 :
2014-03-28 09:31:14 -07:00
cmd = 0xf9 ; /* tell the controller to send touch data */
offset = 5 ; /* where the actual touch data starts */
tplen = 4 ; /* data comes in so called frames */
2015-10-16 15:34:05 -07:00
crclen = 1 ; /* length of the crc data */
2014-03-28 09:31:14 -07:00
break ;
2017-10-09 20:58:11 -07:00
case EDT_M09 :
2017-10-09 21:00:16 -07:00
case EDT_M12 :
2017-10-09 20:58:11 -07:00
case GENERIC_FT :
2015-10-16 15:34:41 -07:00
cmd = 0x0 ;
offset = 3 ;
2014-03-28 09:31:14 -07:00
tplen = 6 ;
2015-10-16 15:34:05 -07:00
crclen = 0 ;
2014-03-28 09:31:14 -07:00
break ;
default :
goto out ;
}
2012-07-24 23:29:36 -07:00
memset ( rdbuf , 0 , sizeof ( rdbuf ) ) ;
2015-10-16 15:34:16 -07:00
datalen = tplen * tsdata - > max_support_points + offset + crclen ;
2012-07-24 23:29:36 -07:00
error = edt_ft5x06_ts_readwrite ( tsdata - > client ,
sizeof ( cmd ) , & cmd ,
2014-03-28 09:31:14 -07:00
datalen , rdbuf ) ;
2012-07-24 23:29:36 -07:00
if ( error ) {
dev_err_ratelimited ( dev , " Unable to fetch data, error: %d \n " ,
error ) ;
goto out ;
}
2017-10-09 21:00:16 -07:00
/* M09/M12 does not send header or CRC */
2017-10-09 20:58:11 -07:00
if ( tsdata - > version = = EDT_M06 ) {
2014-03-28 09:31:14 -07:00
if ( rdbuf [ 0 ] ! = 0xaa | | rdbuf [ 1 ] ! = 0xaa | |
rdbuf [ 2 ] ! = datalen ) {
dev_err_ratelimited ( dev ,
" Unexpected header: %02x%02x%02x! \n " ,
rdbuf [ 0 ] , rdbuf [ 1 ] , rdbuf [ 2 ] ) ;
goto out ;
}
2012-07-24 23:29:36 -07:00
2014-03-28 09:31:14 -07:00
if ( ! edt_ft5x06_ts_check_crc ( tsdata , rdbuf , datalen ) )
goto out ;
}
2012-07-24 23:29:36 -07:00
2015-10-16 15:34:16 -07:00
for ( i = 0 ; i < tsdata - > max_support_points ; i + + ) {
2014-03-28 09:31:14 -07:00
u8 * buf = & rdbuf [ i * tplen + offset ] ;
2012-07-24 23:29:36 -07:00
bool down ;
type = buf [ 0 ] > > 6 ;
/* ignore Reserved events */
if ( type = = TOUCH_EVENT_RESERVED )
continue ;
2014-03-28 09:31:14 -07:00
/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
2017-10-09 20:58:11 -07:00
if ( tsdata - > version = = EDT_M06 & & type = = TOUCH_EVENT_DOWN )
2014-03-28 09:28:17 -07:00
continue ;
2012-07-24 23:29:36 -07:00
x = ( ( buf [ 0 ] < < 8 ) | buf [ 1 ] ) & 0x0fff ;
y = ( ( buf [ 2 ] < < 8 ) | buf [ 3 ] ) & 0x0fff ;
id = ( buf [ 2 ] > > 4 ) & 0x0f ;
2014-03-28 09:20:08 -07:00
down = type ! = TOUCH_EVENT_UP ;
2012-07-24 23:29:36 -07:00
input_mt_slot ( tsdata - > input , id ) ;
input_mt_report_slot_state ( tsdata - > input , MT_TOOL_FINGER , down ) ;
if ( ! down )
continue ;
2016-07-15 14:26:53 -07:00
touchscreen_report_pos ( tsdata - > input , & tsdata - > prop , x , y ,
true ) ;
2012-07-24 23:29:36 -07:00
}
input_mt_report_pointer_emulation ( tsdata - > input , true ) ;
input_sync ( tsdata - > input ) ;
out :
return IRQ_HANDLED ;
}
static int edt_ft5x06_register_write ( struct edt_ft5x06_ts_data * tsdata ,
u8 addr , u8 value )
{
u8 wrbuf [ 4 ] ;
2014-03-28 09:31:14 -07:00
switch ( tsdata - > version ) {
2017-10-09 20:58:11 -07:00
case EDT_M06 :
2014-03-28 09:31:14 -07:00
wrbuf [ 0 ] = tsdata - > factory_mode ? 0xf3 : 0xfc ;
wrbuf [ 1 ] = tsdata - > factory_mode ? addr & 0x7f : addr & 0x3f ;
wrbuf [ 2 ] = value ;
wrbuf [ 3 ] = wrbuf [ 0 ] ^ wrbuf [ 1 ] ^ wrbuf [ 2 ] ;
return edt_ft5x06_ts_readwrite ( tsdata - > client , 4 ,
wrbuf , 0 , NULL ) ;
2017-10-09 20:58:11 -07:00
case EDT_M09 :
2017-10-09 21:00:16 -07:00
case EDT_M12 :
2017-10-09 20:58:11 -07:00
case GENERIC_FT :
2014-03-28 09:31:14 -07:00
wrbuf [ 0 ] = addr ;
wrbuf [ 1 ] = value ;
2014-06-07 22:20:23 -07:00
return edt_ft5x06_ts_readwrite ( tsdata - > client , 2 ,
2014-03-28 09:31:14 -07:00
wrbuf , 0 , NULL ) ;
default :
return - EINVAL ;
}
2012-07-24 23:29:36 -07:00
}
static int edt_ft5x06_register_read ( struct edt_ft5x06_ts_data * tsdata ,
u8 addr )
{
u8 wrbuf [ 2 ] , rdbuf [ 2 ] ;
int error ;
2014-03-28 09:31:14 -07:00
switch ( tsdata - > version ) {
2017-10-09 20:58:11 -07:00
case EDT_M06 :
2014-03-28 09:31:14 -07:00
wrbuf [ 0 ] = tsdata - > factory_mode ? 0xf3 : 0xfc ;
wrbuf [ 1 ] = tsdata - > factory_mode ? addr & 0x7f : addr & 0x3f ;
wrbuf [ 1 ] | = tsdata - > factory_mode ? 0x80 : 0x40 ;
2012-07-24 23:29:36 -07:00
2014-04-03 09:17:05 -07:00
error = edt_ft5x06_ts_readwrite ( tsdata - > client , 2 , wrbuf , 2 ,
rdbuf ) ;
if ( error )
return error ;
2012-07-24 23:29:36 -07:00
2014-03-28 09:31:14 -07:00
if ( ( wrbuf [ 0 ] ^ wrbuf [ 1 ] ^ rdbuf [ 0 ] ) ! = rdbuf [ 1 ] ) {
dev_err ( & tsdata - > client - > dev ,
" crc error: 0x%02x expected, got 0x%02x \n " ,
wrbuf [ 0 ] ^ wrbuf [ 1 ] ^ rdbuf [ 0 ] ,
rdbuf [ 1 ] ) ;
return - EIO ;
}
break ;
2017-10-09 20:58:11 -07:00
case EDT_M09 :
2017-10-09 21:00:16 -07:00
case EDT_M12 :
2017-10-09 20:58:11 -07:00
case GENERIC_FT :
2014-03-28 09:31:14 -07:00
wrbuf [ 0 ] = addr ;
error = edt_ft5x06_ts_readwrite ( tsdata - > client , 1 ,
wrbuf , 1 , rdbuf ) ;
if ( error )
return error ;
break ;
default :
return - EINVAL ;
2012-07-24 23:29:36 -07:00
}
return rdbuf [ 0 ] ;
}
struct edt_ft5x06_attribute {
struct device_attribute dattr ;
size_t field_offset ;
u8 limit_low ;
u8 limit_high ;
2014-03-28 09:31:14 -07:00
u8 addr_m06 ;
u8 addr_m09 ;
2012-07-24 23:29:36 -07:00
} ;
2014-03-28 09:31:14 -07:00
# define EDT_ATTR(_field, _mode, _addr_m06, _addr_m09, \
_limit_low , _limit_high ) \
2012-07-24 23:29:36 -07:00
struct edt_ft5x06_attribute edt_ft5x06_attr_ # # _field = { \
. dattr = __ATTR ( _field , _mode , \
edt_ft5x06_setting_show , \
edt_ft5x06_setting_store ) , \
2014-03-28 09:31:14 -07:00
. field_offset = offsetof ( struct edt_ft5x06_ts_data , _field ) , \
. addr_m06 = _addr_m06 , \
. addr_m09 = _addr_m09 , \
2012-07-24 23:29:36 -07:00
. limit_low = _limit_low , \
. limit_high = _limit_high , \
}
static ssize_t edt_ft5x06_setting_show ( struct device * dev ,
struct device_attribute * dattr ,
char * buf )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct edt_ft5x06_ts_data * tsdata = i2c_get_clientdata ( client ) ;
struct edt_ft5x06_attribute * attr =
container_of ( dattr , struct edt_ft5x06_attribute , dattr ) ;
2014-03-28 09:20:08 -07:00
u8 * field = ( u8 * ) tsdata + attr - > field_offset ;
2012-07-24 23:29:36 -07:00
int val ;
size_t count = 0 ;
int error = 0 ;
2014-03-28 09:31:14 -07:00
u8 addr ;
2012-07-24 23:29:36 -07:00
mutex_lock ( & tsdata - > mutex ) ;
if ( tsdata - > factory_mode ) {
error = - EIO ;
goto out ;
}
2014-03-28 09:31:14 -07:00
switch ( tsdata - > version ) {
2017-10-09 20:58:11 -07:00
case EDT_M06 :
2014-03-28 09:31:14 -07:00
addr = attr - > addr_m06 ;
break ;
2017-10-09 20:58:11 -07:00
case EDT_M09 :
2017-10-09 21:00:16 -07:00
case EDT_M12 :
2017-10-09 20:58:11 -07:00
case GENERIC_FT :
2014-03-28 09:31:14 -07:00
addr = attr - > addr_m09 ;
break ;
default :
error = - ENODEV ;
2012-07-24 23:29:36 -07:00
goto out ;
}
2014-03-28 09:31:14 -07:00
if ( addr ! = NO_REGISTER ) {
val = edt_ft5x06_register_read ( tsdata , addr ) ;
if ( val < 0 ) {
error = val ;
dev_err ( & tsdata - > client - > dev ,
" Failed to fetch attribute %s, error %d \n " ,
dattr - > attr . name , error ) ;
goto out ;
}
} else {
val = * field ;
}
2012-07-24 23:29:36 -07:00
if ( val ! = * field ) {
dev_warn ( & tsdata - > client - > dev ,
" %s: read (%d) and stored value (%d) differ \n " ,
dattr - > attr . name , val , * field ) ;
* field = val ;
}
count = scnprintf ( buf , PAGE_SIZE , " %d \n " , val ) ;
out :
mutex_unlock ( & tsdata - > mutex ) ;
return error ? : count ;
}
static ssize_t edt_ft5x06_setting_store ( struct device * dev ,
struct device_attribute * dattr ,
const char * buf , size_t count )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
struct edt_ft5x06_ts_data * tsdata = i2c_get_clientdata ( client ) ;
struct edt_ft5x06_attribute * attr =
container_of ( dattr , struct edt_ft5x06_attribute , dattr ) ;
2014-03-28 09:20:08 -07:00
u8 * field = ( u8 * ) tsdata + attr - > field_offset ;
2012-07-24 23:29:36 -07:00
unsigned int val ;
int error ;
2014-03-28 09:31:14 -07:00
u8 addr ;
2012-07-24 23:29:36 -07:00
mutex_lock ( & tsdata - > mutex ) ;
if ( tsdata - > factory_mode ) {
error = - EIO ;
goto out ;
}
error = kstrtouint ( buf , 0 , & val ) ;
if ( error )
goto out ;
if ( val < attr - > limit_low | | val > attr - > limit_high ) {
error = - ERANGE ;
goto out ;
}
2014-03-28 09:31:14 -07:00
switch ( tsdata - > version ) {
2017-10-09 20:58:11 -07:00
case EDT_M06 :
2014-03-28 09:31:14 -07:00
addr = attr - > addr_m06 ;
break ;
2017-10-09 20:58:11 -07:00
case EDT_M09 :
2017-10-09 21:00:16 -07:00
case EDT_M12 :
2017-10-09 20:58:11 -07:00
case GENERIC_FT :
2014-03-28 09:31:14 -07:00
addr = attr - > addr_m09 ;
break ;
default :
error = - ENODEV ;
2012-07-24 23:29:36 -07:00
goto out ;
}
2014-03-28 09:31:14 -07:00
if ( addr ! = NO_REGISTER ) {
error = edt_ft5x06_register_write ( tsdata , addr , val ) ;
if ( error ) {
dev_err ( & tsdata - > client - > dev ,
" Failed to update attribute %s, error: %d \n " ,
dattr - > attr . name , error ) ;
goto out ;
}
}
2012-07-24 23:29:36 -07:00
* field = val ;
out :
mutex_unlock ( & tsdata - > mutex ) ;
return error ? : count ;
}
2017-10-09 21:00:16 -07:00
/* m06, m09: range 0-31, m12: range 0-5 */
2014-03-28 09:31:14 -07:00
static EDT_ATTR ( gain , S_IWUSR | S_IRUGO , WORK_REGISTER_GAIN ,
M09_REGISTER_GAIN , 0 , 31 ) ;
2017-10-09 21:00:16 -07:00
/* m06, m09: range 0-31, m12: range 0-16 */
2014-03-28 09:31:14 -07:00
static EDT_ATTR ( offset , S_IWUSR | S_IRUGO , WORK_REGISTER_OFFSET ,
M09_REGISTER_OFFSET , 0 , 31 ) ;
2017-10-09 21:00:16 -07:00
/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
2014-03-28 09:31:14 -07:00
static EDT_ATTR ( threshold , S_IWUSR | S_IRUGO , WORK_REGISTER_THRESHOLD ,
2017-10-09 21:00:16 -07:00
M09_REGISTER_THRESHOLD , 0 , 255 ) ;
/* m06: range 3 to 14, m12: (0x64: 100Hz) */
2014-03-28 09:31:14 -07:00
static EDT_ATTR ( report_rate , S_IWUSR | S_IRUGO , WORK_REGISTER_REPORT_RATE ,
2017-10-09 21:00:16 -07:00
NO_REGISTER , 0 , 255 ) ;
2012-07-24 23:29:36 -07:00
static struct attribute * edt_ft5x06_attrs [ ] = {
& edt_ft5x06_attr_gain . dattr . attr ,
& edt_ft5x06_attr_offset . dattr . attr ,
& edt_ft5x06_attr_threshold . dattr . attr ,
& edt_ft5x06_attr_report_rate . dattr . attr ,
NULL
} ;
static const struct attribute_group edt_ft5x06_attr_group = {
. attrs = edt_ft5x06_attrs ,
} ;
# ifdef CONFIG_DEBUG_FS
static int edt_ft5x06_factory_mode ( struct edt_ft5x06_ts_data * tsdata )
{
struct i2c_client * client = tsdata - > client ;
int retries = EDT_SWITCH_MODE_RETRIES ;
int ret ;
int error ;
2018-01-23 10:01:57 -08:00
if ( tsdata - > version ! = EDT_M06 ) {
dev_err ( & client - > dev ,
" No factory mode support for non-M06 devices \n " ) ;
return - EINVAL ;
}
2012-07-24 23:29:36 -07:00
disable_irq ( client - > irq ) ;
if ( ! tsdata - > raw_buffer ) {
tsdata - > raw_bufsize = tsdata - > num_x * tsdata - > num_y *
sizeof ( u16 ) ;
tsdata - > raw_buffer = kzalloc ( tsdata - > raw_bufsize , GFP_KERNEL ) ;
if ( ! tsdata - > raw_buffer ) {
error = - ENOMEM ;
goto err_out ;
}
}
/* mode register is 0x3c when in the work mode */
error = edt_ft5x06_register_write ( tsdata , WORK_REGISTER_OPMODE , 0x03 ) ;
if ( error ) {
dev_err ( & client - > dev ,
" failed to switch to factory mode, error %d \n " , error ) ;
goto err_out ;
}
tsdata - > factory_mode = true ;
do {
mdelay ( EDT_SWITCH_MODE_DELAY ) ;
/* mode register is 0x01 when in factory mode */
ret = edt_ft5x06_register_read ( tsdata , FACTORY_REGISTER_OPMODE ) ;
if ( ret = = 0x03 )
break ;
} while ( - - retries > 0 ) ;
if ( retries = = 0 ) {
dev_err ( & client - > dev , " not in factory mode after %dms. \n " ,
EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY ) ;
error = - EIO ;
goto err_out ;
}
return 0 ;
err_out :
kfree ( tsdata - > raw_buffer ) ;
tsdata - > raw_buffer = NULL ;
tsdata - > factory_mode = false ;
enable_irq ( client - > irq ) ;
return error ;
}
static int edt_ft5x06_work_mode ( struct edt_ft5x06_ts_data * tsdata )
{
struct i2c_client * client = tsdata - > client ;
int retries = EDT_SWITCH_MODE_RETRIES ;
2014-03-28 09:31:14 -07:00
struct edt_reg_addr * reg_addr = & tsdata - > reg_addr ;
2012-07-24 23:29:36 -07:00
int ret ;
int error ;
/* mode register is 0x01 when in the factory mode */
error = edt_ft5x06_register_write ( tsdata , FACTORY_REGISTER_OPMODE , 0x1 ) ;
if ( error ) {
dev_err ( & client - > dev ,
" failed to switch to work mode, error: %d \n " , error ) ;
return error ;
}
tsdata - > factory_mode = false ;
do {
mdelay ( EDT_SWITCH_MODE_DELAY ) ;
/* mode register is 0x01 when in factory mode */
ret = edt_ft5x06_register_read ( tsdata , WORK_REGISTER_OPMODE ) ;
if ( ret = = 0x01 )
break ;
} while ( - - retries > 0 ) ;
if ( retries = = 0 ) {
dev_err ( & client - > dev , " not in work mode after %dms. \n " ,
EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY ) ;
tsdata - > factory_mode = true ;
return - EIO ;
}
2013-03-28 01:14:42 -07:00
kfree ( tsdata - > raw_buffer ) ;
2012-07-24 23:29:36 -07:00
tsdata - > raw_buffer = NULL ;
/* restore parameters */
2014-03-28 09:31:14 -07:00
edt_ft5x06_register_write ( tsdata , reg_addr - > reg_threshold ,
2012-07-24 23:29:36 -07:00
tsdata - > threshold ) ;
2014-03-28 09:31:14 -07:00
edt_ft5x06_register_write ( tsdata , reg_addr - > reg_gain ,
2012-07-24 23:29:36 -07:00
tsdata - > gain ) ;
2014-03-28 09:31:14 -07:00
edt_ft5x06_register_write ( tsdata , reg_addr - > reg_offset ,
2012-07-24 23:29:36 -07:00
tsdata - > offset ) ;
2017-09-07 14:28:28 -07:00
if ( reg_addr - > reg_report_rate ! = NO_REGISTER )
2014-03-28 09:31:14 -07:00
edt_ft5x06_register_write ( tsdata , reg_addr - > reg_report_rate ,
2012-07-24 23:29:36 -07:00
tsdata - > report_rate ) ;
enable_irq ( client - > irq ) ;
return 0 ;
}
static int edt_ft5x06_debugfs_mode_get ( void * data , u64 * mode )
{
struct edt_ft5x06_ts_data * tsdata = data ;
* mode = tsdata - > factory_mode ;
return 0 ;
} ;
static int edt_ft5x06_debugfs_mode_set ( void * data , u64 mode )
{
struct edt_ft5x06_ts_data * tsdata = data ;
int retval = 0 ;
if ( mode > 1 )
return - ERANGE ;
mutex_lock ( & tsdata - > mutex ) ;
if ( mode ! = tsdata - > factory_mode ) {
retval = mode ? edt_ft5x06_factory_mode ( tsdata ) :
2014-03-28 09:20:08 -07:00
edt_ft5x06_work_mode ( tsdata ) ;
2012-07-24 23:29:36 -07:00
}
mutex_unlock ( & tsdata - > mutex ) ;
return retval ;
} ;
DEFINE_SIMPLE_ATTRIBUTE ( debugfs_mode_fops , edt_ft5x06_debugfs_mode_get ,
edt_ft5x06_debugfs_mode_set , " %llu \n " ) ;
static ssize_t edt_ft5x06_debugfs_raw_data_read ( struct file * file ,
char __user * buf , size_t count , loff_t * off )
{
struct edt_ft5x06_ts_data * tsdata = file - > private_data ;
struct i2c_client * client = tsdata - > client ;
int retries = EDT_RAW_DATA_RETRIES ;
int val , i , error ;
size_t read = 0 ;
int colbytes ;
char wrbuf [ 3 ] ;
u8 * rdbuf ;
if ( * off < 0 | | * off > = tsdata - > raw_bufsize )
return 0 ;
mutex_lock ( & tsdata - > mutex ) ;
if ( ! tsdata - > factory_mode | | ! tsdata - > raw_buffer ) {
error = - EIO ;
goto out ;
}
error = edt_ft5x06_register_write ( tsdata , 0x08 , 0x01 ) ;
if ( error ) {
dev_dbg ( & client - > dev ,
" failed to write 0x08 register, error %d \n " , error ) ;
goto out ;
}
do {
2017-01-04 10:57:51 -08:00
usleep_range ( EDT_RAW_DATA_DELAY , EDT_RAW_DATA_DELAY + 100 ) ;
2012-07-24 23:29:36 -07:00
val = edt_ft5x06_register_read ( tsdata , 0x08 ) ;
if ( val < 1 )
break ;
} while ( - - retries > 0 ) ;
if ( val < 0 ) {
error = val ;
dev_dbg ( & client - > dev ,
" failed to read 0x08 register, error %d \n " , error ) ;
goto out ;
}
if ( retries = = 0 ) {
dev_dbg ( & client - > dev ,
" timed out waiting for register to settle \n " ) ;
error = - ETIMEDOUT ;
goto out ;
}
rdbuf = tsdata - > raw_buffer ;
colbytes = tsdata - > num_y * sizeof ( u16 ) ;
wrbuf [ 0 ] = 0xf5 ;
wrbuf [ 1 ] = 0x0e ;
for ( i = 0 ; i < tsdata - > num_x ; i + + ) {
wrbuf [ 2 ] = i ; /* column index */
error = edt_ft5x06_ts_readwrite ( tsdata - > client ,
sizeof ( wrbuf ) , wrbuf ,
colbytes , rdbuf ) ;
if ( error )
goto out ;
rdbuf + = colbytes ;
}
read = min_t ( size_t , count , tsdata - > raw_bufsize - * off ) ;
2012-09-19 15:56:23 -07:00
if ( copy_to_user ( buf , tsdata - > raw_buffer + * off , read ) ) {
error = - EFAULT ;
goto out ;
}
* off + = read ;
2012-07-24 23:29:36 -07:00
out :
mutex_unlock ( & tsdata - > mutex ) ;
return error ? : read ;
} ;
static const struct file_operations debugfs_raw_data_fops = {
2012-10-17 23:55:54 -07:00
. open = simple_open ,
2012-07-24 23:29:36 -07:00
. read = edt_ft5x06_debugfs_raw_data_read ,
} ;
2012-11-23 21:38:25 -08:00
static void
2012-07-24 23:29:36 -07:00
edt_ft5x06_ts_prepare_debugfs ( struct edt_ft5x06_ts_data * tsdata ,
const char * debugfs_name )
{
tsdata - > debug_dir = debugfs_create_dir ( debugfs_name , NULL ) ;
if ( ! tsdata - > debug_dir )
return ;
debugfs_create_u16 ( " num_x " , S_IRUSR , tsdata - > debug_dir , & tsdata - > num_x ) ;
debugfs_create_u16 ( " num_y " , S_IRUSR , tsdata - > debug_dir , & tsdata - > num_y ) ;
debugfs_create_file ( " mode " , S_IRUSR | S_IWUSR ,
tsdata - > debug_dir , tsdata , & debugfs_mode_fops ) ;
debugfs_create_file ( " raw_data " , S_IRUSR ,
tsdata - > debug_dir , tsdata , & debugfs_raw_data_fops ) ;
}
2012-11-23 21:50:47 -08:00
static void
2012-07-24 23:29:36 -07:00
edt_ft5x06_ts_teardown_debugfs ( struct edt_ft5x06_ts_data * tsdata )
{
2014-07-09 09:45:57 -07:00
debugfs_remove_recursive ( tsdata - > debug_dir ) ;
2012-08-21 22:01:45 -07:00
kfree ( tsdata - > raw_buffer ) ;
2012-07-24 23:29:36 -07:00
}
# else
static inline void
edt_ft5x06_ts_prepare_debugfs ( struct edt_ft5x06_ts_data * tsdata ,
const char * debugfs_name )
{
}
static inline void
edt_ft5x06_ts_teardown_debugfs ( struct edt_ft5x06_ts_data * tsdata )
{
}
# endif /* CONFIG_DEBUGFS */
2012-11-23 21:38:25 -08:00
static int edt_ft5x06_ts_identify ( struct i2c_client * client ,
2014-03-28 09:31:14 -07:00
struct edt_ft5x06_ts_data * tsdata ,
char * fw_version )
2012-07-24 23:29:36 -07:00
{
u8 rdbuf [ EDT_NAME_LEN ] ;
char * p ;
int error ;
2014-03-28 09:31:14 -07:00
char * model_name = tsdata - > name ;
2012-07-24 23:29:36 -07:00
2014-03-28 09:31:14 -07:00
/* see what we find if we assume it is a M06 *
* if we get less than EDT_NAME_LEN , we don ' t want
* to have garbage in there
*/
memset ( rdbuf , 0 , sizeof ( rdbuf ) ) ;
2017-10-09 21:00:16 -07:00
error = edt_ft5x06_ts_readwrite ( client , 1 , " \xBB " ,
2012-07-24 23:29:36 -07:00
EDT_NAME_LEN - 1 , rdbuf ) ;
if ( error )
return error ;
2017-10-09 21:00:16 -07:00
/* Probe content for something consistent.
* M06 starts with a response byte , M12 gives the data directly .
* M09 / Generic does not provide model number information .
2014-03-28 09:31:14 -07:00
*/
2017-10-09 21:00:16 -07:00
if ( ! strncasecmp ( rdbuf + 1 , " EP0 " , 3 ) ) {
2017-10-09 20:58:11 -07:00
tsdata - > version = EDT_M06 ;
2014-03-28 09:31:14 -07:00
/* remove last '$' end marker */
rdbuf [ EDT_NAME_LEN - 1 ] = ' \0 ' ;
if ( rdbuf [ EDT_NAME_LEN - 2 ] = = ' $ ' )
rdbuf [ EDT_NAME_LEN - 2 ] = ' \0 ' ;
/* look for Model/Version separator */
p = strchr ( rdbuf , ' * ' ) ;
if ( p )
* p + + = ' \0 ' ;
strlcpy ( model_name , rdbuf + 1 , EDT_NAME_LEN ) ;
strlcpy ( fw_version , p ? p : " " , EDT_NAME_LEN ) ;
2017-10-09 21:00:16 -07:00
} else if ( ! strncasecmp ( rdbuf , " EP0 " , 3 ) ) {
tsdata - > version = EDT_M12 ;
/* remove last '$' end marker */
rdbuf [ EDT_NAME_LEN - 2 ] = ' \0 ' ;
if ( rdbuf [ EDT_NAME_LEN - 3 ] = = ' $ ' )
rdbuf [ EDT_NAME_LEN - 3 ] = ' \0 ' ;
/* look for Model/Version separator */
p = strchr ( rdbuf , ' * ' ) ;
if ( p )
* p + + = ' \0 ' ;
strlcpy ( model_name , rdbuf , EDT_NAME_LEN ) ;
strlcpy ( fw_version , p ? p : " " , EDT_NAME_LEN ) ;
2014-03-28 09:31:14 -07:00
} else {
2017-10-09 21:00:16 -07:00
/* If it is not an EDT M06/M12 touchscreen, then the model
2017-10-09 20:58:11 -07:00
* detection is a bit hairy . The different ft5x06
* firmares around don ' t reliably implement the
* identification registers . Well , we ' ll take a shot .
*
* The main difference between generic focaltec based
* touches and EDT M09 is that we know how to retrieve
* the max coordinates for the latter .
*/
tsdata - > version = GENERIC_FT ;
2014-03-28 09:31:14 -07:00
error = edt_ft5x06_ts_readwrite ( client , 1 , " \xA6 " ,
2 , rdbuf ) ;
if ( error )
return error ;
2012-07-24 23:29:36 -07:00
2014-03-28 09:31:14 -07:00
strlcpy ( fw_version , rdbuf , 2 ) ;
2012-07-24 23:29:36 -07:00
2014-03-28 09:31:14 -07:00
error = edt_ft5x06_ts_readwrite ( client , 1 , " \xA8 " ,
1 , rdbuf ) ;
if ( error )
return error ;
2017-10-09 20:58:11 -07:00
/* This "model identification" is not exact. Unfortunately
* not all firmwares for the ft5x06 put useful values in
* the identification registers .
*/
switch ( rdbuf [ 0 ] ) {
case 0x35 : /* EDT EP0350M09 */
case 0x43 : /* EDT EP0430M09 */
case 0x50 : /* EDT EP0500M09 */
case 0x57 : /* EDT EP0570M09 */
case 0x70 : /* EDT EP0700M09 */
tsdata - > version = EDT_M09 ;
snprintf ( model_name , EDT_NAME_LEN , " EP0%i%i0M09 " ,
rdbuf [ 0 ] > > 4 , rdbuf [ 0 ] & 0x0F ) ;
break ;
case 0xa1 : /* EDT EP1010ML00 */
tsdata - > version = EDT_M09 ;
snprintf ( model_name , EDT_NAME_LEN , " EP%i%i0ML00 " ,
rdbuf [ 0 ] > > 4 , rdbuf [ 0 ] & 0x0F ) ;
break ;
case 0x5a : /* Solomon Goldentek Display */
snprintf ( model_name , EDT_NAME_LEN , " GKTW50SCED1R0 " ) ;
break ;
default :
snprintf ( model_name , EDT_NAME_LEN ,
" generic ft5x06 (%02x) " ,
rdbuf [ 0 ] ) ;
break ;
}
2014-03-28 09:31:14 -07:00
}
2012-07-24 23:29:36 -07:00
return 0 ;
}
2015-09-12 09:54:15 -07:00
static void edt_ft5x06_ts_get_defaults ( struct device * dev ,
2015-09-12 09:37:03 -07:00
struct edt_ft5x06_ts_data * tsdata )
2014-03-28 09:23:02 -07:00
{
2014-03-28 09:31:14 -07:00
struct edt_reg_addr * reg_addr = & tsdata - > reg_addr ;
2015-09-12 09:54:15 -07:00
u32 val ;
int error ;
error = device_property_read_u32 ( dev , " threshold " , & val ) ;
2016-02-09 09:32:42 -08:00
if ( ! error ) {
edt_ft5x06_register_write ( tsdata , reg_addr - > reg_threshold , val ) ;
tsdata - > threshold = val ;
}
2015-09-12 09:54:15 -07:00
error = device_property_read_u32 ( dev , " gain " , & val ) ;
2016-02-09 09:32:42 -08:00
if ( ! error ) {
edt_ft5x06_register_write ( tsdata , reg_addr - > reg_gain , val ) ;
tsdata - > gain = val ;
}
2014-03-28 09:31:14 -07:00
2015-09-12 09:54:15 -07:00
error = device_property_read_u32 ( dev , " offset " , & val ) ;
2016-02-09 09:32:42 -08:00
if ( ! error ) {
edt_ft5x06_register_write ( tsdata , reg_addr - > reg_offset , val ) ;
tsdata - > offset = val ;
}
2014-03-28 09:23:02 -07:00
}
2012-11-23 21:38:25 -08:00
static void
2012-07-24 23:29:36 -07:00
edt_ft5x06_ts_get_parameters ( struct edt_ft5x06_ts_data * tsdata )
{
2014-03-28 09:31:14 -07:00
struct edt_reg_addr * reg_addr = & tsdata - > reg_addr ;
2012-07-24 23:29:36 -07:00
tsdata - > threshold = edt_ft5x06_register_read ( tsdata ,
2014-03-28 09:31:14 -07:00
reg_addr - > reg_threshold ) ;
tsdata - > gain = edt_ft5x06_register_read ( tsdata , reg_addr - > reg_gain ) ;
tsdata - > offset = edt_ft5x06_register_read ( tsdata , reg_addr - > reg_offset ) ;
if ( reg_addr - > reg_report_rate ! = NO_REGISTER )
tsdata - > report_rate = edt_ft5x06_register_read ( tsdata ,
reg_addr - > reg_report_rate ) ;
2017-10-09 20:58:11 -07:00
if ( tsdata - > version = = EDT_M06 | |
2017-10-09 21:00:16 -07:00
tsdata - > version = = EDT_M09 | |
tsdata - > version = = EDT_M12 ) {
2017-10-09 20:58:11 -07:00
tsdata - > num_x = edt_ft5x06_register_read ( tsdata ,
reg_addr - > reg_num_x ) ;
tsdata - > num_y = edt_ft5x06_register_read ( tsdata ,
reg_addr - > reg_num_y ) ;
} else {
tsdata - > num_x = - 1 ;
tsdata - > num_y = - 1 ;
}
2014-03-28 09:31:14 -07:00
}
static void
edt_ft5x06_ts_set_regs ( struct edt_ft5x06_ts_data * tsdata )
{
struct edt_reg_addr * reg_addr = & tsdata - > reg_addr ;
switch ( tsdata - > version ) {
2017-10-09 20:58:11 -07:00
case EDT_M06 :
2014-03-28 09:31:14 -07:00
reg_addr - > reg_threshold = WORK_REGISTER_THRESHOLD ;
reg_addr - > reg_report_rate = WORK_REGISTER_REPORT_RATE ;
reg_addr - > reg_gain = WORK_REGISTER_GAIN ;
reg_addr - > reg_offset = WORK_REGISTER_OFFSET ;
reg_addr - > reg_num_x = WORK_REGISTER_NUM_X ;
reg_addr - > reg_num_y = WORK_REGISTER_NUM_Y ;
break ;
2017-10-09 20:58:11 -07:00
case EDT_M09 :
2017-10-09 21:00:16 -07:00
case EDT_M12 :
2014-03-28 09:31:14 -07:00
reg_addr - > reg_threshold = M09_REGISTER_THRESHOLD ;
2017-09-07 14:28:28 -07:00
reg_addr - > reg_report_rate = NO_REGISTER ;
2014-03-28 09:31:14 -07:00
reg_addr - > reg_gain = M09_REGISTER_GAIN ;
reg_addr - > reg_offset = M09_REGISTER_OFFSET ;
reg_addr - > reg_num_x = M09_REGISTER_NUM_X ;
reg_addr - > reg_num_y = M09_REGISTER_NUM_Y ;
break ;
2017-10-09 20:58:11 -07:00
case GENERIC_FT :
/* this is a guesswork */
reg_addr - > reg_threshold = M09_REGISTER_THRESHOLD ;
reg_addr - > reg_gain = M09_REGISTER_GAIN ;
reg_addr - > reg_offset = M09_REGISTER_OFFSET ;
break ;
2014-03-28 09:31:14 -07:00
}
2012-07-24 23:29:36 -07:00
}
2012-11-23 21:38:25 -08:00
static int edt_ft5x06_ts_probe ( struct i2c_client * client ,
2012-07-24 23:29:36 -07:00
const struct i2c_device_id * id )
{
2015-10-16 15:34:16 -07:00
const struct edt_i2c_chip_data * chip_data ;
2012-07-24 23:29:36 -07:00
struct edt_ft5x06_ts_data * tsdata ;
struct input_dev * input ;
2015-09-12 10:11:09 -07:00
unsigned long irq_flags ;
2012-07-24 23:29:36 -07:00
int error ;
char fw_version [ EDT_NAME_LEN ] ;
dev_dbg ( & client - > dev , " probing for EDT FT5x06 I2C \n " ) ;
2014-03-28 09:23:02 -07:00
tsdata = devm_kzalloc ( & client - > dev , sizeof ( * tsdata ) , GFP_KERNEL ) ;
if ( ! tsdata ) {
dev_err ( & client - > dev , " failed to allocate driver data. \n " ) ;
return - ENOMEM ;
}
2015-10-16 15:34:16 -07:00
chip_data = of_device_get_match_data ( & client - > dev ) ;
if ( ! chip_data )
chip_data = ( const struct edt_i2c_chip_data * ) id - > driver_data ;
if ( ! chip_data | | ! chip_data - > max_support_points ) {
dev_err ( & client - > dev , " invalid or missing chip data \n " ) ;
return - EINVAL ;
}
tsdata - > max_support_points = chip_data - > max_support_points ;
2015-09-11 17:30:34 -07:00
tsdata - > reset_gpio = devm_gpiod_get_optional ( & client - > dev ,
" reset " , GPIOD_OUT_HIGH ) ;
if ( IS_ERR ( tsdata - > reset_gpio ) ) {
error = PTR_ERR ( tsdata - > reset_gpio ) ;
dev_err ( & client - > dev ,
" Failed to request GPIO reset pin, error %d \n " , error ) ;
return error ;
2012-07-24 23:29:36 -07:00
}
2015-09-11 17:30:34 -07:00
tsdata - > wake_gpio = devm_gpiod_get_optional ( & client - > dev ,
" wake " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( tsdata - > wake_gpio ) ) {
error = PTR_ERR ( tsdata - > wake_gpio ) ;
dev_err ( & client - > dev ,
" Failed to request GPIO wake pin, error %d \n " , error ) ;
2012-07-24 23:29:36 -07:00
return error ;
2015-09-11 17:30:34 -07:00
}
2012-07-24 23:29:36 -07:00
2015-09-11 17:30:34 -07:00
if ( tsdata - > wake_gpio ) {
usleep_range ( 5000 , 6000 ) ;
gpiod_set_value_cansleep ( tsdata - > wake_gpio , 1 ) ;
}
if ( tsdata - > reset_gpio ) {
usleep_range ( 5000 , 6000 ) ;
gpiod_set_value_cansleep ( tsdata - > reset_gpio , 0 ) ;
msleep ( 300 ) ;
2012-07-24 23:29:36 -07:00
}
2014-01-16 16:26:55 -08:00
input = devm_input_allocate_device ( & client - > dev ) ;
if ( ! input ) {
dev_err ( & client - > dev , " failed to allocate input device. \n " ) ;
return - ENOMEM ;
2012-07-24 23:29:36 -07:00
}
mutex_init ( & tsdata - > mutex ) ;
tsdata - > client = client ;
tsdata - > input = input ;
tsdata - > factory_mode = false ;
2014-03-28 09:31:14 -07:00
error = edt_ft5x06_ts_identify ( client , tsdata , fw_version ) ;
2012-07-24 23:29:36 -07:00
if ( error ) {
dev_err ( & client - > dev , " touchscreen probe failed \n " ) ;
2014-01-16 16:26:55 -08:00
return error ;
2012-07-24 23:29:36 -07:00
}
2014-03-28 09:31:14 -07:00
edt_ft5x06_ts_set_regs ( tsdata ) ;
2015-09-12 09:54:15 -07:00
edt_ft5x06_ts_get_defaults ( & client - > dev , tsdata ) ;
2012-07-24 23:29:36 -07:00
edt_ft5x06_ts_get_parameters ( tsdata ) ;
dev_dbg ( & client - > dev ,
" Model \" %s \" , Rev. \" %s \" , %dx%d sensors \n " ,
tsdata - > name , fw_version , tsdata - > num_x , tsdata - > num_y ) ;
input - > name = tsdata - > name ;
input - > id . bustype = BUS_I2C ;
input - > dev . parent = & client - > dev ;
2017-10-09 20:58:11 -07:00
if ( tsdata - > version = = EDT_M06 | |
2017-10-09 21:00:16 -07:00
tsdata - > version = = EDT_M09 | |
tsdata - > version = = EDT_M12 ) {
2017-10-09 20:58:11 -07:00
input_set_abs_params ( input , ABS_MT_POSITION_X ,
0 , tsdata - > num_x * 64 - 1 , 0 , 0 ) ;
input_set_abs_params ( input , ABS_MT_POSITION_Y ,
0 , tsdata - > num_y * 64 - 1 , 0 , 0 ) ;
} else {
/* Unknown maximum values. Specify via devicetree */
input_set_abs_params ( input , ABS_MT_POSITION_X ,
0 , 65535 , 0 , 0 ) ;
input_set_abs_params ( input , ABS_MT_POSITION_Y ,
0 , 65535 , 0 , 0 ) ;
}
2015-03-21 20:18:06 -07:00
2016-07-15 14:26:53 -07:00
touchscreen_parse_properties ( input , true , & tsdata - > prop ) ;
2015-03-21 20:18:06 -07:00
2015-10-16 15:34:16 -07:00
error = input_mt_init_slots ( input , tsdata - > max_support_points ,
INPUT_MT_DIRECT ) ;
2012-07-24 23:29:36 -07:00
if ( error ) {
dev_err ( & client - > dev , " Unable to init MT slots. \n " ) ;
2014-01-16 16:26:55 -08:00
return error ;
2012-07-24 23:29:36 -07:00
}
i2c_set_clientdata ( client , tsdata ) ;
2015-09-12 10:11:09 -07:00
irq_flags = irq_get_trigger_type ( client - > irq ) ;
if ( irq_flags = = IRQF_TRIGGER_NONE )
irq_flags = IRQF_TRIGGER_FALLING ;
irq_flags | = IRQF_ONESHOT ;
error = devm_request_threaded_irq ( & client - > dev , client - > irq ,
NULL , edt_ft5x06_ts_isr , irq_flags ,
2014-03-28 09:23:02 -07:00
client - > name , tsdata ) ;
2012-07-24 23:29:36 -07:00
if ( error ) {
dev_err ( & client - > dev , " Unable to request touchscreen IRQ. \n " ) ;
2014-01-16 16:26:55 -08:00
return error ;
2012-07-24 23:29:36 -07:00
}
2017-09-29 16:42:06 -07:00
error = devm_device_add_group ( & client - > dev , & edt_ft5x06_attr_group ) ;
2012-07-24 23:29:36 -07:00
if ( error )
2014-01-16 16:26:55 -08:00
return error ;
2012-07-24 23:29:36 -07:00
error = input_register_device ( input ) ;
2014-03-28 09:23:02 -07:00
if ( error )
2017-09-29 16:42:06 -07:00
return error ;
2012-07-24 23:29:36 -07:00
edt_ft5x06_ts_prepare_debugfs ( tsdata , dev_driver_string ( & client - > dev ) ) ;
device_init_wakeup ( & client - > dev , 1 ) ;
dev_dbg ( & client - > dev ,
2014-03-28 09:23:02 -07:00
" EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d. \n " ,
2015-10-06 15:24:34 -07:00
client - > irq ,
tsdata - > wake_gpio ? desc_to_gpio ( tsdata - > wake_gpio ) : - 1 ,
tsdata - > reset_gpio ? desc_to_gpio ( tsdata - > reset_gpio ) : - 1 ) ;
2012-07-24 23:29:36 -07:00
return 0 ;
}
2012-11-23 21:50:47 -08:00
static int edt_ft5x06_ts_remove ( struct i2c_client * client )
2012-07-24 23:29:36 -07:00
{
struct edt_ft5x06_ts_data * tsdata = i2c_get_clientdata ( client ) ;
edt_ft5x06_ts_teardown_debugfs ( tsdata ) ;
return 0 ;
}
2014-11-02 00:04:14 -07:00
static int __maybe_unused edt_ft5x06_ts_suspend ( struct device * dev )
2012-07-24 23:29:36 -07:00
{
struct i2c_client * client = to_i2c_client ( dev ) ;
if ( device_may_wakeup ( dev ) )
enable_irq_wake ( client - > irq ) ;
return 0 ;
}
2014-11-02 00:04:14 -07:00
static int __maybe_unused edt_ft5x06_ts_resume ( struct device * dev )
2012-07-24 23:29:36 -07:00
{
struct i2c_client * client = to_i2c_client ( dev ) ;
if ( device_may_wakeup ( dev ) )
disable_irq_wake ( client - > irq ) ;
return 0 ;
}
static SIMPLE_DEV_PM_OPS ( edt_ft5x06_ts_pm_ops ,
edt_ft5x06_ts_suspend , edt_ft5x06_ts_resume ) ;
2015-10-16 15:34:16 -07:00
static const struct edt_i2c_chip_data edt_ft5x06_data = {
. max_support_points = 5 ,
} ;
2015-10-16 15:34:26 -07:00
static const struct edt_i2c_chip_data edt_ft5506_data = {
. max_support_points = 10 ,
} ;
2016-08-04 08:21:19 -07:00
static const struct edt_i2c_chip_data edt_ft6236_data = {
. max_support_points = 2 ,
} ;
2012-07-24 23:29:36 -07:00
static const struct i2c_device_id edt_ft5x06_ts_id [ ] = {
2015-10-16 15:34:16 -07:00
{ . name = " edt-ft5x06 " , . driver_data = ( long ) & edt_ft5x06_data } ,
2015-10-16 15:34:26 -07:00
{ . name = " edt-ft5506 " , . driver_data = ( long ) & edt_ft5506_data } ,
2016-08-04 08:21:19 -07:00
/* Note no edt- prefix for compatibility with the ft6236.c driver */
{ . name = " ft6236 " , . driver_data = ( long ) & edt_ft6236_data } ,
2014-03-28 09:20:08 -07:00
{ /* sentinel */ }
2012-07-24 23:29:36 -07:00
} ;
MODULE_DEVICE_TABLE ( i2c , edt_ft5x06_ts_id ) ;
2014-03-28 09:23:02 -07:00
# ifdef CONFIG_OF
static const struct of_device_id edt_ft5x06_of_match [ ] = {
2015-10-16 15:34:16 -07:00
{ . compatible = " edt,edt-ft5206 " , . data = & edt_ft5x06_data } ,
{ . compatible = " edt,edt-ft5306 " , . data = & edt_ft5x06_data } ,
{ . compatible = " edt,edt-ft5406 " , . data = & edt_ft5x06_data } ,
2015-10-16 15:34:26 -07:00
{ . compatible = " edt,edt-ft5506 " , . data = & edt_ft5506_data } ,
2016-08-04 08:21:19 -07:00
/* Note focaltech vendor prefix for compatibility with ft6236.c */
{ . compatible = " focaltech,ft6236 " , . data = & edt_ft6236_data } ,
2014-03-28 09:23:02 -07:00
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , edt_ft5x06_of_match ) ;
# endif
2012-07-24 23:29:36 -07:00
static struct i2c_driver edt_ft5x06_ts_driver = {
. driver = {
. name = " edt_ft5x06 " ,
2014-03-28 09:23:02 -07:00
. of_match_table = of_match_ptr ( edt_ft5x06_of_match ) ,
2012-07-24 23:29:36 -07:00
. pm = & edt_ft5x06_ts_pm_ops ,
} ,
. id_table = edt_ft5x06_ts_id ,
. probe = edt_ft5x06_ts_probe ,
2012-11-23 21:27:39 -08:00
. remove = edt_ft5x06_ts_remove ,
2012-07-24 23:29:36 -07:00
} ;
module_i2c_driver ( edt_ft5x06_ts_driver ) ;
MODULE_AUTHOR ( " Simon Budig <simon.budig@kernelconcepts.de> " ) ;
MODULE_DESCRIPTION ( " EDT FT5x06 I2C Touchscreen Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;