2010-06-01 15:50:06 +04:00
/*
2010-09-01 09:57:28 +04:00
* Intel MID Resistive Touch Screen Driver
2010-06-01 15:50:06 +04:00
*
* Copyright ( C ) 2008 Intel Corp
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* 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 of the License .
*
* 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
2010-09-01 09:57:28 +04:00
* with this program ; if not , write to the Free Software Foundation , Inc . ,
2010-06-01 15:50:06 +04:00
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
*
* Questions / Comments / Bug fixes to Sreedhara ( sreedhara . ds @ intel . com )
2010-09-01 09:57:28 +04:00
* Ramesh Agarwal ( ramesh . agarwal @ intel . com )
2010-06-01 15:50:06 +04:00
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* TODO :
* review conversion of r / m / w sequences
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/input.h>
# include <linux/interrupt.h>
# include <linux/err.h>
# include <linux/param.h>
2010-09-01 09:57:30 +04:00
# include <linux/slab.h>
# include <linux/platform_device.h>
2010-06-01 15:50:06 +04:00
# include <linux/irq.h>
# include <linux/delay.h>
# include <asm/intel_scu_ipc.h>
/* PMIC Interrupt registers */
2010-09-01 09:57:28 +04:00
# define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
2010-06-01 15:50:06 +04:00
/* PMIC Interrupt registers */
2010-09-01 09:57:28 +04:00
# define PMIC_REG_INT 0x04 /* PMIC interrupt register */
# define PMIC_REG_MINT 0x05 /* PMIC interrupt mask register */
2010-06-01 15:50:06 +04:00
/* ADC Interrupt registers */
2010-09-01 09:57:28 +04:00
# define PMIC_REG_ADCINT 0x5F /* ADC interrupt register */
# define PMIC_REG_MADCINT 0x60 /* ADC interrupt mask register */
2010-06-01 15:50:06 +04:00
/* ADC Control registers */
2010-09-01 09:57:28 +04:00
# define PMIC_REG_ADCCNTL1 0x61 /* ADC control register */
2010-06-01 15:50:06 +04:00
/* ADC Channel Selection registers */
2010-09-01 09:57:28 +04:00
# define PMICADDR0 0xA4
# define END_OF_CHANNEL 0x1F
2010-06-01 15:50:06 +04:00
/* ADC Result register */
2010-09-01 09:57:28 +04:00
# define PMIC_REG_ADCSNS0H 0x64
2010-06-01 15:50:06 +04:00
/* ADC channels for touch screen */
2010-09-01 09:57:28 +04:00
# define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
# define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
# define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
# define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
2010-06-01 15:50:06 +04:00
/* Touch screen channel BIAS constants */
2010-09-01 09:57:28 +04:00
# define MRST_XBIAS 0x20
# define MRST_YBIAS 0x40
# define MRST_ZBIAS 0x80
2010-06-01 15:50:06 +04:00
/* Touch screen coordinates */
2010-09-01 09:57:28 +04:00
# define MRST_X_MIN 10
# define MRST_X_MAX 1024
# define MRST_X_FUZZ 5
# define MRST_Y_MIN 10
# define MRST_Y_MAX 1024
# define MRST_Y_FUZZ 5
# define MRST_PRESSURE_MIN 0
# define MRST_PRESSURE_NOMINAL 50
# define MRST_PRESSURE_MAX 100
# define WAIT_ADC_COMPLETION 10 /* msec */
2010-06-01 15:50:06 +04:00
/* PMIC ADC round robin delays */
2010-09-01 09:57:28 +04:00
# define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
# define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
2010-06-01 15:50:06 +04:00
/* PMIC Vendor Identifiers */
2010-09-01 09:57:28 +04:00
# define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
# define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
# define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
# define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
2010-06-01 15:50:06 +04:00
/* Touch screen device structure */
struct mrstouch_dev {
2010-09-01 09:57:30 +04:00
struct device * dev ; /* device associated with touch screen */
2010-09-01 09:57:28 +04:00
struct input_dev * input ;
char phys [ 32 ] ;
u16 asr ; /* Address selection register */
int irq ;
unsigned int vendor ; /* PMIC vendor */
unsigned int rev ; /* PMIC revision */
int ( * read_prepare ) ( struct mrstouch_dev * tsdev ) ;
int ( * read ) ( struct mrstouch_dev * tsdev , u16 * x , u16 * y , u16 * z ) ;
int ( * read_finish ) ( struct mrstouch_dev * tsdev ) ;
} ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
/*************************** NEC and Maxim Interface ************************/
static int mrstouch_nec_adc_read_prepare ( struct mrstouch_dev * tsdev )
2010-06-01 15:50:06 +04:00
{
2010-09-01 10:00:41 +04:00
return intel_scu_ipc_update_register ( PMIC_REG_MADCINT , 0 , 0x20 ) ;
2010-06-01 15:50:06 +04:00
}
/*
2010-09-01 09:57:28 +04:00
* Enables PENDET interrupt .
2010-06-01 15:50:06 +04:00
*/
2010-09-01 09:57:28 +04:00
static int mrstouch_nec_adc_read_finish ( struct mrstouch_dev * tsdev )
2010-06-01 15:50:06 +04:00
{
int err ;
2010-09-01 10:00:41 +04:00
err = intel_scu_ipc_update_register ( PMIC_REG_MADCINT , 0x20 , 0x20 ) ;
if ( ! err )
err = intel_scu_ipc_update_register ( PMIC_REG_ADCCNTL1 , 0 , 0x05 ) ;
2010-06-01 15:50:06 +04:00
2010-09-01 10:00:41 +04:00
return err ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
/*
* Reads PMIC ADC touch screen result
* Reads ADC storage registers for higher 7 and lower 3 bits and
* converts the two readings into a single value and turns off gain bit
2010-06-01 15:50:06 +04:00
*/
static int mrstouch_ts_chan_read ( u16 offset , u16 chan , u16 * vp , u16 * vm )
{
int err ;
u16 result ;
u32 res ;
result = PMIC_REG_ADCSNS0H + offset ;
if ( chan = = MRST_TS_CHAN12 )
result + = 4 ;
err = intel_scu_ipc_ioread32 ( result , & res ) ;
if ( err )
return err ;
/* Mash the bits up */
* vp = ( res & 0xFF ) < < 3 ; /* Highest 7 bits */
* vp | = ( res > > 8 ) & 0x07 ; /* Lower 3 bits */
* vp & = 0x3FF ;
res > > = 16 ;
* vm = ( res & 0xFF ) < < 3 ; /* Highest 7 bits */
* vm | = ( res > > 8 ) & 0x07 ; /* Lower 3 bits */
* vm & = 0x3FF ;
return 0 ;
}
2010-09-01 09:57:28 +04:00
/*
* Enables X , Y and Z bias values
* Enables YPYM for X channels and XPXM for Y channels
2010-06-01 15:50:06 +04:00
*/
2010-09-01 09:57:28 +04:00
static int mrstouch_ts_bias_set ( uint offset , uint bias )
2010-06-01 15:50:06 +04:00
{
int count ;
2010-09-01 09:57:28 +04:00
u16 chan , start ;
u16 reg [ 4 ] ;
u8 data [ 4 ] ;
2010-06-01 15:50:06 +04:00
chan = PMICADDR0 + offset ;
2010-09-01 09:57:28 +04:00
start = MRST_TS_CHAN10 ;
2010-06-01 15:50:06 +04:00
for ( count = 0 ; count < = 3 ; count + + ) {
reg [ count ] = chan + + ;
2010-09-01 09:57:28 +04:00
data [ count ] = bias | ( start + count ) ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
return intel_scu_ipc_writev ( reg , data , 4 ) ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
/* To read touch screen channel values */
static int mrstouch_nec_adc_read ( struct mrstouch_dev * tsdev ,
u16 * x , u16 * y , u16 * z )
2010-06-01 15:50:06 +04:00
{
int err ;
2010-09-01 09:57:28 +04:00
u16 xm , ym , zm ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
/* configure Y bias for X channels */
err = mrstouch_ts_bias_set ( tsdev - > asr , MRST_YBIAS ) ;
if ( err )
goto ipc_error ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
msleep ( WAIT_ADC_COMPLETION ) ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
/* read x+ and x- channels */
err = mrstouch_ts_chan_read ( tsdev - > asr , MRST_TS_CHAN10 , x , & xm ) ;
2010-06-01 15:50:06 +04:00
if ( err )
goto ipc_error ;
2010-09-01 09:57:28 +04:00
/* configure x bias for y channels */
err = mrstouch_ts_bias_set ( tsdev - > asr , MRST_XBIAS ) ;
if ( err )
goto ipc_error ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
msleep ( WAIT_ADC_COMPLETION ) ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
/* read y+ and y- channels */
err = mrstouch_ts_chan_read ( tsdev - > asr , MRST_TS_CHAN12 , y , & ym ) ;
if ( err )
goto ipc_error ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
/* configure z bias for x and y channels */
err = mrstouch_ts_bias_set ( tsdev - > asr , MRST_ZBIAS ) ;
2010-06-01 15:50:06 +04:00
if ( err )
goto ipc_error ;
2010-09-01 09:57:28 +04:00
msleep ( WAIT_ADC_COMPLETION ) ;
/* read z+ and z- channels */
err = mrstouch_ts_chan_read ( tsdev - > asr , MRST_TS_CHAN10 , z , & zm ) ;
if ( err )
goto ipc_error ;
2010-06-01 15:50:06 +04:00
return 0 ;
ipc_error :
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev , " ipc error during adc read \n " ) ;
2010-06-01 15:50:06 +04:00
return err ;
}
2010-09-01 09:57:28 +04:00
/*************************** Freescale Interface ************************/
static int mrstouch_fs_adc_read_prepare ( struct mrstouch_dev * tsdev )
2010-06-01 15:50:06 +04:00
{
int err , count ;
u16 chan ;
u16 reg [ 5 ] ;
u8 data [ 5 ] ;
2010-09-01 09:57:28 +04:00
/* Stop the ADC */
err = intel_scu_ipc_update_register ( PMIC_REG_MADCINT , 0x00 , 0x02 ) ;
if ( err )
goto ipc_error ;
2010-06-01 15:50:06 +04:00
chan = PMICADDR0 + tsdev - > asr ;
/* Set X BIAS */
for ( count = 0 ; count < = 3 ; count + + ) {
reg [ count ] = chan + + ;
data [ count ] = 0x2A ;
}
reg [ count ] = chan + + ; /* Dummy */
data [ count ] = 0 ;
err = intel_scu_ipc_writev ( reg , data , 5 ) ;
if ( err )
goto ipc_error ;
msleep ( WAIT_ADC_COMPLETION ) ;
/* Set Y BIAS */
for ( count = 0 ; count < = 3 ; count + + ) {
reg [ count ] = chan + + ;
data [ count ] = 0x4A ;
}
reg [ count ] = chan + + ; /* Dummy */
data [ count ] = 0 ;
err = intel_scu_ipc_writev ( reg , data , 5 ) ;
if ( err )
goto ipc_error ;
msleep ( WAIT_ADC_COMPLETION ) ;
/* Set Z BIAS */
err = intel_scu_ipc_iowrite32 ( chan + 2 , 0x8A8A8A8A ) ;
if ( err )
goto ipc_error ;
msleep ( WAIT_ADC_COMPLETION ) ;
2010-09-01 09:57:28 +04:00
return 0 ;
ipc_error :
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev , " ipc error during %s \n " , __func__ ) ;
2010-09-01 09:57:28 +04:00
return err ;
}
static int mrstouch_fs_adc_read ( struct mrstouch_dev * tsdev ,
u16 * x , u16 * y , u16 * z )
{
int err ;
u16 result ;
u16 reg [ 4 ] ;
u8 data [ 4 ] ;
result = PMIC_REG_ADCSNS0H + tsdev - > asr ;
reg [ 0 ] = result + 4 ;
reg [ 1 ] = result + 5 ;
reg [ 2 ] = result + 16 ;
reg [ 3 ] = result + 17 ;
err = intel_scu_ipc_readv ( reg , data , 4 ) ;
if ( err )
goto ipc_error ;
* x = data [ 0 ] < < 3 ; /* Higher 7 bits */
* x | = data [ 1 ] & 0x7 ; /* Lower 3 bits */
* x & = 0x3FF ;
* y = data [ 2 ] < < 3 ; /* Higher 7 bits */
* y | = data [ 3 ] & 0x7 ; /* Lower 3 bits */
* y & = 0x3FF ;
/* Read Z value */
reg [ 0 ] = result + 28 ;
reg [ 1 ] = result + 29 ;
err = intel_scu_ipc_readv ( reg , data , 4 ) ;
if ( err )
goto ipc_error ;
* z = data [ 0 ] < < 3 ; /* Higher 7 bits */
* z | = data [ 1 ] & 0x7 ; /* Lower 3 bits */
* z & = 0x3FF ;
return 0 ;
ipc_error :
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev , " ipc error during %s \n " , __func__ ) ;
2010-09-01 09:57:28 +04:00
return err ;
}
static int mrstouch_fs_adc_read_finish ( struct mrstouch_dev * tsdev )
{
int err , count ;
u16 chan ;
u16 reg [ 5 ] ;
u8 data [ 5 ] ;
2010-06-01 15:50:06 +04:00
/* Clear all TS channels */
chan = PMICADDR0 + tsdev - > asr ;
for ( count = 0 ; count < = 4 ; count + + ) {
reg [ count ] = chan + + ;
data [ count ] = 0 ;
}
err = intel_scu_ipc_writev ( reg , data , 5 ) ;
if ( err )
goto ipc_error ;
for ( count = 0 ; count < = 4 ; count + + ) {
reg [ count ] = chan + + ;
data [ count ] = 0 ;
}
err = intel_scu_ipc_writev ( reg , data , 5 ) ;
if ( err )
goto ipc_error ;
err = intel_scu_ipc_iowrite32 ( chan + 2 , 0x00000000 ) ;
if ( err )
goto ipc_error ;
2010-09-01 09:57:28 +04:00
/* Start ADC */
err = intel_scu_ipc_update_register ( PMIC_REG_MADCINT , 0x02 , 0x02 ) ;
if ( err )
goto ipc_error ;
2010-06-01 15:50:06 +04:00
return 0 ;
ipc_error :
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev , " ipc error during %s \n " , __func__ ) ;
2010-06-01 15:50:06 +04:00
return err ;
}
2010-09-01 09:57:28 +04:00
static void mrstouch_report_event ( struct input_dev * input ,
unsigned int x , unsigned int y , unsigned int z )
2010-06-01 15:50:06 +04:00
{
2010-09-01 09:57:28 +04:00
if ( z > MRST_PRESSURE_NOMINAL ) {
/* Pen touched, report button touch and coordinates */
input_report_key ( input , BTN_TOUCH , 1 ) ;
input_report_abs ( input , ABS_X , x ) ;
input_report_abs ( input , ABS_Y , y ) ;
} else {
input_report_key ( input , BTN_TOUCH , 0 ) ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
input_report_abs ( input , ABS_PRESSURE , z ) ;
input_sync ( input ) ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
/* PENDET interrupt handler */
static irqreturn_t mrstouch_pendet_irq ( int irq , void * dev_id )
2010-06-01 15:50:06 +04:00
{
2010-09-01 09:57:28 +04:00
struct mrstouch_dev * tsdev = dev_id ;
u16 x , y , z ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
/*
* Should we lower thread priority ? Probably not , since we are
* not spinning but sleeping . . .
*/
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
if ( tsdev - > read_prepare ( tsdev ) )
goto out ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
do {
if ( tsdev - > read ( tsdev , & x , & y , & z ) )
break ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
mrstouch_report_event ( tsdev - > input , x , y , z ) ;
} while ( z > MRST_PRESSURE_NOMINAL ) ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
tsdev - > read_finish ( tsdev ) ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
out :
return IRQ_HANDLED ;
}
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
/* Utility to read PMIC ID */
static int __devinit mrstouch_read_pmic_id ( uint * vendor , uint * rev )
{
int err ;
u8 r ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
err = intel_scu_ipc_ioread8 ( PMIC_REG_ID1 , & r ) ;
2010-06-01 15:50:06 +04:00
if ( err )
2010-09-01 09:57:28 +04:00
return err ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
* vendor = r & 0x7 ;
* rev = ( r > > 3 ) & 0x7 ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
return 0 ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
/*
* Parse ADC channels to find end of the channel configured by other ADC user
* NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
*/
static int __devinit mrstouch_chan_parse ( struct mrstouch_dev * tsdev )
2010-06-01 15:50:06 +04:00
{
2011-07-19 04:09:05 +04:00
int found = 0 ;
int err , i ;
2010-09-01 09:57:31 +04:00
u8 r8 ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
for ( i = 0 ; i < MRSTOUCH_MAX_CHANNELS ; i + + ) {
2010-09-01 09:57:31 +04:00
err = intel_scu_ipc_ioread8 ( PMICADDR0 + i , & r8 ) ;
2010-09-01 09:57:28 +04:00
if ( err )
return err ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:31 +04:00
if ( r8 = = END_OF_CHANNEL ) {
found = i ;
break ;
2010-09-01 09:57:28 +04:00
}
}
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
if ( tsdev - > vendor = = PMIC_VENDOR_FS ) {
2011-07-19 04:09:05 +04:00
if ( found > MRSTOUCH_MAX_CHANNELS - 18 )
2010-09-01 09:57:28 +04:00
return - ENOSPC ;
} else {
2011-07-19 04:09:05 +04:00
if ( found > MRSTOUCH_MAX_CHANNELS - 4 )
2010-09-01 09:57:28 +04:00
return - ENOSPC ;
2010-06-01 15:50:06 +04:00
}
2011-07-19 04:09:05 +04:00
2010-09-01 09:57:28 +04:00
return found ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
/*
* Writes touch screen channels to ADC address selection registers
*/
static int __devinit mrstouch_ts_chan_set ( uint offset )
2010-06-01 15:50:06 +04:00
{
2010-09-01 09:57:28 +04:00
u16 chan ;
2010-09-01 09:57:31 +04:00
int ret , count ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
chan = PMICADDR0 + offset ;
for ( count = 0 ; count < = 3 ; count + + ) {
2010-09-01 09:57:31 +04:00
ret = intel_scu_ipc_iowrite8 ( chan + + , MRST_TS_CHAN10 + count ) ;
if ( ret )
return ret ;
2010-09-01 09:57:28 +04:00
}
2010-09-01 09:57:31 +04:00
return intel_scu_ipc_iowrite8 ( chan + + , END_OF_CHANNEL ) ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
/* Initialize ADC */
static int __devinit mrstouch_adc_init ( struct mrstouch_dev * tsdev )
2010-06-01 15:50:06 +04:00
{
2010-09-01 09:57:28 +04:00
int err , start ;
u8 ra , rm ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
err = mrstouch_read_pmic_id ( & tsdev - > vendor , & tsdev - > rev ) ;
if ( err ) {
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev , " Unable to read PMIC id \n " ) ;
2010-09-01 09:57:28 +04:00
return err ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
switch ( tsdev - > vendor ) {
case PMIC_VENDOR_NEC :
case PMIC_VENDOR_MAXIM :
tsdev - > read_prepare = mrstouch_nec_adc_read_prepare ;
tsdev - > read = mrstouch_nec_adc_read ;
tsdev - > read_finish = mrstouch_nec_adc_read_finish ;
break ;
case PMIC_VENDOR_FS :
tsdev - > read_prepare = mrstouch_fs_adc_read_prepare ;
tsdev - > read = mrstouch_fs_adc_read ;
tsdev - > read_finish = mrstouch_fs_adc_read_finish ;
break ;
default :
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev ,
2010-09-01 09:57:28 +04:00
" Unsupported touchscreen: %d \n " , tsdev - > vendor ) ;
return - ENXIO ;
}
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
start = mrstouch_chan_parse ( tsdev ) ;
if ( start < 0 ) {
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev , " Unable to parse channels \n " ) ;
2010-09-01 09:57:28 +04:00
return start ;
}
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
tsdev - > asr = start ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
/*
* ADC power on , start , enable PENDET and set loop delay
* ADC loop delay is set to 4.5 ms approximately
* Loop delay more than this results in jitter in adc readings
2011-03-31 05:57:33 +04:00
* Setting loop delay to 0 ( continuous loop ) in MAXIM stops PENDET
2010-09-01 09:57:28 +04:00
* interrupt generation sometimes .
*/
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
if ( tsdev - > vendor = = PMIC_VENDOR_FS ) {
ra = 0xE0 | ADC_LOOP_DELAY0 ;
rm = 0x5 ;
} else {
/* NEC and MAXIm not consistent with loop delay 0 */
ra = 0xE0 | ADC_LOOP_DELAY1 ;
rm = 0x0 ;
/* configure touch screen channels */
err = mrstouch_ts_chan_set ( tsdev - > asr ) ;
if ( err )
return err ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
err = intel_scu_ipc_update_register ( PMIC_REG_ADCCNTL1 , ra , 0xE7 ) ;
if ( err )
return err ;
err = intel_scu_ipc_update_register ( PMIC_REG_MADCINT , rm , 0x03 ) ;
if ( err )
return err ;
return 0 ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
2010-06-01 15:50:06 +04:00
/* Probe function for touch screen driver */
2010-09-01 09:57:30 +04:00
static int __devinit mrstouch_probe ( struct platform_device * pdev )
2010-06-01 15:50:06 +04:00
{
struct mrstouch_dev * tsdev ;
2010-09-01 09:57:28 +04:00
struct input_dev * input ;
int err ;
2010-09-01 09:57:30 +04:00
int irq ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:30 +04:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
dev_err ( & pdev - > dev , " no interrupt assigned \n " ) ;
2010-06-01 15:50:06 +04:00
return - EINVAL ;
}
tsdev = kzalloc ( sizeof ( struct mrstouch_dev ) , GFP_KERNEL ) ;
2010-09-01 09:57:28 +04:00
input = input_allocate_device ( ) ;
if ( ! tsdev | | ! input ) {
2010-09-01 09:57:30 +04:00
dev_err ( & pdev - > dev , " unable to allocate memory \n " ) ;
2010-09-01 09:57:28 +04:00
err = - ENOMEM ;
goto err_free_mem ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:30 +04:00
tsdev - > dev = & pdev - > dev ;
2010-09-01 09:57:28 +04:00
tsdev - > input = input ;
2010-09-01 09:57:30 +04:00
tsdev - > irq = irq ;
2010-09-01 09:57:28 +04:00
snprintf ( tsdev - > phys , sizeof ( tsdev - > phys ) ,
2010-09-01 09:57:30 +04:00
" %s/input0 " , dev_name ( tsdev - > dev ) ) ;
2010-06-01 15:50:06 +04:00
err = mrstouch_adc_init ( tsdev ) ;
if ( err ) {
2010-09-01 09:57:30 +04:00
dev_err ( & pdev - > dev , " ADC initialization failed \n " ) ;
2010-09-01 09:57:28 +04:00
goto err_free_mem ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
input - > name = " mrst_touchscreen " ;
input - > phys = tsdev - > phys ;
2010-09-01 09:57:30 +04:00
input - > dev . parent = tsdev - > dev ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
input - > id . vendor = tsdev - > vendor ;
input - > id . version = tsdev - > rev ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
input - > evbit [ 0 ] = BIT_MASK ( EV_KEY ) | BIT_MASK ( EV_ABS ) ;
input - > keybit [ BIT_WORD ( BTN_TOUCH ) ] = BIT_MASK ( BTN_TOUCH ) ;
2010-06-01 15:50:06 +04:00
2010-09-01 09:57:28 +04:00
input_set_abs_params ( tsdev - > input , ABS_X ,
MRST_X_MIN , MRST_X_MAX , MRST_X_FUZZ , 0 ) ;
input_set_abs_params ( tsdev - > input , ABS_Y ,
MRST_Y_MIN , MRST_Y_MAX , MRST_Y_FUZZ , 0 ) ;
input_set_abs_params ( tsdev - > input , ABS_PRESSURE ,
MRST_PRESSURE_MIN , MRST_PRESSURE_MAX , 0 , 0 ) ;
err = request_threaded_irq ( tsdev - > irq , NULL , mrstouch_pendet_irq ,
0 , " mrstouch " , tsdev ) ;
2010-06-01 15:50:06 +04:00
if ( err ) {
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev , " unable to allocate irq \n " ) ;
2010-09-01 09:57:28 +04:00
goto err_free_mem ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
err = input_register_device ( tsdev - > input ) ;
if ( err ) {
2010-09-01 09:57:30 +04:00
dev_err ( tsdev - > dev , " unable to register input device \n " ) ;
2010-09-01 09:57:28 +04:00
goto err_free_irq ;
2010-06-01 15:50:06 +04:00
}
2010-09-01 09:57:28 +04:00
2010-09-01 09:57:30 +04:00
platform_set_drvdata ( pdev , tsdev ) ;
2010-06-01 15:50:06 +04:00
return 0 ;
2010-09-01 09:57:28 +04:00
err_free_irq :
free_irq ( tsdev - > irq , tsdev ) ;
err_free_mem :
input_free_device ( input ) ;
2010-06-01 15:50:06 +04:00
kfree ( tsdev ) ;
return err ;
}
2010-09-01 09:57:30 +04:00
static int __devexit mrstouch_remove ( struct platform_device * pdev )
2010-06-01 15:50:06 +04:00
{
2010-09-01 09:57:30 +04:00
struct mrstouch_dev * tsdev = platform_get_drvdata ( pdev ) ;
2010-09-01 09:57:28 +04:00
free_irq ( tsdev - > irq , tsdev ) ;
input_unregister_device ( tsdev - > input ) ;
kfree ( tsdev ) ;
2010-09-01 09:57:30 +04:00
platform_set_drvdata ( pdev , NULL ) ;
2010-09-01 09:57:28 +04:00
2010-06-01 15:50:06 +04:00
return 0 ;
}
2010-09-01 09:57:30 +04:00
static struct platform_driver mrstouch_driver = {
2010-06-01 15:50:06 +04:00
. driver = {
2010-09-01 09:57:30 +04:00
. name = " pmic_touch " ,
. owner = THIS_MODULE ,
2010-06-01 15:50:06 +04:00
} ,
2010-09-01 09:57:30 +04:00
. probe = mrstouch_probe ,
. remove = __devexit_p ( mrstouch_remove ) ,
2010-06-01 15:50:06 +04:00
} ;
2011-11-29 23:14:13 +04:00
module_platform_driver ( mrstouch_driver ) ;
2010-06-01 15:50:06 +04:00
MODULE_AUTHOR ( " Sreedhara Murthy. D.S, sreedhara.ds@intel.com " ) ;
MODULE_DESCRIPTION ( " Intel Moorestown Resistive Touch Screen Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;