blob: c2fe799c396789bc8659f235262e54b735de9ce8 [file] [log] [blame]
/* drivers/input/touchscreen/cypress_tma140_lucas.c
*
* Copyright (C) 2007 Google, Inc.
*
* 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.
*
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/earlysuspend.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <mach/gpio.h>
#include <linux/device.h>
#include <linux/regulator/consumer.h>
#include <linux/irq.h>
#include <linux/firmware.h>
#include <linux/uaccess.h>
/* firmware - update */
#define MAX_X 480
#define MAX_Y 360
#define TSP_INT 86
#define TSP_SDA 85
#define TSP_SCL 87
#define TOUCH_EN 22
#define MAX_KEYS 2
#define MAX_USING_FINGER_NUM 2
static const int touchkey_keycodes[] = {
KEY_MENU,
KEY_BACK,
//KEY_HOME,
//KEY_SEARCH,
};
#define TOUCH_ON 1
#define TOUCH_OFF 0
#define TRUE 1
#define FALSE 0
#define I2C_RETRY_CNT 2
//#define __TOUCH_DEBUG__
#define USE_THREADED_IRQ 1
//#define __TOUCH_KEYLED__
static struct regulator *touch_regulator=NULL;
#if defined (__TOUCH_KEYLED__)
static struct regulator *touchkeyled_regulator=NULL;
#endif
#if USE_THREADED_IRQ
#else
static struct workqueue_struct *touch_wq;
#endif
static int touchkey_status[MAX_KEYS];
#define TK_STATUS_PRESS 1
#define TK_STATUS_RELEASE 0
int tsp_irq;
int st_old;
typedef struct
{
int8_t id; /*!< (id>>8) + size */
int8_t status;/////////////IC
int8_t z; /*!< dn>0, up=0, none=-1 */
int16_t x; /*!< X */
int16_t y; /*!< Y */
} report_finger_info_t;
static report_finger_info_t fingerInfo[MAX_USING_FINGER_NUM];
struct touch_data {
uint16_t addr;
struct i2c_client *client;
struct input_dev *input_dev;
int use_irq;
struct hrtimer timer; ////////////////////////IC
struct work_struct work;
//struct work_struct work_timer; ////////////////////////IC
struct early_suspend early_suspend;
};
struct touch_data *ts_global;
/* firmware - update */
static int firmware_ret_val = -1;
static int HW_ver = -1;
unsigned char tsp_special_update = 0;
static char IsfwUpdate[20]={0};
/* touch information*/
unsigned char touch_vendor_id = 0;
unsigned char touch_hw_ver = 0;
unsigned char touch_sw_ver = 0;
int tsp_irq_num = 0;
int tsp_workqueue_num = 0;
int tsp_threadedirq_num = 0;
int g_touch_info_x = 0;
int g_touch_info_y = 0;
int g_touch_info_press = 0;
extern int cypress_update( int );
int tsp_i2c_read(u8 reg, unsigned char *rbuf, int buf_size);
/* sys fs */
struct class *touch_class;
EXPORT_SYMBOL(touch_class);
struct device *firmware_dev;
EXPORT_SYMBOL(firmware_dev);
static ssize_t firmware_In_Binary(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t firmware_In_TSP(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t firm_update(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t firmware_update_status(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_show_tma140(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_enable_tma140(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t raw_disable_tma140(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t read_rawdata_tma140(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t read_difference_tma140(struct device *dev, struct device_attribute *attr, char *buf);
static ssize_t rawdata_pass_fail_tma140(struct device *dev, struct device_attribute *attr, char *buf);
static DEVICE_ATTR(phone_fw_ver, 0777, firmware_In_Binary, NULL);
static DEVICE_ATTR(part_fw_ver, 0777, firmware_In_TSP, NULL);
//static DEVICE_ATTR(fw_update , 0777, firm_update, firm_update);
static DEVICE_ATTR(fw_update , 0777, firm_update, NULL );
static DEVICE_ATTR(raw, 0444, raw_show_tma140, NULL) ;
static DEVICE_ATTR(raw_enable, 0444, raw_enable_tma140, NULL) ;
static DEVICE_ATTR(raw_disable, 0444, raw_disable_tma140, NULL) ;
static DEVICE_ATTR(rawdata_read, 0444, read_rawdata_tma140, NULL) ;
static DEVICE_ATTR(difference_read, 0444, read_difference_tma140, NULL) ;
static DEVICE_ATTR(raw_value, 0444, rawdata_pass_fail_tma140, NULL) ;
//static DEVICE_ATTR(fw_upstatus, 0777, firmware_update_status, firmware_update_status);
static DEVICE_ATTR(fw_upstatus, 0777, firmware_update_status, NULL);
/* sys fs */
static int tsp_testmode = 0;
static int tsp_irq_operation = 0;
static unsigned int touch_present = 0;
#define FW_DOWNLOADING "Downloading"
#define FW_DOWNLOAD_COMPLETE "Complete"
#define FW_DOWNLOAD_FAIL "FAIL"
#define FWUP_NOW -1
#ifdef CONFIG_HAS_EARLYSUSPEND
static void ts_early_suspend(struct early_suspend *h);
static void ts_late_resume(struct early_suspend *h);
#endif
extern int bcm_gpio_pull_up(unsigned int gpio, bool up);
extern int bcm_gpio_pull_up_down_enable(unsigned int gpio, bool enable);
extern int set_irq_type(unsigned int irq, unsigned int type);
void touch_ctrl_regulator(int on_off)
{
if(on_off==TOUCH_ON)
{
gpio_request(TOUCH_EN,"Touch_en");
gpio_direction_output(TOUCH_EN,1);
gpio_set_value(TOUCH_EN,1);
gpio_free(TOUCH_EN);
#if defined (__TOUCH_KEYLED__)
regulator_set_voltage(touchkeyled_regulator,3300000,3300000);
regulator_enable(touchkeyled_regulator);
#endif
}
else
{
gpio_request(TOUCH_EN,"Touch_en");
gpio_direction_output(TOUCH_EN,0);
gpio_set_value(TOUCH_EN,0);
gpio_free(TOUCH_EN);
#if defined (__TOUCH_KEYLED__)
regulator_disable(touchkeyled_regulator);
#endif
}
}
EXPORT_SYMBOL(touch_ctrl_regulator);
int tsp_reset( void )
{
int ret=1;
#if defined(__TOUCH_DEBUG__)
printk("[TSP] %s, %d\n", __func__, __LINE__ );
#endif
if (ts_global->use_irq)
{
disable_irq(ts_global->client->irq);
}
touch_ctrl_regulator(0);
gpio_direction_output( TSP_SCL , 0 );
gpio_direction_output( TSP_SDA , 0 );
//gpio_direction_output( TSP_INT , 0 );
msleep(200);
gpio_direction_output( TSP_SCL , 1 );
gpio_direction_output( TSP_SDA , 1 );
//gpio_direction_output( TSP_INT , 1 );
touch_ctrl_regulator(1);
msleep(10);
enable_irq(ts_global->client->irq);
return ret;
}
static void process_key_event(uint8_t tsk_msg)
{
int i;
int keycode= 0;
int st_new;
printk("[TSP] process_key_event : %d\n", tsk_msg);
if( tsk_msg == 0)
{
input_report_key(ts_global->input_dev, st_old, 0);
printk("[TSP] release keycode: %4d, keypress: %4d\n", st_old, 0);
}
else{
//check each key status
for(i = 0; i < MAX_KEYS; i++)
{
st_new = (tsk_msg>>(i)) & 0x1;
if (st_new ==1)
{
keycode = touchkey_keycodes[i];
input_report_key(ts_global->input_dev, keycode, 1);
printk("[TSP] press keycode: %4d, keypress: %4d\n", keycode, 1);
}
st_old = keycode;
}
}
}
#if USE_THREADED_IRQ
static irqreturn_t ts_work_func(int irq, void *dev_id)
#else
static void ts_work_func(struct work_struct *work)
#endif
{
int ret=0;
//uint8_t buf[12];// 02h ~ 0Dh
uint8_t buf[29];// 02h ~ 1Fh
uint8_t buf_key[1];
uint8_t i2c_addr = 0x02;
int i = 0;
int finger = 0;
#if USE_THREADED_IRQ
struct touch_data *ts = dev_id;
if(tsp_testmode)
return IRQ_HANDLED;
#else
struct touch_data *ts = container_of(work, struct touch_data, work);
#endif
ret = tsp_i2c_read( i2c_addr, buf, sizeof(buf));
if (ret <= 0) {
printk("[TSP] i2c failed : ret=%d, ln=%d\n",ret, __LINE__);
goto work_func_out;
}
/*
printk("[TSP] buf[0]:%d, buf[1]:%d, buf[2]=%d, buf[3]=%d, buf[4]=%d\n", buf[0], buf[1], buf[2], buf[3], buf[4]);
printk("[TSP] buf[5]:%d, buf[6]:%d, buf[7]=%d, buf[8]=%d, buf[9]=%d\n", buf[5], buf[6], buf[7], buf[8], buf[9]);
printk("[TSP] buf[10]:%d, buf[11]:%d, buf[12]=%d, buf[13]=%d, buf[14]=%d\n", buf[10], buf[11], buf[12], buf[13], buf[14]);
printk("[TSP] buf[15]:%d, buf[16]:%d, buf[17]=%d, buf[18]=%d, buf[19]=%d\n", buf[15], buf[16], buf[17], buf[18], buf[19]);
printk("[TSP] buf[20]:%d, buf[21]:%d, buf[22]=%d, buf[23]=%d, buf[24]=%d\n", buf[20], buf[21], buf[22], buf[23], buf[24]);
printk("[TSP] buf[25]:%d, buf[26]:%d, buf[27]=%d, buf[28]=%d=%d\n", buf[25], buf[26], buf[27], buf[28]);
*/
finger = buf[0] & 0x0F; //number of touch finger
buf_key[0] = buf[25] & 0x03; //information of touch key
fingerInfo[0].x = (buf[1] << 8) |buf[2];
fingerInfo[0].y = (buf[3] << 8) |buf[4];
fingerInfo[0].z = buf[5];
fingerInfo[0].id = buf[6] >>4;
fingerInfo[1].x = (buf[7] << 8) |buf[8];
fingerInfo[1].y = (buf[9] << 8) |buf[10];
fingerInfo[1].z = buf[11];
fingerInfo[1].id = buf[6] & 0xf;
/*********************hash
if ( board_hw_revision >= 0x2 && HW_ver==1 )
{
fingerInfo[0].x = 240 - fingerInfo[0].x;
fingerInfo[0].y = 320 - fingerInfo[0].y;
fingerInfo[1].x = 240 - fingerInfo[1].x;
fingerInfo[1].y = 320 - fingerInfo[1].y;
// fingerInfo[0].x = 320 - fingerInfo[0].x;
// fingerInfo[1].y = 480 - fingerInfo[1].y;
}
************************/
// print message
if(finger == 0)
{
process_key_event(buf_key[0]);
}
/* check touch event */
for ( i= 0; i<MAX_USING_FINGER_NUM; i++ )
{
//////////////////////////////////////////////////IC
if(fingerInfo[i].id >=1) // press interrupt
{
if(fingerInfo[i].status != -2) // force release
fingerInfo[i].status = 1;
else
fingerInfo[i].status = -2;
}
else if(fingerInfo[i].id ==0) // release interrupt (only first finger)
{
if(fingerInfo[i].status == 1) // prev status is press
fingerInfo[i].status = 0;
else if(fingerInfo[i].status == 0 || fingerInfo[i].status == -2) // release already or force release
fingerInfo[i].status = -1;
}
if(fingerInfo[i].status < 0) continue;
//////////////////////////////////////////////////IC
input_report_abs(ts->input_dev, ABS_MT_POSITION_X, fingerInfo[i].x);
input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, fingerInfo[i].y);
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, fingerInfo[i].status);
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, fingerInfo[i].z);
input_mt_sync(ts->input_dev);
input_report_key(ts->input_dev, BTN_TOUCH, fingerInfo[i].status); /*must be added for ICS*/
#if defined(__TOUCH_DEBUG__)
printk("[TSP] i[%d] id[%d] xyz[%d, %d, %x] status[%x]\n", i, fingerInfo[i].id, fingerInfo[i].x, fingerInfo[i].y, fingerInfo[i].z, fingerInfo[i].status);
#endif
}
input_sync(ts->input_dev);
work_func_out:
if (ts->use_irq)
{
#if USE_THREADED_IRQ
#else
enable_irq(ts->client->irq);
#endif
}
tsp_irq_operation = 0;
#if USE_THREADED_IRQ
return IRQ_HANDLED;
#else
#endif
}
int tsp_i2c_read(u8 reg, unsigned char *rbuf, int buf_size)
{
int i, ret=-1;
struct i2c_msg rmsg;
uint8_t start_reg;
for (i = 0; i < I2C_RETRY_CNT; i++)
{
rmsg.addr = ts_global->client->addr;
rmsg.flags = 0;//I2C_M_WR;
rmsg.len = 1;
rmsg.buf = &start_reg;
start_reg = reg;
ret = i2c_transfer(ts_global->client->adapter, &rmsg, 1);
if(ret >= 0)
{
rmsg.flags = I2C_M_RD;
rmsg.len = buf_size;
rmsg.buf = rbuf;
ret = i2c_transfer(ts_global->client->adapter, &rmsg, 1 );
if (ret >= 0)
break; // i2c success
}
if( i == (I2C_RETRY_CNT - 1) )
{
printk("[TSP] Error code : %d, %d\n", __LINE__, ret );
}
}
return ret;
}
static enum hrtimer_restart ts_timer_func(struct hrtimer *timer)
{
#if USE_THREADED_IRQ
#else
queue_work(touch_wq, &ts_global->work);
#endif
hrtimer_start(&ts_global->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
static irqreturn_t ts_irq_handler(int irq, void *dev_id)
{
#ifndef USE_THREADED_IRQ
struct touch_data *ts = dev_id;
#endif
if(tsp_testmode)
return IRQ_WAKE_THREAD;
tsp_irq_operation = 1;
//printk("[TSP] %s, %d\n", __func__, __LINE__ );
#if USE_THREADED_IRQ
#else
disable_irq_nosync(ts->client->irq);
#endif
#if USE_THREADED_IRQ
return IRQ_WAKE_THREAD;
#else
queue_work(touch_wq, &ts->work);
return IRQ_HANDLED;
#endif
}
int ts_check(void)
{
int ret, i;
uint8_t buf_tmp[3]={0,0,0};
int retry = 3;
ret = tsp_i2c_read( 0x1B, buf_tmp, sizeof(buf_tmp));
// i2c read retry
if(ret <= 0)
{
for(i=0; i<retry;i++)
{
ret=tsp_i2c_read( 0x1B, buf_tmp, sizeof(buf_tmp));
if(ret > 0)
break;
}
}
if (ret <= 0)
{
printk("[TSP][%s] %s\n", __func__,"Failed i2c");
ret = 0;
}
else
{
printk("[TSP][%s] %s\n", __func__,"Passed i2c");
printk("[TSP][%s][SlaveAddress : 0x%x][VendorID : 0x%x] [HW : 0x%x] [SW : 0x%x]\n", __func__,ts_global->client->addr, buf_tmp[0], buf_tmp[1], buf_tmp[2]);
if ( buf_tmp[0] == 0xf0 )//(ts->hw_rev == 0) && (ts->fw_ver == 2))
{
ret = 1;
printk("[TSP][%s] %s\n", __func__,"Passed ts_check");
}
else
{
ret = 0;
printk("[TSP][%s] %s\n", __func__,"Failed ts_check");
}
}
return ret;
}
static int ts_probe(
struct i2c_client *client, const struct i2c_device_id *id)
{
struct touch_data *ts;
uint8_t buf_tmp[3]={0,0,0};
uint8_t addr[1];
int i;
int ret = 0, key = 0;
printk("[TSP] %s, %d\n", __func__, __LINE__ );
// touch_ctrl_regulator(TOUCH_ON);
// msleep(100);
touch_ctrl_regulator(TOUCH_OFF);
msleep(200);
touch_ctrl_regulator(TOUCH_ON);
msleep(100);
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (ts == NULL) {
ret = -ENOMEM;
goto err_alloc_data_failed;
}
#if USE_THREADED_IRQ
#else
INIT_WORK(&ts->work, ts_work_func);
#endif
ts->client = client;
i2c_set_clientdata(client, ts);
ts_global = ts;
tsp_irq=client->irq;
printk("[TSP] tsp_irq = %d\n",tsp_irq);
ts->input_dev = input_allocate_device();
if (ts->input_dev == NULL) {
ret = -ENOMEM;
printk(KERN_ERR "ts_probe: Failed to allocate input device\n");
goto err_input_dev_alloc_failed;
}
ts->input_dev->name = "sec_touchscreen";
ts->input_dev->keybit[BIT_WORD(KEY_POWER)] |= BIT_MASK(KEY_POWER);
set_bit(EV_SYN, ts->input_dev->evbit);
set_bit(EV_KEY, ts->input_dev->evbit);
set_bit(BTN_TOUCH, ts->input_dev->keybit);
set_bit(EV_ABS, ts->input_dev->evbit);
set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); /*must be added for ICS*/
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, MAX_X, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, MAX_Y, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
for(key = 0; key < MAX_KEYS ; key++)
input_set_capability(ts->input_dev, EV_KEY, touchkey_keycodes[key]);
// for TSK
for(key = 0; key < MAX_KEYS ; key++)
touchkey_status[key] = TK_STATUS_RELEASE;
/* ts->input_dev->name = ts->keypad_info->name; */
ret = input_register_device(ts->input_dev);
if (ret) {
printk(KERN_ERR "ts_probe: Unable to register %s input device\n", ts->input_dev->name);
goto err_input_register_device_failed;
}
printk("[TSP] %s, irq=%d\n", __func__, client->irq );
if (client->irq) {
#if USE_THREADED_IRQ
ret = request_threaded_irq(client->irq, ts_irq_handler, ts_work_func, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts);
#else
ret = request_irq(client->irq, ts_irq_handler, IRQF_TRIGGER_FALLING, client->name, ts);
#endif
if (ret == 0)
ts->use_irq = 1;
else
dev_err(&client->dev, "request_irq failed\n");
}
if (!ts->use_irq) {
hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
ts->timer.function = ts_timer_func;
hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
}
#ifdef CONFIG_HAS_EARLYSUSPEND
ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
ts->early_suspend.suspend = ts_early_suspend;
ts->early_suspend.resume = ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
printk(KERN_INFO "ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
/* sys fs */
touch_class = class_create(THIS_MODULE, "touch");
if (IS_ERR(touch_class))
pr_err("Failed to create class(touch)!\n");
firmware_dev = device_create(touch_class, NULL, 0, NULL, "firmware");
if (IS_ERR(firmware_dev))
pr_err("Failed to create device(firmware)!\n");
if (device_create_file(firmware_dev, &dev_attr_phone_fw_ver) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_phone_fw_ver.attr.name);
if (device_create_file(firmware_dev, &dev_attr_part_fw_ver) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_part_fw_ver.attr.name);
if (device_create_file(firmware_dev, &dev_attr_fw_update) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_fw_update.attr.name);
if (device_create_file(firmware_dev, &dev_attr_raw) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_raw.attr.name);
if (device_create_file(firmware_dev, &dev_attr_fw_upstatus) < 0)
pr_err("[TSP] Failed to create device file(%s)!\n", dev_attr_fw_upstatus.attr.name);
if (device_create_file(firmware_dev, &dev_attr_raw_enable) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_raw_enable.attr.name);
if (device_create_file(firmware_dev, &dev_attr_raw_disable) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_raw_disable.attr.name);
if (device_create_file(firmware_dev, &dev_attr_rawdata_read) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_rawdata_read.attr.name);
if (device_create_file(firmware_dev, &dev_attr_difference_read) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_difference_read.attr.name);
if (device_create_file(firmware_dev, &dev_attr_raw_value) < 0)
pr_err("Failed to create device file(%s)!\n", dev_attr_raw_value.attr.name);
/* Check point - i2c check - start */
for (i = 0; i < 2; i++)
{
printk("[TSP] %s, %d, send\n", __func__, __LINE__ );
addr[0] = 0x1B; //address
ret = i2c_master_send(ts_global->client, addr, 1);
if (ret >= 0)
{
printk("[TSP] %s, %d, receive\n", __func__, __LINE__ );
ret = i2c_master_recv(ts_global->client, buf_tmp, 3);
if (ret >= 0)
break; // i2c success
}
printk("[TSP] %s, %d, fail\n", __func__, __LINE__ );
}
touch_vendor_id = buf_tmp[0];
touch_hw_ver = buf_tmp[1];
touch_sw_ver = buf_tmp[2];
printk("[TSP] %s:%d, ver tsp=%x, HW=%x, SW=%x\n", __func__,__LINE__, touch_vendor_id, touch_hw_ver, touch_sw_ver);
HW_ver = touch_hw_ver;
if(ret >= 0)
{
touch_present = 1;
//hrtimer_start(&ts->timer, ktime_set(2, 0), HRTIMER_MODE_REL);
}
else//if(ret < 0)
{
printk(KERN_ERR "i2c_transfer failed\n");
printk("[TSP] %s, ln:%d, Failed to register TSP!!!\n\tcheck the i2c line!!!, ret=%d\n", __func__,__LINE__, ret);
//goto err_check_functionality_failed;
}
/* Check point - i2c check - end */
return 0;
err_input_register_device_failed:
input_free_device(ts->input_dev);
err_input_dev_alloc_failed:
kfree(ts);
err_alloc_data_failed:
//err_check_functionality_failed:
return ret;
}
static int ts_remove(struct i2c_client *client)
{
struct touch_data *ts = i2c_get_clientdata(client);
unregister_early_suspend(&ts->early_suspend);
if (ts->use_irq)
free_irq(client->irq, ts);
//else
// hrtimer_cancel(&ts->timer);
input_unregister_device(ts->input_dev);
kfree(ts);
return 0;
}
static int ts_suspend(struct i2c_client *client, pm_message_t mesg)
{
struct touch_data *ts = i2c_get_clientdata(client);
printk("[TSP] %s+\n", __func__ );
if (ts->use_irq)
{
disable_irq(client->irq);
}
gpio_direction_output( TSP_INT , 0 );
gpio_direction_output( TSP_SCL , 0 );
gpio_direction_output( TSP_SDA , 0 );
#if USE_THREADED_IRQ
#else
ret = cancel_work_sync(&ts->work);
#endif
msleep(20);
touch_ctrl_regulator(TOUCH_OFF);
printk("[TSP] %s-\n", __func__ );
return 0;
}
static int ts_resume(struct i2c_client *client)
{
int ret;
uint8_t i2c_addr = 0x1D;
uint8_t buf[1];
gpio_direction_output( TSP_SCL , 1 );
gpio_direction_output( TSP_SDA , 1 );
gpio_direction_input(TSP_INT);
touch_ctrl_regulator(TOUCH_ON);
msleep(100);
ret = tsp_i2c_read( i2c_addr, buf, sizeof(buf));
printk("[TSP] %s:%d, ver SW=%x\n", __func__,__LINE__, buf[0] );
enable_irq(client->irq);
printk("[TSP] %s-\n", __func__ );
return 0;
}
#ifdef CONFIG_HAS_EARLYSUSPEND
static void ts_early_suspend(struct early_suspend *h)
{
struct touch_data *ts;
ts = container_of(h, struct touch_data, early_suspend);
ts_suspend(ts->client, PMSG_SUSPEND);
}
static void ts_late_resume(struct early_suspend *h)
{
struct touch_data *ts;
ts = container_of(h, struct touch_data, early_suspend);
ts_resume(ts->client);
}
#endif
static const struct i2c_device_id ts_id[] = {
{ "cypress-tma140", 0 },
{ }
};
static struct i2c_driver ts_driver = {
.probe = ts_probe,
.remove = ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = ts_suspend,
.resume = ts_resume,
#endif
.id_table = ts_id,
.driver = {
.name = "cypress-tma140",
},
};
static int __devinit tsp_driver_init(void)
{
printk("[TSP] %s\n", __func__ );
gpio_request(TSP_INT, "ts_irq");
gpio_direction_input(TSP_INT);
irq_set_irq_type(gpio_to_irq(TSP_INT), IRQ_TYPE_EDGE_FALLING);
gpio_direction_output( TSP_SCL , 1 );
gpio_direction_output( TSP_SDA , 1 );
#if USE_THREADED_IRQ
#else
touch_wq = create_singlethread_workqueue("touch_wq");
if (!touch_wq)
return -ENOMEM;
#endif
// touch_regulator = regulator_get(NULL,"touch_vcc");
#if defined (__TOUCH_KEYLED__)
touchkeyled_regulator = regulator_get(NULL,"touch_keyled");
#endif
return i2c_add_driver(&ts_driver);
}
static void __exit tsp_driver_exit(void)
{
if (touch_regulator)
{
regulator_put(touch_regulator);
touch_regulator = NULL;
}
#if defined (__TOUCH_KEYLED__)
if (touchkeyled_regulator)
{
regulator_put(touchkeyled_regulator);
touchkeyled_regulator = NULL;
}
#endif
i2c_del_driver(&ts_driver);
#if USE_THREADED_IRQ
#else
if (touch_wq)
destroy_workqueue(touch_wq);
#endif
}
static ssize_t firmware_In_Binary(struct device *dev, struct device_attribute *attr, char *buf)
{
int phone_ver = 0x01;
sprintf(buf, "%x\n", phone_ver);
return sprintf(buf, "%s", buf );
}
static ssize_t firmware_In_TSP(struct device *dev, struct device_attribute *attr, char *buf)
{
uint8_t i2c_addr = 0x1B;
uint8_t buf_tmp[3] = {0};
printk("[TSP] %s\n",__func__);
tsp_i2c_read( i2c_addr, buf_tmp, sizeof(buf_tmp));
touch_vendor_id = buf_tmp[0] & 0xF0;
touch_hw_ver = buf_tmp[1];
touch_sw_ver = buf_tmp[2];
printk("[TSP] %s:%d, ver tsp=%x, HW=%x, SW=%x\n", __func__,__LINE__, touch_vendor_id, touch_hw_ver, touch_sw_ver);
HW_ver = touch_hw_ver;
// sprintf(buf, "%x\n", 0x1000000 + (touch_hw_ver*0x10000) + (touch_sw_ver*0x100) + phone_ver);
sprintf(buf, "%x\n", touch_sw_ver);
return sprintf(buf, "%s", buf );
}
#define TMA140_RET_SUCCESS 0x00
int sv_tch_firmware_update = 0;
static ssize_t firm_update(struct device *dev, struct device_attribute *attr, char *buf)
{
uint8_t update_num;
printk("[TSP] %s!\n", __func__);
sprintf(IsfwUpdate,"%s\n",FW_DOWNLOADING);
printk("[TSP] disable_irq : %d\n", __LINE__ );
disable_irq(tsp_irq);
local_irq_disable();
for(update_num = 1; update_num <= 5 ; update_num++)
{
sv_tch_firmware_update = cypress_update(HW_ver);
if(sv_tch_firmware_update == TMA140_RET_SUCCESS)
{
firmware_ret_val = 1; //SUCCESS
sprintf(IsfwUpdate,"%s\n",FW_DOWNLOAD_COMPLETE);
printk( "[TSP] %s, %d : firmware update SUCCESS !!\n", __func__, __LINE__);
break;
}
else
{
printk( "[TSP] %s, %d : firmware update RETRY !!\n", __func__, __LINE__);
if(update_num == 5)
{
firmware_ret_val = -1; //FAIL
sprintf(IsfwUpdate,"%s\n",FW_DOWNLOAD_FAIL);
printk( "[TSP] %s, %d : firmware update FAIL !!\n", __func__, __LINE__);
}
}
}
printk("[TSP] enable_irq : %d\n", __LINE__ );
local_irq_enable();
enable_irq(tsp_irq);
return sprintf(buf, "%d", firmware_ret_val );
}
static ssize_t firmware_update_status(struct device *dev, struct device_attribute *attr, char *buf)
{
printk("[TSP] %s\n",__func__);
return sprintf(buf, "%s\n", IsfwUpdate);
}
static ssize_t raw_show_tma140(struct device *dev, struct device_attribute *attr, char *buf)
{
int tma140_col_num = 8; //0 ~ 7
int tma140_row_num = 10;//0 ~ 9
int written_bytes = 0 ; /* & error check */
uint8_t buf1[1]={0,};
uint8_t buf2[80]={0,};
uint16_t ref1[80]={0,};
uint16_t ref2[80]={0,};
int i;
int ret;
uint8_t i2c_addr;
printk("[TSP] %s entered. line : %d, \n", __func__,__LINE__);
if(!tsp_testmode)
return 0;
/////* Raw Value */////
/////* Enter Raw Data Mode */////
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0x40;//value
ret = i2c_master_send(ts_global->client, buf1, 2);
if (ret >= 0)
break; // i2c success
}
msleep(10);
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0xC0;//value
ret = i2c_master_send(ts_global->client, buf1, 2);
if (ret >= 0)
break; // i2c success
}
msleep(50);
/////* Read Raw Data */////
i2c_addr = 0x07;
tsp_i2c_read( i2c_addr, buf2, sizeof(buf2));
printk("[TSP] Raw Value : ");
for(i = 0 ; i < (tma140_col_num * tma140_row_num) ; i++)
{
ref1[i] = buf2[i];
printk(" [%d]%3d", i, buf2[i]);
}
printk("\n");
/////* Difference Value */////
/////* Enter Difference Data Mode */////
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0x50;//value
ret = i2c_master_send(ts_global->client, buf1, 2);
if (ret >= 0)
break; // i2c success
}
msleep(10);
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0xD0;//value
ret = i2c_master_send(ts_global->client, buf1, 2);
if (ret >= 0)
break; // i2c success
}
msleep(50);
/////* Read Difference Data */////
i2c_addr = 0x07;
tsp_i2c_read( i2c_addr, buf2, sizeof(buf2));
printk("[TSP] Diff Value : ");
for(i = 0 ; i < (tma140_col_num * tma140_row_num) ; i++)
{
ref2[i] = buf2[i];
printk(" %d", ref2[i]);
}
printk("\n");
/////* Send Value */////
for (i = 0; i < (tma140_col_num * tma140_row_num) ; i++)
{
written_bytes += sprintf(buf+written_bytes, "%d %d\n", ref1[i], ref2[i]);
}
if (written_bytes > 0)
return written_bytes ;
return sprintf(buf, "-1") ;
}
static ssize_t raw_enable_tma140(struct device *dev, struct device_attribute *attr, char *buf)
{
// uint8_t buf1[2] = {0,};
/////* Enter Inspection Mode */////
/* for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0x40;//value
ret = i2c_master_send(ts_global->client, buf1, 2); //enter Inspection Mode
if (ret >= 0)
break; // i2c success
}*/
tsp_testmode = 1;
printk("[TSP] %s start. line : %d, \n", __func__,__LINE__);
mdelay(100);
return 1;
}
static ssize_t raw_disable_tma140(struct device *dev, struct device_attribute *attr, char *buf)
{
int i, ret;
uint8_t buf1[2] = {0,};
/////* Exit Inspection Mode */////
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0x00;//value
ret = i2c_master_send(ts_global->client, buf1, 2); //exit Inspection Mode
if (ret >= 0)
break; // i2c success
}
tsp_testmode = 0;
printk("[TSP] %s stop. line : %d, \n", __func__,__LINE__);
return 1;
}
static ssize_t read_rawdata_tma140(struct device *dev, struct device_attribute *attr, char *buf)//AT+TSPPTEST=1,1,1
{
int tma140_col_num = 8; //0 ~ 7
int tma140_row_num = 10;//0 ~ 9
int written_bytes = 0 ; /* & error check */
uint8_t buf1[1]={0,};
uint8_t buf2[80]={0,};
uint16_t ref1[80]={0,};
int i;
int ret;
uint8_t i2c_addr;
printk("[TSP] %s entered. line : %d, \n", __func__,__LINE__);
tsp_testmode = 1;
/////* Raw Value */////
/////* Enter Raw Data Mode */////
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0x40;//value
ret = i2c_master_send(ts_global->client, buf1, 2);
if (ret >= 0)
break; // i2c success
}
msleep(10);
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0xC0;//value
ret = i2c_master_send(ts_global->client, buf1, 2);
if (ret >= 0)
break; // i2c success
}
msleep(50);
/////* Read Raw Data */////
i2c_addr = 0x07;
tsp_i2c_read( i2c_addr, buf2, sizeof(buf2));
// printk("[TSP] Raw Value : ");
// for(i = 0 ; i < (tma140_col_num * tma140_row_num) ; i++)
// {
// ref1[i] = buf2[i];
// printk(" [%d]%3d", i, buf2[i]);
// }
// printk("\n");
/////* Exit Inspection Mode */////
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0x00;//value
ret = i2c_master_send(ts_global->client, buf1, 2); //exit Inspection Mode
if (ret >= 0)
break; // i2c success
}
/////* Send Value */////
for (i = 0; i < (tma140_col_num * tma140_row_num) ; i++)
{
written_bytes += sprintf(buf+written_bytes, ",%3d", ref1[i]);
}
// printk("[TSP] %s\n", buf);
mdelay(100);
tsp_testmode = 0;
if (written_bytes > 0)
return written_bytes ;
return sprintf(buf, "-1") ;
}
static ssize_t read_difference_tma140(struct device *dev, struct device_attribute *attr, char *buf)//AT+TSPPTEST=1,2,1
{
int tma140_col_num = 8; //0 ~ 7
int tma140_row_num = 10;//0 ~ 9
int written_bytes = 0 ; /* & error check */
uint8_t buf1[1]={0,};
uint8_t buf2[80]={0,};
uint16_t ref1[80]={0,};
int i;
int ret;
uint8_t i2c_addr;
printk("[TSP] %s entered. line : %d, \n", __func__,__LINE__);
tsp_testmode = 1;
/////* Difference Value */////
/////* Enter Difference Data Mode */////
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0x50;//value
ret = i2c_master_send(ts_global->client, buf1, 2);
if (ret >= 0)
break; // i2c success
}
msleep(10);
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0xD0;//value
ret = i2c_master_send(ts_global->client, buf1, 2);
if (ret >= 0)
break; // i2c success
}
msleep(50);
/////* Read Difference Data */////
i2c_addr = 0x07;
tsp_i2c_read( i2c_addr, buf2, sizeof(buf2));
// printk("[TSP] Difference Value : ");
// for(i = 0 ; i < (tma140_col_num * tma140_row_num) ; i++)
// {
// ref1[i] = buf2[i];
// printk(" [%d]%3d", i, buf2[i]);
// }
// printk("\n");
/////* Exit Inspection Mode */////
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x00;//address
buf1[1] = 0x00;//value
ret = i2c_master_send(ts_global->client, buf1, 2); //exit Inspection Mode
if (ret >= 0)
break; // i2c success
}
/////* Send Value */////
for (i = 0; i < (tma140_col_num * tma140_row_num) ; i++)
{
written_bytes += sprintf(buf+written_bytes, ",%3d", ref1[i]);
}
// printk("[TSP] %s\n", buf);
mdelay(100);
tsp_testmode = 0;
if (written_bytes > 0)
return written_bytes ;
return sprintf(buf, "-1") ;
}
static ssize_t rawdata_pass_fail_tma140(struct device *dev, struct device_attribute *attr, char *buf)
{
int tst200_col_num = 9; //0 ~ 8
int tst200_row_num = 7; //0 ~ 6
uint8_t buf1[2]={0,};
uint8_t buf2[32]={0,};
uint16_t ref1[16]={0,};
int i;
int ret;
uint16_t RAWDATA_MAX[16] = {16383,16383,16383,16383,16383,16383,16383,16383,16383,16383,16383,16383,16383,16383,16383,16383};
uint16_t RAWDATA_MIN[16] = {0,};
tsp_testmode = 1;
/////* Raw Value */////
for (i = 0; i < I2C_RETRY_CNT; i++)
{
buf1[0] = 0x0C; //address
ret = i2c_master_send(ts_global->client, buf1, 1);
if (ret >= 0)
{
ret = i2c_master_recv(ts_global->client, buf2, (tst200_col_num + tst200_row_num)*2);
if (ret >= 0)
break; // i2c success
}
}
for(i = 0 ; i < (tst200_col_num + tst200_row_num); i++)
{
ref1[i] = (buf2[i*2] <<8) + buf2[i*2+1];
printk(" %d", ref1[i]);
}
printk("\n");
/////* Check MAX/MIN Raw Value */////
for (i = 0; i < (tst200_col_num + tst200_row_num); i++)
{
if( RAWDATA_MAX[i] < ref1[i]) return sprintf(buf, "0"); // fail
if( RAWDATA_MIN[i] > ref1[i]) return sprintf(buf, "0"); // fail
}
tsp_testmode = 0;
return sprintf(buf, "1"); // success
}
module_init(tsp_driver_init);
module_exit(tsp_driver_exit);
MODULE_DESCRIPTION("Cypress Touchscreen Driver");
MODULE_LICENSE("GPL");