2012-01-31 12:18:00 +04:00
/*
* Core Source for :
* Cypress TrueTouch ( TM ) Standard Product ( TTSP ) touchscreen drivers .
* For use with Cypress Txx3xx parts .
* Supported parts include :
* CY8CTST341
* CY8CTMA340
*
* Copyright ( C ) 2009 , 2010 , 2011 Cypress Semiconductor , Inc .
* Copyright ( C ) 2012 Javier Martinez Canillas < javier @ dowhile0 . org >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* version 2 , and only version 2 , as published by the
* Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA .
*
* Contact Cypress Semiconductor at www . cypress . com < kev @ cypress . com >
*
*/
# include <linux/delay.h>
# include <linux/input.h>
# include <linux/input/mt.h>
2016-01-28 00:55:43 +03:00
# include <linux/input/touchscreen.h>
2012-01-31 12:18:00 +04:00
# include <linux/gpio.h>
# include <linux/interrupt.h>
# include <linux/slab.h>
2016-01-28 00:55:43 +03:00
# include <linux/property.h>
# include <linux/gpio/consumer.h>
2012-01-31 12:18:00 +04:00
# include "cyttsp_core.h"
/* Bootloader number of command keys */
# define CY_NUM_BL_KEYS 8
/* helpers */
# define GET_NUM_TOUCHES(x) ((x) & 0x0F)
# define IS_LARGE_AREA(x) (((x) & 0x10) >> 4)
# define IS_BAD_PKT(x) ((x) & 0x20)
# define IS_VALID_APP(x) ((x) & 0x01)
# define IS_OPERATIONAL_ERR(x) ((x) & 0x3F)
# define GET_HSTMODE(reg) (((reg) & 0x70) >> 4)
# define GET_BOOTLOADERMODE(reg) (((reg) & 0x10) >> 4)
# define CY_REG_BASE 0x00
# define CY_REG_ACT_DIST 0x1E
# define CY_REG_ACT_INTRVL 0x1D
# define CY_REG_TCH_TMOUT (CY_REG_ACT_INTRVL + 1)
# define CY_REG_LP_INTRVL (CY_REG_TCH_TMOUT + 1)
# define CY_MAXZ 255
# define CY_DELAY_DFLT 20 /* ms */
# define CY_DELAY_MAX 500
# define CY_ACT_DIST_DFLT 0xF8
2016-01-28 00:55:43 +03:00
# define CY_ACT_DIST_MASK 0x0F
2012-01-31 12:18:00 +04:00
# define CY_HNDSHK_BIT 0x80
/* device mode bits */
# define CY_OPERATE_MODE 0x00
# define CY_SYSINFO_MODE 0x10
/* power mode select bits */
# define CY_SOFT_RESET_MODE 0x01 /* return to Bootloader mode */
# define CY_DEEP_SLEEP_MODE 0x02
# define CY_LOW_POWER_MODE 0x04
/* Slots management */
# define CY_MAX_FINGER 4
# define CY_MAX_ID 16
static const u8 bl_command [ ] = {
0x00 , /* file offset */
0xFF , /* command */
0xA5 , /* exit bootloader command */
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 /* default keys */
} ;
static int ttsp_read_block_data ( struct cyttsp * ts , u8 command ,
u8 length , void * buf )
{
int error ;
int tries ;
for ( tries = 0 ; tries < CY_NUM_RETRY ; tries + + ) {
2013-07-01 05:46:56 +04:00
error = ts - > bus_ops - > read ( ts - > dev , ts - > xfer_buf , command ,
length , buf ) ;
2012-01-31 12:18:00 +04:00
if ( ! error )
return 0 ;
msleep ( CY_DELAY_DFLT ) ;
}
return - EIO ;
}
static int ttsp_write_block_data ( struct cyttsp * ts , u8 command ,
u8 length , void * buf )
{
int error ;
int tries ;
for ( tries = 0 ; tries < CY_NUM_RETRY ; tries + + ) {
2013-07-01 05:46:56 +04:00
error = ts - > bus_ops - > write ( ts - > dev , ts - > xfer_buf , command ,
length , buf ) ;
2012-01-31 12:18:00 +04:00
if ( ! error )
return 0 ;
msleep ( CY_DELAY_DFLT ) ;
}
return - EIO ;
}
static int ttsp_send_command ( struct cyttsp * ts , u8 cmd )
{
return ttsp_write_block_data ( ts , CY_REG_BASE , sizeof ( cmd ) , & cmd ) ;
}
2013-05-23 21:04:36 +04:00
static int cyttsp_handshake ( struct cyttsp * ts )
{
2016-01-28 00:55:43 +03:00
if ( ts - > use_hndshk )
2013-05-23 21:04:36 +04:00
return ttsp_send_command ( ts ,
ts - > xy_data . hst_mode ^ CY_HNDSHK_BIT ) ;
return 0 ;
}
2012-01-31 12:18:00 +04:00
static int cyttsp_load_bl_regs ( struct cyttsp * ts )
{
memset ( & ts - > bl_data , 0 , sizeof ( ts - > bl_data ) ) ;
ts - > bl_data . bl_status = 0x10 ;
return ttsp_read_block_data ( ts , CY_REG_BASE ,
sizeof ( ts - > bl_data ) , & ts - > bl_data ) ;
}
static int cyttsp_exit_bl_mode ( struct cyttsp * ts )
{
int error ;
u8 bl_cmd [ sizeof ( bl_command ) ] ;
memcpy ( bl_cmd , bl_command , sizeof ( bl_command ) ) ;
2016-01-28 00:55:43 +03:00
if ( ts - > bl_keys )
2012-01-31 12:18:00 +04:00
memcpy ( & bl_cmd [ sizeof ( bl_command ) - CY_NUM_BL_KEYS ] ,
2016-01-28 00:55:43 +03:00
ts - > bl_keys , CY_NUM_BL_KEYS ) ;
2012-01-31 12:18:00 +04:00
error = ttsp_write_block_data ( ts , CY_REG_BASE ,
sizeof ( bl_cmd ) , bl_cmd ) ;
if ( error )
return error ;
/* wait for TTSP Device to complete the operation */
msleep ( CY_DELAY_DFLT ) ;
error = cyttsp_load_bl_regs ( ts ) ;
if ( error )
return error ;
if ( GET_BOOTLOADERMODE ( ts - > bl_data . bl_status ) )
return - EIO ;
return 0 ;
}
static int cyttsp_set_operational_mode ( struct cyttsp * ts )
{
int error ;
error = ttsp_send_command ( ts , CY_OPERATE_MODE ) ;
if ( error )
return error ;
/* wait for TTSP Device to complete switch to Operational mode */
error = ttsp_read_block_data ( ts , CY_REG_BASE ,
sizeof ( ts - > xy_data ) , & ts - > xy_data ) ;
if ( error )
return error ;
2013-05-23 21:04:36 +04:00
error = cyttsp_handshake ( ts ) ;
if ( error )
return error ;
2012-01-31 12:18:00 +04:00
return ts - > xy_data . act_dist = = CY_ACT_DIST_DFLT ? - EIO : 0 ;
}
static int cyttsp_set_sysinfo_mode ( struct cyttsp * ts )
{
int error ;
memset ( & ts - > sysinfo_data , 0 , sizeof ( ts - > sysinfo_data ) ) ;
/* switch to sysinfo mode */
error = ttsp_send_command ( ts , CY_SYSINFO_MODE ) ;
if ( error )
return error ;
/* read sysinfo registers */
msleep ( CY_DELAY_DFLT ) ;
error = ttsp_read_block_data ( ts , CY_REG_BASE , sizeof ( ts - > sysinfo_data ) ,
& ts - > sysinfo_data ) ;
if ( error )
return error ;
2013-05-23 21:04:36 +04:00
error = cyttsp_handshake ( ts ) ;
if ( error )
return error ;
2012-01-31 12:18:00 +04:00
if ( ! ts - > sysinfo_data . tts_verh & & ! ts - > sysinfo_data . tts_verl )
return - EIO ;
return 0 ;
}
static int cyttsp_set_sysinfo_regs ( struct cyttsp * ts )
{
int retval = 0 ;
2016-01-28 00:55:43 +03:00
if ( ts - > act_intrvl ! = CY_ACT_INTRVL_DFLT | |
ts - > tch_tmout ! = CY_TCH_TMOUT_DFLT | |
ts - > lp_intrvl ! = CY_LP_INTRVL_DFLT ) {
2012-01-31 12:18:00 +04:00
u8 intrvl_ray [ ] = {
2016-01-28 00:55:43 +03:00
ts - > act_intrvl ,
ts - > tch_tmout ,
ts - > lp_intrvl
2012-01-31 12:18:00 +04:00
} ;
/* set intrvl registers */
retval = ttsp_write_block_data ( ts , CY_REG_ACT_INTRVL ,
sizeof ( intrvl_ray ) , intrvl_ray ) ;
msleep ( CY_DELAY_DFLT ) ;
}
return retval ;
}
2016-01-28 00:58:38 +03:00
static void cyttsp_hard_reset ( struct cyttsp * ts )
{
if ( ts - > reset_gpio ) {
gpiod_set_value_cansleep ( ts - > reset_gpio , 1 ) ;
msleep ( CY_DELAY_DFLT ) ;
gpiod_set_value_cansleep ( ts - > reset_gpio , 0 ) ;
msleep ( CY_DELAY_DFLT ) ;
}
}
2012-01-31 12:18:00 +04:00
static int cyttsp_soft_reset ( struct cyttsp * ts )
{
unsigned long timeout ;
int retval ;
/* wait for interrupt to set ready completion */
2013-11-15 02:32:02 +04:00
reinit_completion ( & ts - > bl_ready ) ;
2012-01-31 12:18:00 +04:00
ts - > state = CY_BL_STATE ;
enable_irq ( ts - > irq ) ;
retval = ttsp_send_command ( ts , CY_SOFT_RESET_MODE ) ;
if ( retval )
goto out ;
timeout = wait_for_completion_timeout ( & ts - > bl_ready ,
msecs_to_jiffies ( CY_DELAY_DFLT * CY_DELAY_MAX ) ) ;
retval = timeout ? 0 : - EIO ;
out :
ts - > state = CY_IDLE_STATE ;
disable_irq ( ts - > irq ) ;
return retval ;
}
static int cyttsp_act_dist_setup ( struct cyttsp * ts )
{
2016-01-28 00:55:43 +03:00
u8 act_dist_setup = ts - > act_dist ;
2012-01-31 12:18:00 +04:00
/* Init gesture; active distance setup */
return ttsp_write_block_data ( ts , CY_REG_ACT_DIST ,
sizeof ( act_dist_setup ) , & act_dist_setup ) ;
}
static void cyttsp_extract_track_ids ( struct cyttsp_xydata * xy_data , int * ids )
{
ids [ 0 ] = xy_data - > touch12_id > > 4 ;
ids [ 1 ] = xy_data - > touch12_id & 0xF ;
ids [ 2 ] = xy_data - > touch34_id > > 4 ;
ids [ 3 ] = xy_data - > touch34_id & 0xF ;
}
static const struct cyttsp_tch * cyttsp_get_tch ( struct cyttsp_xydata * xy_data ,
int idx )
{
switch ( idx ) {
case 0 :
return & xy_data - > tch1 ;
case 1 :
return & xy_data - > tch2 ;
case 2 :
return & xy_data - > tch3 ;
case 3 :
return & xy_data - > tch4 ;
default :
return NULL ;
}
}
static void cyttsp_report_tchdata ( struct cyttsp * ts )
{
struct cyttsp_xydata * xy_data = & ts - > xy_data ;
struct input_dev * input = ts - > input ;
int num_tch = GET_NUM_TOUCHES ( xy_data - > tt_stat ) ;
const struct cyttsp_tch * tch ;
int ids [ CY_MAX_ID ] ;
int i ;
DECLARE_BITMAP ( used , CY_MAX_ID ) ;
if ( IS_LARGE_AREA ( xy_data - > tt_stat ) = = 1 ) {
/* terminate all active tracks */
num_tch = 0 ;
dev_dbg ( ts - > dev , " %s: Large area detected \n " , __func__ ) ;
} else if ( num_tch > CY_MAX_FINGER ) {
/* terminate all active tracks */
num_tch = 0 ;
dev_dbg ( ts - > dev , " %s: Num touch error detected \n " , __func__ ) ;
} else if ( IS_BAD_PKT ( xy_data - > tt_mode ) ) {
/* terminate all active tracks */
num_tch = 0 ;
dev_dbg ( ts - > dev , " %s: Invalid buffer detected \n " , __func__ ) ;
}
cyttsp_extract_track_ids ( xy_data , ids ) ;
bitmap_zero ( used , CY_MAX_ID ) ;
for ( i = 0 ; i < num_tch ; i + + ) {
tch = cyttsp_get_tch ( xy_data , i ) ;
input_mt_slot ( input , ids [ i ] ) ;
input_mt_report_slot_state ( input , MT_TOOL_FINGER , true ) ;
input_report_abs ( input , ABS_MT_POSITION_X , be16_to_cpu ( tch - > x ) ) ;
input_report_abs ( input , ABS_MT_POSITION_Y , be16_to_cpu ( tch - > y ) ) ;
input_report_abs ( input , ABS_MT_TOUCH_MAJOR , tch - > z ) ;
__set_bit ( ids [ i ] , used ) ;
}
for ( i = 0 ; i < CY_MAX_ID ; i + + ) {
if ( test_bit ( i , used ) )
continue ;
input_mt_slot ( input , i ) ;
input_mt_report_slot_state ( input , MT_TOOL_FINGER , false ) ;
}
input_sync ( input ) ;
}
static irqreturn_t cyttsp_irq ( int irq , void * handle )
{
struct cyttsp * ts = handle ;
int error ;
if ( unlikely ( ts - > state = = CY_BL_STATE ) ) {
complete ( & ts - > bl_ready ) ;
goto out ;
}
/* Get touch data from CYTTSP device */
error = ttsp_read_block_data ( ts , CY_REG_BASE ,
sizeof ( struct cyttsp_xydata ) , & ts - > xy_data ) ;
if ( error )
goto out ;
/* provide flow control handshake */
2013-05-23 21:04:36 +04:00
error = cyttsp_handshake ( ts ) ;
if ( error )
goto out ;
2012-01-31 12:18:00 +04:00
if ( unlikely ( ts - > state = = CY_IDLE_STATE ) )
goto out ;
if ( GET_BOOTLOADERMODE ( ts - > xy_data . tt_mode ) ) {
/*
* TTSP device has reset back to bootloader mode .
* Restore to operational mode .
*/
error = cyttsp_exit_bl_mode ( ts ) ;
if ( error ) {
dev_err ( ts - > dev ,
" Could not return to operational mode, err: %d \n " ,
error ) ;
ts - > state = CY_IDLE_STATE ;
}
} else {
cyttsp_report_tchdata ( ts ) ;
}
out :
return IRQ_HANDLED ;
}
static int cyttsp_power_on ( struct cyttsp * ts )
{
int error ;
error = cyttsp_soft_reset ( ts ) ;
if ( error )
return error ;
error = cyttsp_load_bl_regs ( ts ) ;
if ( error )
return error ;
if ( GET_BOOTLOADERMODE ( ts - > bl_data . bl_status ) & &
IS_VALID_APP ( ts - > bl_data . bl_status ) ) {
error = cyttsp_exit_bl_mode ( ts ) ;
if ( error )
return error ;
}
if ( GET_HSTMODE ( ts - > bl_data . bl_file ) ! = CY_OPERATE_MODE | |
IS_OPERATIONAL_ERR ( ts - > bl_data . bl_status ) ) {
return - ENODEV ;
}
error = cyttsp_set_sysinfo_mode ( ts ) ;
if ( error )
return error ;
error = cyttsp_set_sysinfo_regs ( ts ) ;
if ( error )
return error ;
error = cyttsp_set_operational_mode ( ts ) ;
if ( error )
return error ;
/* init active distance */
error = cyttsp_act_dist_setup ( ts ) ;
if ( error )
return error ;
ts - > state = CY_ACTIVE_STATE ;
return 0 ;
}
static int cyttsp_enable ( struct cyttsp * ts )
{
int error ;
/*
* The device firmware can wake on an I2C or SPI memory slave
* address match . So just reading a register is sufficient to
* wake up the device . The first read attempt will fail but it
* will wake it up making the second read attempt successful .
*/
error = ttsp_read_block_data ( ts , CY_REG_BASE ,
sizeof ( ts - > xy_data ) , & ts - > xy_data ) ;
if ( error )
return error ;
if ( GET_HSTMODE ( ts - > xy_data . hst_mode ) )
return - EIO ;
enable_irq ( ts - > irq ) ;
return 0 ;
}
static int cyttsp_disable ( struct cyttsp * ts )
{
int error ;
error = ttsp_send_command ( ts , CY_LOW_POWER_MODE ) ;
if ( error )
return error ;
disable_irq ( ts - > irq ) ;
return 0 ;
}
2014-11-02 10:04:14 +03:00
static int __maybe_unused cyttsp_suspend ( struct device * dev )
2012-01-31 12:18:00 +04:00
{
struct cyttsp * ts = dev_get_drvdata ( dev ) ;
int retval = 0 ;
mutex_lock ( & ts - > input - > mutex ) ;
if ( ts - > input - > users ) {
retval = cyttsp_disable ( ts ) ;
if ( retval = = 0 )
ts - > suspended = true ;
}
mutex_unlock ( & ts - > input - > mutex ) ;
return retval ;
}
2014-11-02 10:04:14 +03:00
static int __maybe_unused cyttsp_resume ( struct device * dev )
2012-01-31 12:18:00 +04:00
{
struct cyttsp * ts = dev_get_drvdata ( dev ) ;
mutex_lock ( & ts - > input - > mutex ) ;
if ( ts - > input - > users )
cyttsp_enable ( ts ) ;
ts - > suspended = false ;
mutex_unlock ( & ts - > input - > mutex ) ;
return 0 ;
}
SIMPLE_DEV_PM_OPS ( cyttsp_pm_ops , cyttsp_suspend , cyttsp_resume ) ;
EXPORT_SYMBOL_GPL ( cyttsp_pm_ops ) ;
static int cyttsp_open ( struct input_dev * dev )
{
struct cyttsp * ts = input_get_drvdata ( dev ) ;
int retval = 0 ;
if ( ! ts - > suspended )
retval = cyttsp_enable ( ts ) ;
return retval ;
}
static void cyttsp_close ( struct input_dev * dev )
{
struct cyttsp * ts = input_get_drvdata ( dev ) ;
if ( ! ts - > suspended )
cyttsp_disable ( ts ) ;
}
2016-01-28 00:55:43 +03:00
static int cyttsp_parse_properties ( struct cyttsp * ts )
2016-01-28 00:53:33 +03:00
{
2016-01-28 00:55:43 +03:00
struct device * dev = ts - > dev ;
u32 dt_value ;
int ret ;
ts - > bl_keys = devm_kzalloc ( dev , CY_NUM_BL_KEYS , GFP_KERNEL ) ;
if ( ! ts - > bl_keys )
return - ENOMEM ;
/* Set some default values */
ts - > use_hndshk = false ;
ts - > act_dist = CY_ACT_DIST_DFLT ;
ts - > act_intrvl = CY_ACT_INTRVL_DFLT ;
ts - > tch_tmout = CY_TCH_TMOUT_DFLT ;
ts - > lp_intrvl = CY_LP_INTRVL_DFLT ;
ret = device_property_read_u8_array ( dev , " bootloader-key " ,
ts - > bl_keys , CY_NUM_BL_KEYS ) ;
if ( ret ) {
dev_err ( dev ,
" bootloader-key property could not be retrieved \n " ) ;
return ret ;
}
ts - > use_hndshk = device_property_present ( dev , " use-handshake " ) ;
if ( ! device_property_read_u32 ( dev , " active-distance " , & dt_value ) ) {
if ( dt_value > 15 ) {
dev_err ( dev , " active-distance (%u) must be [0-15] \n " ,
dt_value ) ;
return - EINVAL ;
}
ts - > act_dist & = ~ CY_ACT_DIST_MASK ;
ts - > act_dist | = dt_value ;
}
if ( ! device_property_read_u32 ( dev , " active-interval-ms " , & dt_value ) ) {
if ( dt_value > 255 ) {
dev_err ( dev , " active-interval-ms (%u) must be [0-255] \n " ,
dt_value ) ;
return - EINVAL ;
}
ts - > act_intrvl = dt_value ;
}
2016-01-28 00:53:33 +03:00
2016-01-28 00:55:43 +03:00
if ( ! device_property_read_u32 ( dev , " lowpower-interval-ms " , & dt_value ) ) {
if ( dt_value > 2550 ) {
dev_err ( dev , " lowpower-interval-ms (%u) must be [0-2550] \n " ,
dt_value ) ;
return - EINVAL ;
}
/* Register value is expressed in 0.01s / bit */
ts - > lp_intrvl = dt_value / 10 ;
}
if ( ! device_property_read_u32 ( dev , " touch-timeout-ms " , & dt_value ) ) {
if ( dt_value > 2550 ) {
dev_err ( dev , " touch-timeout-ms (%u) must be [0-2550] \n " ,
dt_value ) ;
return - EINVAL ;
}
/* Register value is expressed in 0.01s / bit */
ts - > tch_tmout = dt_value / 10 ;
}
return 0 ;
2016-01-28 00:53:33 +03:00
}
2012-01-31 12:18:00 +04:00
struct cyttsp * cyttsp_probe ( const struct cyttsp_bus_ops * bus_ops ,
struct device * dev , int irq , size_t xfer_buf_size )
{
struct cyttsp * ts ;
struct input_dev * input_dev ;
int error ;
2016-01-28 00:53:33 +03:00
ts = devm_kzalloc ( dev , sizeof ( * ts ) + xfer_buf_size , GFP_KERNEL ) ;
if ( ! ts )
return ERR_PTR ( - ENOMEM ) ;
input_dev = devm_input_allocate_device ( dev ) ;
if ( ! input_dev )
return ERR_PTR ( - ENOMEM ) ;
2012-01-31 12:18:00 +04:00
ts - > dev = dev ;
ts - > input = input_dev ;
ts - > bus_ops = bus_ops ;
ts - > irq = irq ;
2016-01-28 00:55:43 +03:00
ts - > reset_gpio = devm_gpiod_get_optional ( dev , " reset " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( ts - > reset_gpio ) ) {
error = PTR_ERR ( ts - > reset_gpio ) ;
dev_err ( dev , " Failed to request reset gpio, error %d \n " , error ) ;
2016-01-28 00:53:33 +03:00
return ERR_PTR ( error ) ;
}
2016-01-28 00:55:43 +03:00
error = cyttsp_parse_properties ( ts ) ;
if ( error )
return ERR_PTR ( error ) ;
init_completion ( & ts - > bl_ready ) ;
snprintf ( ts - > phys , sizeof ( ts - > phys ) , " %s/input0 " , dev_name ( dev ) ) ;
2012-01-31 12:18:00 +04:00
2016-01-28 00:55:43 +03:00
input_dev - > name = " Cypress TTSP TouchScreen " ;
2012-01-31 12:18:00 +04:00
input_dev - > phys = ts - > phys ;
input_dev - > id . bustype = bus_ops - > bustype ;
input_dev - > dev . parent = ts - > dev ;
input_dev - > open = cyttsp_open ;
input_dev - > close = cyttsp_close ;
input_set_drvdata ( input_dev , ts ) ;
2016-01-28 00:55:43 +03:00
input_set_capability ( input_dev , EV_ABS , ABS_MT_POSITION_X ) ;
input_set_capability ( input_dev , EV_ABS , ABS_MT_POSITION_Y ) ;
2016-07-16 00:05:29 +03:00
touchscreen_parse_properties ( input_dev , true , NULL ) ;
2012-01-31 12:18:00 +04:00
2016-01-28 00:55:20 +03:00
error = input_mt_init_slots ( input_dev , CY_MAX_ID , 0 ) ;
if ( error ) {
dev_err ( dev , " Unable to init MT slots. \n " ) ;
return ERR_PTR ( error ) ;
}
2012-01-31 12:18:00 +04:00
2016-01-28 00:53:33 +03:00
error = devm_request_threaded_irq ( dev , ts - > irq , NULL , cyttsp_irq ,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT ,
2016-01-28 00:55:43 +03:00
" cyttsp " , ts ) ;
2012-01-31 12:18:00 +04:00
if ( error ) {
dev_err ( ts - > dev , " failed to request IRQ %d, err: %d \n " ,
ts - > irq , error ) ;
2016-01-28 00:53:33 +03:00
return ERR_PTR ( error ) ;
2012-01-31 12:18:00 +04:00
}
disable_irq ( ts - > irq ) ;
2016-01-28 00:58:38 +03:00
cyttsp_hard_reset ( ts ) ;
2012-01-31 12:18:00 +04:00
error = cyttsp_power_on ( ts ) ;
if ( error )
2016-01-28 00:53:33 +03:00
return ERR_PTR ( error ) ;
2012-01-31 12:18:00 +04:00
error = input_register_device ( input_dev ) ;
if ( error ) {
dev_err ( ts - > dev , " failed to register input device: %d \n " ,
error ) ;
2016-01-28 00:53:33 +03:00
return ERR_PTR ( error ) ;
2012-01-31 12:18:00 +04:00
}
return ts ;
}
EXPORT_SYMBOL_GPL ( cyttsp_probe ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Cypress TrueTouch(R) Standard touchscreen driver core " ) ;
MODULE_AUTHOR ( " Cypress " ) ;