2012-03-04 20:11:57 +04:00
/*
* TI Touch Screen driver
*
* Copyright ( C ) 2011 Texas Instruments Incorporated - http : //www.ti.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 version 2.
*
* This program is distributed " as is " WITHOUT ANY WARRANTY of any
* kind , whether express or implied ; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <linux/err.h>
# include <linux/module.h>
# include <linux/input.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/clk.h>
# include <linux/platform_device.h>
# include <linux/io.h>
# include <linux/delay.h>
2013-01-24 07:45:10 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
2015-02-03 22:47:05 +03:00
# include <linux/sort.h>
2012-03-04 20:11:57 +04:00
2012-10-16 11:25:44 +04:00
# include <linux/mfd/ti_am335x_tscadc.h>
2012-10-16 11:25:38 +04:00
# define ADCFSM_STEPID 0x10
2012-03-04 20:11:57 +04:00
# define SEQ_SETTLE 275
# define MAX_12BIT ((1 << 12) - 1)
2013-01-24 07:45:06 +04:00
static const int config_pins [ ] = {
STEPCONFIG_XPP ,
STEPCONFIG_XNN ,
STEPCONFIG_YPP ,
STEPCONFIG_YNN ,
} ;
2012-10-16 11:25:42 +04:00
struct titsc {
2012-03-04 20:11:57 +04:00
struct input_dev * input ;
2012-10-16 11:25:44 +04:00
struct ti_tscadc_dev * mfd_tscadc ;
2012-03-04 20:11:57 +04:00
unsigned int irq ;
unsigned int wires ;
unsigned int x_plate_resistance ;
bool pen_down ;
2013-01-24 07:45:10 +04:00
int coordinate_readouts ;
2013-01-24 07:45:06 +04:00
u32 config_inp [ 4 ] ;
u32 bit_xp , bit_xn , bit_yp , bit_yn ;
u32 inp_xp , inp_xn , inp_yp , inp_yn ;
2013-09-19 10:24:00 +04:00
u32 step_mask ;
2015-02-03 22:45:34 +03:00
u32 charge_delay ;
2012-03-04 20:11:57 +04:00
} ;
2012-10-16 11:25:42 +04:00
static unsigned int titsc_readl ( struct titsc * ts , unsigned int reg )
2012-03-04 20:11:57 +04:00
{
2012-10-16 11:25:44 +04:00
return readl ( ts - > mfd_tscadc - > tscadc_base + reg ) ;
2012-03-04 20:11:57 +04:00
}
2012-10-16 11:25:42 +04:00
static void titsc_writel ( struct titsc * tsc , unsigned int reg ,
2012-03-04 20:11:57 +04:00
unsigned int val )
{
2012-10-16 11:25:44 +04:00
writel ( val , tsc - > mfd_tscadc - > tscadc_base + reg ) ;
2012-03-04 20:11:57 +04:00
}
2013-01-24 07:45:06 +04:00
static int titsc_config_wires ( struct titsc * ts_dev )
{
u32 analog_line [ 4 ] ;
u32 wire_order [ 4 ] ;
int i , bit_cfg ;
for ( i = 0 ; i < 4 ; i + + ) {
/*
* Get the order in which TSC wires are attached
* w . r . t . each of the analog input lines on the EVM .
*/
analog_line [ i ] = ( ts_dev - > config_inp [ i ] & 0xF0 ) > > 4 ;
wire_order [ i ] = ts_dev - > config_inp [ i ] & 0x0F ;
if ( WARN_ON ( analog_line [ i ] > 7 ) )
return - EINVAL ;
if ( WARN_ON ( wire_order [ i ] > ARRAY_SIZE ( config_pins ) ) )
return - EINVAL ;
}
for ( i = 0 ; i < 4 ; i + + ) {
int an_line ;
int wi_order ;
an_line = analog_line [ i ] ;
wi_order = wire_order [ i ] ;
bit_cfg = config_pins [ wi_order ] ;
if ( bit_cfg = = 0 )
return - EINVAL ;
switch ( wi_order ) {
case 0 :
ts_dev - > bit_xp = bit_cfg ;
ts_dev - > inp_xp = an_line ;
break ;
case 1 :
ts_dev - > bit_xn = bit_cfg ;
ts_dev - > inp_xn = an_line ;
break ;
case 2 :
ts_dev - > bit_yp = bit_cfg ;
ts_dev - > inp_yp = an_line ;
break ;
case 3 :
ts_dev - > bit_yn = bit_cfg ;
ts_dev - > inp_yn = an_line ;
break ;
}
}
return 0 ;
}
2012-10-16 11:25:42 +04:00
static void titsc_step_config ( struct titsc * ts_dev )
2012-03-04 20:11:57 +04:00
{
unsigned int config ;
2013-05-29 16:46:21 +04:00
int i ;
2015-02-03 22:41:58 +03:00
int end_step , first_step , tsc_steps ;
2013-05-29 16:46:21 +04:00
u32 stepenable ;
2012-03-04 20:11:57 +04:00
config = STEPCONFIG_MODE_HWSYNC |
2013-01-24 07:45:06 +04:00
STEPCONFIG_AVG_16 | ts_dev - > bit_xp ;
2012-03-04 20:11:57 +04:00
switch ( ts_dev - > wires ) {
case 4 :
2013-01-24 07:45:06 +04:00
config | = STEPCONFIG_INP ( ts_dev - > inp_yp ) | ts_dev - > bit_xn ;
2012-03-04 20:11:57 +04:00
break ;
case 5 :
2013-01-24 07:45:06 +04:00
config | = ts_dev - > bit_yn |
STEPCONFIG_INP_AN4 | ts_dev - > bit_xn |
ts_dev - > bit_yp ;
2012-03-04 20:11:57 +04:00
break ;
case 8 :
2013-01-24 07:45:06 +04:00
config | = STEPCONFIG_INP ( ts_dev - > inp_yp ) | ts_dev - > bit_xn ;
2012-03-04 20:11:57 +04:00
break ;
}
2015-02-03 22:41:58 +03:00
tsc_steps = ts_dev - > coordinate_readouts * 2 + 2 ;
first_step = TOTAL_STEPS - tsc_steps ;
/* Steps 16 to 16-coordinate_readouts is for X */
end_step = first_step + tsc_steps ;
for ( i = end_step - ts_dev - > coordinate_readouts ; i < end_step ; i + + ) {
2012-10-16 11:25:42 +04:00
titsc_writel ( ts_dev , REG_STEPCONFIG ( i ) , config ) ;
titsc_writel ( ts_dev , REG_STEPDELAY ( i ) , STEPCONFIG_OPENDLY ) ;
2012-03-04 20:11:57 +04:00
}
config = 0 ;
config = STEPCONFIG_MODE_HWSYNC |
2013-01-24 07:45:06 +04:00
STEPCONFIG_AVG_16 | ts_dev - > bit_yn |
2013-05-29 16:46:21 +04:00
STEPCONFIG_INM_ADCREFM ;
2012-03-04 20:11:57 +04:00
switch ( ts_dev - > wires ) {
case 4 :
2013-01-24 07:45:06 +04:00
config | = ts_dev - > bit_yp | STEPCONFIG_INP ( ts_dev - > inp_xp ) ;
2012-03-04 20:11:57 +04:00
break ;
case 5 :
2013-01-24 07:45:06 +04:00
config | = ts_dev - > bit_xp | STEPCONFIG_INP_AN4 |
2017-10-19 03:25:52 +03:00
STEPCONFIG_XNP | STEPCONFIG_YPN ;
2012-03-04 20:11:57 +04:00
break ;
case 8 :
2013-01-24 07:45:06 +04:00
config | = ts_dev - > bit_yp | STEPCONFIG_INP ( ts_dev - > inp_xp ) ;
2012-03-04 20:11:57 +04:00
break ;
}
2015-02-03 22:41:58 +03:00
/* 1 ... coordinate_readouts is for Y */
end_step = first_step + ts_dev - > coordinate_readouts ;
for ( i = first_step ; i < end_step ; i + + ) {
2012-10-16 11:25:42 +04:00
titsc_writel ( ts_dev , REG_STEPCONFIG ( i ) , config ) ;
titsc_writel ( ts_dev , REG_STEPDELAY ( i ) , STEPCONFIG_OPENDLY ) ;
2012-03-04 20:11:57 +04:00
}
2015-02-03 22:44:12 +03:00
/* Make CHARGECONFIG same as IDLECONFIG */
2012-03-04 20:11:57 +04:00
2015-02-03 22:44:12 +03:00
config = titsc_readl ( ts_dev , REG_IDLECONFIG ) ;
2012-10-16 11:25:42 +04:00
titsc_writel ( ts_dev , REG_CHARGECONFIG , config ) ;
2015-02-03 22:45:34 +03:00
titsc_writel ( ts_dev , REG_CHARGEDELAY , ts_dev - > charge_delay ) ;
2012-03-04 20:11:57 +04:00
2015-02-03 22:41:58 +03:00
/* coordinate_readouts + 1 ... coordinate_readouts + 2 is for Z */
2012-03-04 20:11:57 +04:00
config = STEPCONFIG_MODE_HWSYNC |
2013-01-24 07:45:06 +04:00
STEPCONFIG_AVG_16 | ts_dev - > bit_yp |
ts_dev - > bit_xn | STEPCONFIG_INM_ADCREFM |
STEPCONFIG_INP ( ts_dev - > inp_xp ) ;
2013-05-29 16:46:21 +04:00
titsc_writel ( ts_dev , REG_STEPCONFIG ( end_step ) , config ) ;
titsc_writel ( ts_dev , REG_STEPDELAY ( end_step ) ,
2012-10-16 11:25:39 +04:00
STEPCONFIG_OPENDLY ) ;
2012-03-04 20:11:57 +04:00
2013-05-29 16:46:21 +04:00
end_step + + ;
config | = STEPCONFIG_INP ( ts_dev - > inp_yn ) ;
titsc_writel ( ts_dev , REG_STEPCONFIG ( end_step ) , config ) ;
titsc_writel ( ts_dev , REG_STEPDELAY ( end_step ) ,
2012-10-16 11:25:39 +04:00
STEPCONFIG_OPENDLY ) ;
2012-03-04 20:11:57 +04:00
2015-02-03 22:41:58 +03:00
/* The steps end ... end - readouts * 2 + 2 and bit 0 for TS_Charge */
stepenable = 1 ;
for ( i = 0 ; i < tsc_steps ; i + + )
stepenable | = 1 < < ( first_step + i + 1 ) ;
2013-09-19 10:24:00 +04:00
ts_dev - > step_mask = stepenable ;
2013-12-19 19:28:29 +04:00
am335x_tsc_se_set_cache ( ts_dev - > mfd_tscadc , ts_dev - > step_mask ) ;
2012-03-04 20:11:57 +04:00
}
2015-02-03 22:47:05 +03:00
static int titsc_cmp_coord ( const void * a , const void * b )
{
return * ( int * ) a - * ( int * ) b ;
}
2012-10-16 11:25:42 +04:00
static void titsc_read_coordinates ( struct titsc * ts_dev ,
2013-05-29 16:46:21 +04:00
u32 * x , u32 * y , u32 * z1 , u32 * z2 )
2012-03-04 20:11:57 +04:00
{
2015-02-03 22:47:05 +03:00
unsigned int yvals [ 7 ] , xvals [ 7 ] ;
unsigned int i , xsum = 0 , ysum = 0 ;
2013-05-29 16:46:21 +04:00
unsigned int creads = ts_dev - > coordinate_readouts ;
2012-03-04 20:11:57 +04:00
2015-02-03 22:47:05 +03:00
for ( i = 0 ; i < creads ; i + + ) {
yvals [ i ] = titsc_readl ( ts_dev , REG_FIFO0 ) ;
yvals [ i ] & = 0xfff ;
}
2012-03-04 20:11:57 +04:00
2015-02-03 22:47:05 +03:00
* z1 = titsc_readl ( ts_dev , REG_FIFO0 ) ;
* z1 & = 0xfff ;
* z2 = titsc_readl ( ts_dev , REG_FIFO0 ) ;
* z2 & = 0xfff ;
2015-02-03 22:41:58 +03:00
2015-02-03 22:47:05 +03:00
for ( i = 0 ; i < creads ; i + + ) {
xvals [ i ] = titsc_readl ( ts_dev , REG_FIFO0 ) ;
xvals [ i ] & = 0xfff ;
}
2015-02-03 22:41:58 +03:00
2015-02-03 22:47:05 +03:00
/*
* If co - ordinates readouts is less than 4 then
* report the average . In case of 4 or more
* readouts , sort the co - ordinate samples , drop
* min and max values and report the average of
* remaining values .
*/
if ( creads < = 3 ) {
for ( i = 0 ; i < creads ; i + + ) {
ysum + = yvals [ i ] ;
xsum + = xvals [ i ] ;
2012-03-04 20:11:57 +04:00
}
2015-02-03 22:47:05 +03:00
ysum / = creads ;
xsum / = creads ;
} else {
sort ( yvals , creads , sizeof ( unsigned int ) ,
titsc_cmp_coord , NULL ) ;
sort ( xvals , creads , sizeof ( unsigned int ) ,
titsc_cmp_coord , NULL ) ;
for ( i = 1 ; i < creads - 1 ; i + + ) {
ysum + = yvals [ i ] ;
xsum + = xvals [ i ] ;
}
ysum / = creads - 2 ;
xsum / = creads - 2 ;
2012-03-04 20:11:57 +04:00
}
2015-02-03 22:47:05 +03:00
* y = ysum ;
* x = xsum ;
2012-03-04 20:11:57 +04:00
}
2012-10-16 11:25:42 +04:00
static irqreturn_t titsc_irq ( int irq , void * dev )
2012-03-04 20:11:57 +04:00
{
2012-10-16 11:25:42 +04:00
struct titsc * ts_dev = dev ;
2012-03-04 20:11:57 +04:00
struct input_dev * input_dev = ts_dev - > input ;
2015-02-03 22:44:12 +03:00
unsigned int fsm , status , irqclr = 0 ;
2012-03-04 20:11:57 +04:00
unsigned int x = 0 , y = 0 ;
unsigned int z1 , z2 , z ;
2015-02-03 22:44:12 +03:00
status = titsc_readl ( ts_dev , REG_RAWIRQSTATUS ) ;
if ( status & IRQENB_HW_PEN ) {
ts_dev - > pen_down = true ;
irqclr | = IRQENB_HW_PEN ;
}
if ( status & IRQENB_PENUP ) {
fsm = titsc_readl ( ts_dev , REG_ADCFSM ) ;
if ( fsm = = ADCFSM_STEPID ) {
ts_dev - > pen_down = false ;
input_report_key ( input_dev , BTN_TOUCH , 0 ) ;
input_report_abs ( input_dev , ABS_PRESSURE , 0 ) ;
input_sync ( input_dev ) ;
} else {
ts_dev - > pen_down = true ;
}
irqclr | = IRQENB_PENUP ;
}
if ( status & IRQENB_EOS )
irqclr | = IRQENB_EOS ;
2013-09-19 10:24:00 +04:00
/*
* ADC and touchscreen share the IRQ line .
* FIFO1 interrupts are used by ADC . Handle FIFO0 IRQs here only
*/
2012-10-16 11:25:40 +04:00
if ( status & IRQENB_FIFO0THRES ) {
2012-03-04 20:11:57 +04:00
2013-05-29 16:46:21 +04:00
titsc_read_coordinates ( ts_dev , & x , & y , & z1 , & z2 ) ;
2012-10-16 11:25:44 +04:00
2012-03-04 20:11:57 +04:00
if ( ts_dev - > pen_down & & z1 ! = 0 & & z2 ! = 0 ) {
/*
* Calculate pressure using formula
* Resistance ( touch ) = x plate resistance *
* x postion / 4096 * ( ( z2 / z1 ) - 1 )
*/
2013-05-29 16:46:21 +04:00
z = z1 - z2 ;
2012-03-04 20:11:57 +04:00
z * = x ;
z * = ts_dev - > x_plate_resistance ;
2013-05-29 16:46:21 +04:00
z / = z2 ;
2012-03-04 20:11:57 +04:00
z = ( z + 2047 ) > > 12 ;
if ( z < = MAX_12BIT ) {
input_report_abs ( input_dev , ABS_X , x ) ;
input_report_abs ( input_dev , ABS_Y , y ) ;
input_report_abs ( input_dev , ABS_PRESSURE , z ) ;
input_report_key ( input_dev , BTN_TOUCH , 1 ) ;
input_sync ( input_dev ) ;
}
}
2012-10-16 11:25:40 +04:00
irqclr | = IRQENB_FIFO0THRES ;
2012-03-04 20:11:57 +04:00
}
2013-06-05 18:30:00 +04:00
if ( irqclr ) {
titsc_writel ( ts_dev , REG_IRQSTATUS , irqclr ) ;
2015-02-03 22:44:12 +03:00
if ( status & IRQENB_EOS )
am335x_tsc_se_set_cache ( ts_dev - > mfd_tscadc ,
ts_dev - > step_mask ) ;
2013-06-05 18:30:00 +04:00
return IRQ_HANDLED ;
}
return IRQ_NONE ;
2012-03-04 20:11:57 +04:00
}
2013-01-24 07:45:10 +04:00
static int titsc_parse_dt ( struct platform_device * pdev ,
struct titsc * ts_dev )
{
struct device_node * node = pdev - > dev . of_node ;
int err ;
if ( ! node )
return - EINVAL ;
err = of_property_read_u32 ( node , " ti,wires " , & ts_dev - > wires ) ;
if ( err < 0 )
return err ;
switch ( ts_dev - > wires ) {
case 4 :
case 5 :
case 8 :
break ;
default :
return - EINVAL ;
}
err = of_property_read_u32 ( node , " ti,x-plate-resistance " ,
& ts_dev - > x_plate_resistance ) ;
if ( err < 0 )
return err ;
2013-11-11 11:56:43 +04:00
/*
* Try with the new binding first . If it fails , try again with
* bogus , miss - spelled version .
*/
err = of_property_read_u32 ( node , " ti,coordinate-readouts " ,
2013-01-24 07:45:10 +04:00
& ts_dev - > coordinate_readouts ) ;
2014-06-15 11:15:09 +04:00
if ( err < 0 ) {
dev_warn ( & pdev - > dev , " please use 'ti,coordinate-readouts' instead \n " ) ;
2013-11-11 11:56:43 +04:00
err = of_property_read_u32 ( node , " ti,coordiante-readouts " ,
& ts_dev - > coordinate_readouts ) ;
2014-06-15 11:15:09 +04:00
}
2013-01-24 07:45:10 +04:00
if ( err < 0 )
return err ;
2015-02-03 22:47:05 +03:00
if ( ts_dev - > coordinate_readouts < = 0 ) {
dev_warn ( & pdev - > dev ,
" invalid co-ordinate readouts, resetting it to 5 \n " ) ;
ts_dev - > coordinate_readouts = 5 ;
}
2015-02-03 22:45:34 +03:00
err = of_property_read_u32 ( node , " ti,charge-delay " ,
& ts_dev - > charge_delay ) ;
/*
* If ti , charge - delay value is not specified , then use
* CHARGEDLY_OPENDLY as the default value .
*/
if ( err < 0 ) {
ts_dev - > charge_delay = CHARGEDLY_OPENDLY ;
dev_warn ( & pdev - > dev , " ti,charge-delay not specified \n " ) ;
}
2013-01-24 07:45:10 +04:00
return of_property_read_u32_array ( node , " ti,wire-config " ,
ts_dev - > config_inp , ARRAY_SIZE ( ts_dev - > config_inp ) ) ;
2012-03-04 20:11:57 +04:00
}
/*
* The functions for inserting / removing driver as a module .
*/
2012-12-19 00:46:37 +04:00
static int titsc_probe ( struct platform_device * pdev )
2012-03-04 20:11:57 +04:00
{
2012-10-16 11:25:42 +04:00
struct titsc * ts_dev ;
2012-03-04 20:11:57 +04:00
struct input_dev * input_dev ;
2013-06-05 18:13:47 +04:00
struct ti_tscadc_dev * tscadc_dev = ti_tscadc_dev_get ( pdev ) ;
2012-03-04 20:11:57 +04:00
int err ;
/* Allocate memory for device */
2016-06-01 21:35:05 +03:00
ts_dev = kzalloc ( sizeof ( * ts_dev ) , GFP_KERNEL ) ;
2012-03-04 20:11:57 +04:00
input_dev = input_allocate_device ( ) ;
if ( ! ts_dev | | ! input_dev ) {
dev_err ( & pdev - > dev , " failed to allocate memory. \n " ) ;
err = - ENOMEM ;
goto err_free_mem ;
}
2012-10-16 11:25:44 +04:00
tscadc_dev - > tsc = ts_dev ;
ts_dev - > mfd_tscadc = tscadc_dev ;
2012-03-04 20:11:57 +04:00
ts_dev - > input = input_dev ;
2012-10-16 11:25:44 +04:00
ts_dev - > irq = tscadc_dev - > irq ;
2013-01-24 07:45:10 +04:00
2013-05-21 19:39:13 +04:00
err = titsc_parse_dt ( pdev , ts_dev ) ;
2013-01-24 07:45:10 +04:00
if ( err ) {
dev_err ( & pdev - > dev , " Could not find valid DT data. \n " ) ;
goto err_free_mem ;
}
2012-03-04 20:11:57 +04:00
2012-10-16 11:25:42 +04:00
err = request_irq ( ts_dev - > irq , titsc_irq ,
2013-09-19 10:24:00 +04:00
IRQF_SHARED , pdev - > dev . driver - > name , ts_dev ) ;
2012-03-04 20:11:57 +04:00
if ( err ) {
dev_err ( & pdev - > dev , " failed to allocate irq. \n " ) ;
2012-10-16 11:25:44 +04:00
goto err_free_mem ;
2012-03-04 20:11:57 +04:00
}
2012-10-16 11:25:42 +04:00
titsc_writel ( ts_dev , REG_IRQENABLE , IRQENB_FIFO0THRES ) ;
2015-02-03 22:44:12 +03:00
titsc_writel ( ts_dev , REG_IRQENABLE , IRQENB_EOS ) ;
2013-01-24 07:45:06 +04:00
err = titsc_config_wires ( ts_dev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " wrong i/p wire configuration \n " ) ;
goto err_free_irq ;
}
2012-10-16 11:25:42 +04:00
titsc_step_config ( ts_dev ) ;
2013-05-29 16:46:21 +04:00
titsc_writel ( ts_dev , REG_FIFO0THR ,
ts_dev - > coordinate_readouts * 2 + 2 - 1 ) ;
2012-03-04 20:11:57 +04:00
2012-10-16 11:25:44 +04:00
input_dev - > name = " ti-tsc " ;
2012-03-04 20:11:57 +04:00
input_dev - > dev . parent = & pdev - > dev ;
input_dev - > evbit [ 0 ] = BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_ABS ) ;
input_dev - > keybit [ BIT_WORD ( BTN_TOUCH ) ] = BIT_MASK ( BTN_TOUCH ) ;
input_set_abs_params ( input_dev , ABS_X , 0 , MAX_12BIT , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_Y , 0 , MAX_12BIT , 0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_PRESSURE , 0 , MAX_12BIT , 0 , 0 ) ;
/* register to the input system */
err = input_register_device ( input_dev ) ;
if ( err )
2012-10-16 11:25:44 +04:00
goto err_free_irq ;
2012-03-04 20:11:57 +04:00
platform_set_drvdata ( pdev , ts_dev ) ;
return 0 ;
err_free_irq :
free_irq ( ts_dev - > irq , ts_dev ) ;
err_free_mem :
input_free_device ( input_dev ) ;
kfree ( ts_dev ) ;
return err ;
}
2012-12-19 00:46:37 +04:00
static int titsc_remove ( struct platform_device * pdev )
2012-03-04 20:11:57 +04:00
{
2013-06-05 18:13:47 +04:00
struct titsc * ts_dev = platform_get_drvdata ( pdev ) ;
u32 steps ;
2012-03-04 20:11:57 +04:00
free_irq ( ts_dev - > irq , ts_dev ) ;
2013-01-24 07:45:05 +04:00
/* total steps followed by the enable mask */
2013-01-24 07:45:10 +04:00
steps = 2 * ts_dev - > coordinate_readouts + 2 ;
2013-01-24 07:45:05 +04:00
steps = ( 1 < < steps ) - 1 ;
am335x_tsc_se_clr ( ts_dev - > mfd_tscadc , steps ) ;
2012-03-04 20:11:57 +04:00
input_unregister_device ( ts_dev - > input ) ;
2012-10-16 11:25:44 +04:00
kfree ( ts_dev ) ;
return 0 ;
}
2012-03-04 20:11:57 +04:00
2016-01-08 04:28:06 +03:00
static int __maybe_unused titsc_suspend ( struct device * dev )
2012-10-16 11:25:44 +04:00
{
2013-06-05 18:13:47 +04:00
struct titsc * ts_dev = dev_get_drvdata ( dev ) ;
struct ti_tscadc_dev * tscadc_dev ;
2012-10-16 11:25:44 +04:00
unsigned int idle ;
2013-06-05 18:13:47 +04:00
tscadc_dev = ti_tscadc_dev_get ( to_platform_device ( dev ) ) ;
2012-10-16 11:25:44 +04:00
if ( device_may_wakeup ( tscadc_dev - > dev ) ) {
idle = titsc_readl ( ts_dev , REG_IRQENABLE ) ;
titsc_writel ( ts_dev , REG_IRQENABLE ,
( idle | IRQENB_HW_PEN ) ) ;
titsc_writel ( ts_dev , REG_IRQWAKEUP , IRQWKUP_ENB ) ;
}
return 0 ;
}
2012-03-04 20:11:57 +04:00
2016-01-08 04:28:06 +03:00
static int __maybe_unused titsc_resume ( struct device * dev )
2012-10-16 11:25:44 +04:00
{
2013-06-05 18:13:47 +04:00
struct titsc * ts_dev = dev_get_drvdata ( dev ) ;
struct ti_tscadc_dev * tscadc_dev ;
2012-03-04 20:11:57 +04:00
2013-06-05 18:13:47 +04:00
tscadc_dev = ti_tscadc_dev_get ( to_platform_device ( dev ) ) ;
2012-10-16 11:25:44 +04:00
if ( device_may_wakeup ( tscadc_dev - > dev ) ) {
titsc_writel ( ts_dev , REG_IRQWAKEUP ,
0x00 ) ;
titsc_writel ( ts_dev , REG_IRQCLR , IRQENB_HW_PEN ) ;
}
titsc_step_config ( ts_dev ) ;
titsc_writel ( ts_dev , REG_FIFO0THR ,
2013-05-29 16:46:21 +04:00
ts_dev - > coordinate_readouts * 2 + 2 - 1 ) ;
2012-03-04 20:11:57 +04:00
return 0 ;
}
2016-01-08 04:28:06 +03:00
static SIMPLE_DEV_PM_OPS ( titsc_pm_ops , titsc_suspend , titsc_resume ) ;
2012-10-16 11:25:44 +04:00
2013-01-24 07:45:10 +04:00
static const struct of_device_id ti_tsc_dt_ids [ ] = {
{ . compatible = " ti,am3359-tsc " , } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , ti_tsc_dt_ids ) ;
2012-03-04 20:11:57 +04:00
static struct platform_driver ti_tsc_driver = {
2012-10-16 11:25:42 +04:00
. probe = titsc_probe ,
2012-12-19 00:46:37 +04:00
. remove = titsc_remove ,
2012-03-04 20:11:57 +04:00
. driver = {
2013-05-27 19:08:28 +04:00
. name = " TI-am335x-tsc " ,
2016-01-08 04:28:06 +03:00
. pm = & titsc_pm_ops ,
2013-10-06 11:53:52 +04:00
. of_match_table = ti_tsc_dt_ids ,
2012-03-04 20:11:57 +04:00
} ,
} ;
module_platform_driver ( ti_tsc_driver ) ;
MODULE_DESCRIPTION ( " TI touchscreen controller driver " ) ;
MODULE_AUTHOR ( " Rachna Patil <rachna@ti.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;