2009-03-10 06:12:52 +03:00
/*
2010-06-30 12:40:52 +04:00
* AD7879 / AD7889 based touchscreen and GPIO driver
2009-03-10 06:12:52 +03:00
*
2010-06-30 12:40:52 +04:00
* Copyright ( C ) 2008 - 2010 Michael Hennerich , Analog Devices Inc .
2009-03-10 06:12:52 +03:00
*
2010-06-30 12:40:52 +04:00
* Licensed under the GPL - 2 or later .
2009-03-10 06:12:52 +03:00
*
* History :
* Copyright ( c ) 2005 David Brownell
* Copyright ( c ) 2006 Nokia Corporation
* Various changes : Imre Deak < imre . deak @ nokia . com >
*
* Using code from :
* - corgi_ts . c
* Copyright ( C ) 2004 - 2005 Richard Purdie
* - omap_ts . [ hc ] , ads7846 . h , ts_osk . c
* Copyright ( C ) 2002 MontaVista Software
* Copyright ( C ) 2004 Texas Instruments
* Copyright ( C ) 2005 Dirk Behme
* - ad7877 . c
* Copyright ( C ) 2006 - 2008 Analog Devices Inc .
*/
# include <linux/device.h>
# include <linux/delay.h>
# include <linux/input.h>
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/slab.h>
# include <linux/spi/spi.h>
# include <linux/i2c.h>
2010-01-19 11:27:58 +03:00
# include <linux/gpio.h>
2009-03-10 06:12:52 +03:00
# include <linux/spi/ad7879.h>
2011-07-03 21:53:48 +04:00
# include <linux/module.h>
2010-06-30 12:40:52 +04:00
# include "ad7879.h"
2009-03-10 06:12:52 +03:00
# define AD7879_REG_ZEROS 0
# define AD7879_REG_CTRL1 1
# define AD7879_REG_CTRL2 2
# define AD7879_REG_CTRL3 3
# define AD7879_REG_AUX1HIGH 4
# define AD7879_REG_AUX1LOW 5
# define AD7879_REG_TEMP1HIGH 6
# define AD7879_REG_TEMP1LOW 7
# define AD7879_REG_XPLUS 8
# define AD7879_REG_YPLUS 9
# define AD7879_REG_Z1 10
# define AD7879_REG_Z2 11
# define AD7879_REG_AUXVBAT 12
# define AD7879_REG_TEMP 13
# define AD7879_REG_REVID 14
/* Control REG 1 */
# define AD7879_TMR(x) ((x & 0xFF) << 0)
# define AD7879_ACQ(x) ((x & 0x3) << 8)
# define AD7879_MODE_NOC (0 << 10) /* Do not convert */
# define AD7879_MODE_SCC (1 << 10) /* Single channel conversion */
# define AD7879_MODE_SEQ0 (2 << 10) /* Sequence 0 in Slave Mode */
# define AD7879_MODE_SEQ1 (3 << 10) /* Sequence 1 in Master Mode */
# define AD7879_MODE_INT (1 << 15) /* PENIRQ disabled INT enabled */
/* Control REG 2 */
# define AD7879_FCD(x) ((x & 0x3) << 0)
# define AD7879_RESET (1 << 4)
# define AD7879_MFS(x) ((x & 0x3) << 5)
# define AD7879_AVG(x) ((x & 0x3) << 7)
# define AD7879_SER (1 << 9) /* non-differential */
# define AD7879_DFR (0 << 9) /* differential */
# define AD7879_GPIOPOL (1 << 10)
# define AD7879_GPIODIR (1 << 11)
# define AD7879_GPIO_DATA (1 << 12)
# define AD7879_GPIO_EN (1 << 13)
# define AD7879_PM(x) ((x & 0x3) << 14)
# define AD7879_PM_SHUTDOWN (0)
# define AD7879_PM_DYN (1)
# define AD7879_PM_FULLON (2)
/* Control REG 3 */
# define AD7879_TEMPMASK_BIT (1<<15)
# define AD7879_AUXVBATMASK_BIT (1<<14)
# define AD7879_INTMODE_BIT (1<<13)
# define AD7879_GPIOALERTMASK_BIT (1<<12)
# define AD7879_AUXLOW_BIT (1<<11)
# define AD7879_AUXHIGH_BIT (1<<10)
# define AD7879_TEMPLOW_BIT (1<<9)
# define AD7879_TEMPHIGH_BIT (1<<8)
# define AD7879_YPLUS_BIT (1<<7)
# define AD7879_XPLUS_BIT (1<<6)
# define AD7879_Z1_BIT (1<<5)
# define AD7879_Z2_BIT (1<<4)
# define AD7879_AUX_BIT (1<<3)
# define AD7879_VBAT_BIT (1<<2)
# define AD7879_TEMP_BIT (1<<1)
enum {
AD7879_SEQ_XPOS = 0 ,
AD7879_SEQ_YPOS = 1 ,
AD7879_SEQ_Z1 = 2 ,
AD7879_SEQ_Z2 = 3 ,
AD7879_NR_SENSE = 4 ,
} ;
# define MAX_12BIT ((1<<12)-1)
# define TS_PEN_UP_TIMEOUT msecs_to_jiffies(50)
struct ad7879 {
2010-06-30 12:40:52 +04:00
const struct ad7879_bus_ops * bops ;
struct device * dev ;
2009-03-10 06:12:52 +03:00
struct input_dev * input ;
struct timer_list timer ;
2010-01-19 11:27:58 +03:00
# ifdef CONFIG_GPIOLIB
struct gpio_chip gc ;
2010-07-01 01:50:51 +04:00
struct mutex mutex ;
2010-01-19 11:27:58 +03:00
# endif
2010-06-30 12:40:52 +04:00
unsigned int irq ;
2010-07-01 01:50:51 +04:00
bool disabled ; /* P: input->mutex */
bool suspended ; /* P: input->mutex */
2012-07-06 21:44:19 +04:00
bool swap_xy ;
2009-03-10 06:12:52 +03:00
u16 conversion_data [ AD7879_NR_SENSE ] ;
char phys [ 32 ] ;
u8 first_conversion_delay ;
u8 acquisition_time ;
u8 averaging ;
u8 pen_down_acc_interval ;
u8 median ;
u16 x_plate_ohms ;
u16 pressure_max ;
u16 cmd_crtl1 ;
u16 cmd_crtl2 ;
u16 cmd_crtl3 ;
2010-10-29 01:59:05 +04:00
int x ;
int y ;
int Rt ;
2009-03-10 06:12:52 +03:00
} ;
2010-06-30 12:40:52 +04:00
static int ad7879_read ( struct ad7879 * ts , u8 reg )
{
return ts - > bops - > read ( ts - > dev , reg ) ;
}
static int ad7879_multi_read ( struct ad7879 * ts , u8 first_reg , u8 count , u16 * buf )
{
return ts - > bops - > multi_read ( ts - > dev , first_reg , count , buf ) ;
}
static int ad7879_write ( struct ad7879 * ts , u8 reg , u16 val )
{
return ts - > bops - > write ( ts - > dev , reg , val ) ;
}
2009-03-10 06:12:52 +03:00
2010-07-01 01:51:10 +04:00
static int ad7879_report ( struct ad7879 * ts )
2009-03-10 06:12:52 +03:00
{
struct input_dev * input_dev = ts - > input ;
unsigned Rt ;
u16 x , y , z1 , z2 ;
x = ts - > conversion_data [ AD7879_SEQ_XPOS ] & MAX_12BIT ;
y = ts - > conversion_data [ AD7879_SEQ_YPOS ] & MAX_12BIT ;
z1 = ts - > conversion_data [ AD7879_SEQ_Z1 ] & MAX_12BIT ;
z2 = ts - > conversion_data [ AD7879_SEQ_Z2 ] & MAX_12BIT ;
2012-07-06 21:44:19 +04:00
if ( ts - > swap_xy )
swap ( x , y ) ;
2009-03-10 06:12:52 +03:00
/*
* The samples processed here are already preprocessed by the AD7879 .
2010-06-30 12:40:52 +04:00
* The preprocessing function consists of a median and an averaging
* filter . The combination of these two techniques provides a robust
* solution , discarding the spurious noise in the signal and keeping
* only the data of interest . The size of both filters is
* programmable . ( dev . platform_data , see linux / spi / ad7879 . h ) Other
* user - programmable conversion controls include variable acquisition
* time , and first conversion delay . Up to 16 averages can be taken
* per conversion .
2009-03-10 06:12:52 +03:00
*/
if ( likely ( x & & z1 ) ) {
/* compute touch pressure resistance using equation #1 */
Rt = ( z2 - z1 ) * x * ts - > x_plate_ohms ;
Rt / = z1 ;
Rt = ( Rt + 2047 ) > > 12 ;
2010-10-29 01:59:05 +04:00
/*
* Sample found inconsistent , pressure is beyond
* the maximum . Don ' t report it to user space .
*/
if ( Rt > ts - > pressure_max )
return - EINVAL ;
/*
* Note that we delay reporting events by one sample .
* This is done to avoid reporting last sample of the
* touch sequence , which may be incomplete if finger
* leaves the surface before last reading is taken .
*/
if ( timer_pending ( & ts - > timer ) ) {
/* Touch continues */
2010-07-01 01:51:10 +04:00
input_report_key ( input_dev , BTN_TOUCH , 1 ) ;
2010-10-29 01:59:05 +04:00
input_report_abs ( input_dev , ABS_X , ts - > x ) ;
input_report_abs ( input_dev , ABS_Y , ts - > y ) ;
input_report_abs ( input_dev , ABS_PRESSURE , ts - > Rt ) ;
input_sync ( input_dev ) ;
}
ts - > x = x ;
ts - > y = y ;
ts - > Rt = Rt ;
2010-07-01 01:51:10 +04:00
return 0 ;
2009-03-10 06:12:52 +03:00
}
2010-07-01 01:51:10 +04:00
return - EINVAL ;
2009-03-10 06:12:52 +03:00
}
static void ad7879_ts_event_release ( struct ad7879 * ts )
{
struct input_dev * input_dev = ts - > input ;
input_report_abs ( input_dev , ABS_PRESSURE , 0 ) ;
2010-07-01 01:51:10 +04:00
input_report_key ( input_dev , BTN_TOUCH , 0 ) ;
2009-03-10 06:12:52 +03:00
input_sync ( input_dev ) ;
}
static void ad7879_timer ( unsigned long handle )
{
struct ad7879 * ts = ( void * ) handle ;
ad7879_ts_event_release ( ts ) ;
}
static irqreturn_t ad7879_irq ( int irq , void * handle )
{
struct ad7879 * ts = handle ;
2010-06-30 12:40:52 +04:00
ad7879_multi_read ( ts , AD7879_REG_XPLUS , AD7879_NR_SENSE , ts - > conversion_data ) ;
2009-03-10 06:12:52 +03:00
2010-07-01 01:51:10 +04:00
if ( ! ad7879_report ( ts ) )
mod_timer ( & ts - > timer , jiffies + TS_PEN_UP_TIMEOUT ) ;
2009-03-10 06:12:52 +03:00
return IRQ_HANDLED ;
}
2010-07-01 01:50:51 +04:00
static void __ad7879_enable ( struct ad7879 * ts )
2009-03-10 06:12:52 +03:00
{
2010-06-30 12:40:52 +04:00
ad7879_write ( ts , AD7879_REG_CTRL2 , ts - > cmd_crtl2 ) ;
ad7879_write ( ts , AD7879_REG_CTRL3 , ts - > cmd_crtl3 ) ;
ad7879_write ( ts , AD7879_REG_CTRL1 , ts - > cmd_crtl1 ) ;
2010-07-01 01:50:51 +04:00
enable_irq ( ts - > irq ) ;
2009-03-10 06:12:52 +03:00
}
2010-07-01 01:50:51 +04:00
static void __ad7879_disable ( struct ad7879 * ts )
2009-03-10 06:12:52 +03:00
{
2011-08-03 02:41:37 +04:00
u16 reg = ( ts - > cmd_crtl2 & ~ AD7879_PM ( - 1 ) ) |
AD7879_PM ( AD7879_PM_SHUTDOWN ) ;
2010-07-01 01:50:51 +04:00
disable_irq ( ts - > irq ) ;
2009-03-10 06:12:52 +03:00
2010-07-01 01:50:51 +04:00
if ( del_timer_sync ( & ts - > timer ) )
ad7879_ts_event_release ( ts ) ;
2009-03-10 06:12:52 +03:00
2011-08-03 02:41:37 +04:00
ad7879_write ( ts , AD7879_REG_CTRL2 , reg ) ;
2010-07-01 01:50:51 +04:00
}
2009-03-10 06:12:52 +03:00
2010-07-01 01:50:51 +04:00
static int ad7879_open ( struct input_dev * input )
{
struct ad7879 * ts = input_get_drvdata ( input ) ;
2009-03-10 06:12:52 +03:00
2010-07-01 01:50:51 +04:00
/* protected by input->mutex */
if ( ! ts - > disabled & & ! ts - > suspended )
__ad7879_enable ( ts ) ;
return 0 ;
2009-03-10 06:12:52 +03:00
}
2010-07-01 01:50:51 +04:00
static void ad7879_close ( struct input_dev * input )
2009-03-10 06:12:52 +03:00
{
2010-07-01 01:50:51 +04:00
struct ad7879 * ts = input_get_drvdata ( input ) ;
/* protected by input->mutex */
if ( ! ts - > disabled & & ! ts - > suspended )
__ad7879_disable ( ts ) ;
}
2014-11-02 10:04:14 +03:00
static int __maybe_unused ad7879_suspend ( struct device * dev )
2010-07-01 01:50:51 +04:00
{
2011-11-14 12:32:09 +04:00
struct ad7879 * ts = dev_get_drvdata ( dev ) ;
2010-07-01 01:50:51 +04:00
mutex_lock ( & ts - > input - > mutex ) ;
if ( ! ts - > suspended & & ! ts - > disabled & & ts - > input - > users )
__ad7879_disable ( ts ) ;
ts - > suspended = true ;
mutex_unlock ( & ts - > input - > mutex ) ;
2011-11-14 12:32:09 +04:00
return 0 ;
2010-07-01 01:50:51 +04:00
}
2014-11-02 10:04:14 +03:00
static int __maybe_unused ad7879_resume ( struct device * dev )
2010-07-01 01:50:51 +04:00
{
2011-11-14 12:32:09 +04:00
struct ad7879 * ts = dev_get_drvdata ( dev ) ;
2010-07-01 01:50:51 +04:00
mutex_lock ( & ts - > input - > mutex ) ;
2009-03-10 06:12:52 +03:00
2010-07-01 01:50:51 +04:00
if ( ts - > suspended & & ! ts - > disabled & & ts - > input - > users )
__ad7879_enable ( ts ) ;
ts - > suspended = false ;
mutex_unlock ( & ts - > input - > mutex ) ;
2011-11-14 12:32:09 +04:00
return 0 ;
2010-07-01 01:50:51 +04:00
}
2011-11-14 12:32:09 +04:00
SIMPLE_DEV_PM_OPS ( ad7879_pm_ops , ad7879_suspend , ad7879_resume ) ;
EXPORT_SYMBOL ( ad7879_pm_ops ) ;
2010-07-01 01:50:51 +04:00
static void ad7879_toggle ( struct ad7879 * ts , bool disable )
{
mutex_lock ( & ts - > input - > mutex ) ;
if ( ! ts - > suspended & & ts - > input - > users ! = 0 ) {
if ( disable ) {
if ( ts - > disabled )
__ad7879_enable ( ts ) ;
} else {
if ( ! ts - > disabled )
__ad7879_disable ( ts ) ;
}
2009-03-10 06:12:52 +03:00
}
2010-07-01 01:50:51 +04:00
ts - > disabled = disable ;
mutex_unlock ( & ts - > input - > mutex ) ;
2009-03-10 06:12:52 +03:00
}
static ssize_t ad7879_disable_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct ad7879 * ts = dev_get_drvdata ( dev ) ;
return sprintf ( buf , " %u \n " , ts - > disabled ) ;
}
static ssize_t ad7879_disable_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct ad7879 * ts = dev_get_drvdata ( dev ) ;
2011-11-09 22:20:14 +04:00
unsigned int val ;
2009-03-10 06:12:52 +03:00
int error ;
2011-11-09 22:20:14 +04:00
error = kstrtouint ( buf , 10 , & val ) ;
2009-03-10 06:12:52 +03:00
if ( error )
return error ;
2010-07-01 01:50:51 +04:00
ad7879_toggle ( ts , val ) ;
2009-03-10 06:12:52 +03:00
return count ;
}
static DEVICE_ATTR ( disable , 0664 , ad7879_disable_show , ad7879_disable_store ) ;
2010-01-19 11:27:58 +03:00
static struct attribute * ad7879_attributes [ ] = {
& dev_attr_disable . attr ,
NULL
} ;
static const struct attribute_group ad7879_attr_group = {
. attrs = ad7879_attributes ,
} ;
# ifdef CONFIG_GPIOLIB
static int ad7879_gpio_direction_input ( struct gpio_chip * chip ,
unsigned gpio )
2009-03-10 06:12:52 +03:00
{
2010-01-19 11:27:58 +03:00
struct ad7879 * ts = container_of ( chip , struct ad7879 , gc ) ;
int err ;
2009-03-10 06:12:52 +03:00
2010-01-19 11:27:58 +03:00
mutex_lock ( & ts - > mutex ) ;
ts - > cmd_crtl2 | = AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL ;
2010-06-30 12:40:52 +04:00
err = ad7879_write ( ts , AD7879_REG_CTRL2 , ts - > cmd_crtl2 ) ;
2010-01-19 11:27:58 +03:00
mutex_unlock ( & ts - > mutex ) ;
return err ;
2009-03-10 06:12:52 +03:00
}
2010-01-19 11:27:58 +03:00
static int ad7879_gpio_direction_output ( struct gpio_chip * chip ,
unsigned gpio , int level )
2009-03-10 06:12:52 +03:00
{
2010-01-19 11:27:58 +03:00
struct ad7879 * ts = container_of ( chip , struct ad7879 , gc ) ;
int err ;
2009-03-10 06:12:52 +03:00
2010-01-19 11:27:58 +03:00
mutex_lock ( & ts - > mutex ) ;
ts - > cmd_crtl2 & = ~ AD7879_GPIODIR ;
ts - > cmd_crtl2 | = AD7879_GPIO_EN | AD7879_GPIOPOL ;
if ( level )
ts - > cmd_crtl2 | = AD7879_GPIO_DATA ;
else
ts - > cmd_crtl2 & = ~ AD7879_GPIO_DATA ;
2010-06-30 12:40:52 +04:00
err = ad7879_write ( ts , AD7879_REG_CTRL2 , ts - > cmd_crtl2 ) ;
2010-01-19 11:27:58 +03:00
mutex_unlock ( & ts - > mutex ) ;
return err ;
}
static int ad7879_gpio_get_value ( struct gpio_chip * chip , unsigned gpio )
{
struct ad7879 * ts = container_of ( chip , struct ad7879 , gc ) ;
u16 val ;
2009-03-10 06:12:52 +03:00
mutex_lock ( & ts - > mutex ) ;
2010-06-30 12:40:52 +04:00
val = ad7879_read ( ts , AD7879_REG_CTRL2 ) ;
2009-03-10 06:12:52 +03:00
mutex_unlock ( & ts - > mutex ) ;
2010-01-19 11:27:58 +03:00
return ! ! ( val & AD7879_GPIO_DATA ) ;
2009-03-10 06:12:52 +03:00
}
2010-01-19 11:27:58 +03:00
static void ad7879_gpio_set_value ( struct gpio_chip * chip ,
unsigned gpio , int value )
{
struct ad7879 * ts = container_of ( chip , struct ad7879 , gc ) ;
2009-03-10 06:12:52 +03:00
2010-01-19 11:27:58 +03:00
mutex_lock ( & ts - > mutex ) ;
if ( value )
ts - > cmd_crtl2 | = AD7879_GPIO_DATA ;
else
ts - > cmd_crtl2 & = ~ AD7879_GPIO_DATA ;
2009-03-10 06:12:52 +03:00
2010-06-30 12:40:52 +04:00
ad7879_write ( ts , AD7879_REG_CTRL2 , ts - > cmd_crtl2 ) ;
2010-01-19 11:27:58 +03:00
mutex_unlock ( & ts - > mutex ) ;
}
2010-06-30 12:40:52 +04:00
static int ad7879_gpio_add ( struct ad7879 * ts ,
const struct ad7879_platform_data * pdata )
2010-01-19 11:27:58 +03:00
{
int ret = 0 ;
2010-07-01 01:50:51 +04:00
mutex_init ( & ts - > mutex ) ;
2010-01-19 11:27:58 +03:00
if ( pdata - > gpio_export ) {
ts - > gc . direction_input = ad7879_gpio_direction_input ;
ts - > gc . direction_output = ad7879_gpio_direction_output ;
ts - > gc . get = ad7879_gpio_get_value ;
ts - > gc . set = ad7879_gpio_set_value ;
ts - > gc . can_sleep = 1 ;
ts - > gc . base = pdata - > gpio_base ;
ts - > gc . ngpio = 1 ;
ts - > gc . label = " AD7879-GPIO " ;
ts - > gc . owner = THIS_MODULE ;
2010-06-30 12:40:52 +04:00
ts - > gc . dev = ts - > dev ;
2010-01-19 11:27:58 +03:00
ret = gpiochip_add ( & ts - > gc ) ;
if ( ret )
2010-06-30 12:40:52 +04:00
dev_err ( ts - > dev , " failed to register gpio %d \n " ,
2010-01-19 11:27:58 +03:00
ts - > gc . base ) ;
}
return ret ;
}
2010-06-30 12:40:52 +04:00
static void ad7879_gpio_remove ( struct ad7879 * ts )
2010-01-19 11:27:58 +03:00
{
2013-12-06 07:21:10 +04:00
const struct ad7879_platform_data * pdata = dev_get_platdata ( ts - > dev ) ;
2010-01-19 11:27:58 +03:00
2014-07-13 00:30:14 +04:00
if ( pdata - > gpio_export )
gpiochip_remove ( & ts - > gc ) ;
2010-01-19 11:27:58 +03:00
}
# else
2010-06-30 12:40:52 +04:00
static inline int ad7879_gpio_add ( struct ad7879 * ts ,
const struct ad7879_platform_data * pdata )
2010-01-19 11:27:58 +03:00
{
return 0 ;
}
2010-06-30 12:40:52 +04:00
static inline void ad7879_gpio_remove ( struct ad7879 * ts )
2010-01-19 11:27:58 +03:00
{
}
# endif
2009-03-10 06:12:52 +03:00
2010-06-30 12:40:52 +04:00
struct ad7879 * ad7879_probe ( struct device * dev , u8 devid , unsigned int irq ,
const struct ad7879_bus_ops * bops )
2009-03-10 06:12:52 +03:00
{
2013-12-06 07:21:10 +04:00
struct ad7879_platform_data * pdata = dev_get_platdata ( dev ) ;
2010-06-30 12:40:52 +04:00
struct ad7879 * ts ;
2009-03-10 06:12:52 +03:00
struct input_dev * input_dev ;
int err ;
u16 revid ;
2010-06-30 12:40:52 +04:00
if ( ! irq ) {
dev_err ( dev , " no IRQ? \n " ) ;
err = - EINVAL ;
goto err_out ;
2009-03-10 06:12:52 +03:00
}
if ( ! pdata ) {
2010-06-30 12:40:52 +04:00
dev_err ( dev , " no platform data? \n " ) ;
err = - EINVAL ;
goto err_out ;
2009-03-10 06:12:52 +03:00
}
2010-06-30 12:40:52 +04:00
ts = kzalloc ( sizeof ( * ts ) , GFP_KERNEL ) ;
2009-03-10 06:12:52 +03:00
input_dev = input_allocate_device ( ) ;
2010-06-30 12:40:52 +04:00
if ( ! ts | | ! input_dev ) {
err = - ENOMEM ;
goto err_free_mem ;
}
2009-03-10 06:12:52 +03:00
2010-06-30 12:40:52 +04:00
ts - > bops = bops ;
ts - > dev = dev ;
2009-03-10 06:12:52 +03:00
ts - > input = input_dev ;
2010-07-01 01:50:51 +04:00
ts - > irq = irq ;
2012-07-06 21:44:19 +04:00
ts - > swap_xy = pdata - > swap_xy ;
2009-03-10 06:12:52 +03:00
setup_timer ( & ts - > timer , ad7879_timer , ( unsigned long ) ts ) ;
2010-06-30 12:40:52 +04:00
2009-03-10 06:12:52 +03:00
ts - > x_plate_ohms = pdata - > x_plate_ohms ? : 400 ;
ts - > pressure_max = pdata - > pressure_max ? : ~ 0 ;
ts - > first_conversion_delay = pdata - > first_conversion_delay ;
ts - > acquisition_time = pdata - > acquisition_time ;
ts - > averaging = pdata - > averaging ;
ts - > pen_down_acc_interval = pdata - > pen_down_acc_interval ;
ts - > median = pdata - > median ;
2010-06-30 12:40:52 +04:00
snprintf ( ts - > phys , sizeof ( ts - > phys ) , " %s/input0 " , dev_name ( dev ) ) ;
2009-03-10 06:12:52 +03:00
input_dev - > name = " AD7879 Touchscreen " ;
input_dev - > phys = ts - > phys ;
2010-06-30 12:40:52 +04:00
input_dev - > dev . parent = dev ;
input_dev - > id . bustype = bops - > bustype ;
2009-03-10 06:12:52 +03:00
2010-07-01 01:50:51 +04:00
input_dev - > open = ad7879_open ;
input_dev - > close = ad7879_close ;
input_set_drvdata ( input_dev , ts ) ;
2009-03-10 06:12:52 +03:00
__set_bit ( EV_ABS , input_dev - > evbit ) ;
__set_bit ( ABS_X , input_dev - > absbit ) ;
__set_bit ( ABS_Y , input_dev - > absbit ) ;
__set_bit ( ABS_PRESSURE , input_dev - > absbit ) ;
2010-07-01 01:51:10 +04:00
__set_bit ( EV_KEY , input_dev - > evbit ) ;
__set_bit ( BTN_TOUCH , input_dev - > keybit ) ;
2009-03-10 06:12:52 +03:00
input_set_abs_params ( input_dev , ABS_X ,
pdata - > x_min ? : 0 ,
pdata - > x_max ? : MAX_12BIT ,
0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_Y ,
pdata - > y_min ? : 0 ,
pdata - > y_max ? : MAX_12BIT ,
0 , 0 ) ;
input_set_abs_params ( input_dev , ABS_PRESSURE ,
pdata - > pressure_min , pdata - > pressure_max , 0 , 0 ) ;
2010-06-30 12:40:52 +04:00
err = ad7879_write ( ts , AD7879_REG_CTRL2 , AD7879_RESET ) ;
2009-03-10 06:12:52 +03:00
if ( err < 0 ) {
2010-06-30 12:40:52 +04:00
dev_err ( dev , " Failed to write %s \n " , input_dev - > name ) ;
2009-03-10 06:12:52 +03:00
goto err_free_mem ;
}
2010-06-30 12:40:52 +04:00
revid = ad7879_read ( ts , AD7879_REG_REVID ) ;
input_dev - > id . product = ( revid & 0xff ) ;
input_dev - > id . version = revid > > 8 ;
if ( input_dev - > id . product ! = devid ) {
dev_err ( dev , " Failed to probe %s (%x vs %x) \n " ,
input_dev - > name , devid , revid ) ;
2009-03-10 06:12:52 +03:00
err = - ENODEV ;
goto err_free_mem ;
}
2010-01-19 11:27:58 +03:00
ts - > cmd_crtl3 = AD7879_YPLUS_BIT |
AD7879_XPLUS_BIT |
AD7879_Z2_BIT |
AD7879_Z1_BIT |
AD7879_TEMPMASK_BIT |
AD7879_AUXVBATMASK_BIT |
AD7879_GPIOALERTMASK_BIT ;
ts - > cmd_crtl2 = AD7879_PM ( AD7879_PM_DYN ) | AD7879_DFR |
AD7879_AVG ( ts - > averaging ) |
AD7879_MFS ( ts - > median ) |
AD7879_FCD ( ts - > first_conversion_delay ) ;
ts - > cmd_crtl1 = AD7879_MODE_INT | AD7879_MODE_SEQ1 |
AD7879_ACQ ( ts - > acquisition_time ) |
AD7879_TMR ( ts - > pen_down_acc_interval ) ;
2010-06-30 12:40:52 +04:00
err = request_threaded_irq ( ts - > irq , NULL , ad7879_irq ,
2012-07-05 00:02:56 +04:00
IRQF_TRIGGER_FALLING | IRQF_ONESHOT ,
2010-06-30 12:40:52 +04:00
dev_name ( dev ) , ts ) ;
2009-03-10 06:12:52 +03:00
if ( err ) {
2010-06-30 12:40:52 +04:00
dev_err ( dev , " irq %d busy? \n " , ts - > irq ) ;
2009-03-10 06:12:52 +03:00
goto err_free_mem ;
}
2010-07-01 01:50:51 +04:00
__ad7879_disable ( ts ) ;
2010-06-30 12:40:52 +04:00
err = sysfs_create_group ( & dev - > kobj , & ad7879_attr_group ) ;
2009-03-10 06:12:52 +03:00
if ( err )
goto err_free_irq ;
2010-06-30 12:40:52 +04:00
err = ad7879_gpio_add ( ts , pdata ) ;
2009-03-10 06:12:52 +03:00
if ( err )
goto err_remove_attr ;
2010-01-19 11:27:58 +03:00
err = input_register_device ( input_dev ) ;
if ( err )
goto err_remove_gpio ;
2010-06-30 12:40:52 +04:00
return ts ;
2009-03-10 06:12:52 +03:00
2010-01-19 11:27:58 +03:00
err_remove_gpio :
2010-06-30 12:40:52 +04:00
ad7879_gpio_remove ( ts ) ;
2009-03-10 06:12:52 +03:00
err_remove_attr :
2010-06-30 12:40:52 +04:00
sysfs_remove_group ( & dev - > kobj , & ad7879_attr_group ) ;
2009-03-10 06:12:52 +03:00
err_free_irq :
2010-06-30 12:40:52 +04:00
free_irq ( ts - > irq , ts ) ;
2009-03-10 06:12:52 +03:00
err_free_mem :
input_free_device ( input_dev ) ;
2010-06-30 12:40:52 +04:00
kfree ( ts ) ;
err_out :
return ERR_PTR ( err ) ;
2009-03-10 06:12:52 +03:00
}
2010-06-30 12:40:52 +04:00
EXPORT_SYMBOL ( ad7879_probe ) ;
2009-03-10 06:12:52 +03:00
2010-06-30 12:40:52 +04:00
void ad7879_remove ( struct ad7879 * ts )
2009-03-10 06:12:52 +03:00
{
2010-06-30 12:40:52 +04:00
ad7879_gpio_remove ( ts ) ;
sysfs_remove_group ( & ts - > dev - > kobj , & ad7879_attr_group ) ;
free_irq ( ts - > irq , ts ) ;
2009-03-10 06:12:52 +03:00
input_unregister_device ( ts - > input ) ;
kfree ( ts ) ;
}
2010-06-30 12:40:52 +04:00
EXPORT_SYMBOL ( ad7879_remove ) ;
2009-03-10 06:12:52 +03:00
MODULE_AUTHOR ( " Michael Hennerich <hennerich@blackfin.uclinux.org> " ) ;
MODULE_DESCRIPTION ( " AD7879(-1) touchscreen Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;