#include <linux/irq.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
+#include <linux/proc_fs.h>
#include "ili2102_ts.h"
+static int ts_dbg_enable = 0;
-#if 0
- #define DBG(msg...) printk(msg);
-#else
- #define DBG(msg...)
-#endif
-
+#define DBG(msg...) \
+ ({if(ts_dbg_enable == 1) printk(msg);})
+
#define TOUCH_NUMBER 2
-static int touch_state[TOUCH_NUMBER] = {TOUCH_UP,TOUCH_UP};
-static unsigned int g_x[TOUCH_NUMBER] = {0},g_y[TOUCH_NUMBER] = {0};
+static volatile int touch_state[TOUCH_NUMBER] = {TOUCH_UP,TOUCH_UP};
+static volatile unsigned int g_x[TOUCH_NUMBER] = {0},g_y[TOUCH_NUMBER] = {0};
struct ili2102_ts_data {
u16 model; /* 801. */
#define ILITEK_IOCTL_STOP_READ_DATA _IOWR(ILITEK_IOCTL_BASE, 12, int)
#define ILITEK_IOCTL_START_READ_DATA _IOWR(ILITEK_IOCTL_BASE, 13, int)
+
+static ssize_t ili2102_proc_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char c;
+ int rc;
+
+ rc = get_user(c, buffer);
+ if (rc)
+ return rc;
+
+ if (c == '1')
+ ts_dbg_enable = 1;
+ else if (c == '0')
+ ts_dbg_enable = 0;
+
+ return count;
+}
+
+static const struct file_operations ili2102_proc_fops = {
+ .owner = THIS_MODULE,
+ .write = ili2102_proc_write,
+};
+
static int ilitek_file_open(struct inode *inode, struct file *filp)
{
return 0;
msg[0].scl_rate = 400*1000;
msg[0].udelay = 80;
- printk("%s:count=0x%x\n",__FUNCTION__,count);
+ DBG("%s:count=0x%x\n",__FUNCTION__,count);
// before sending data to touch device, we need to check whether the device is working or not
if(g_ts->valid_i2c_register == 0){
return -1;
}
- printk("%s:cmd=0x%x\n",__FUNCTION__,cmd);
+ DBG("%s:cmd=0x%x\n",__FUNCTION__,cmd);
return 0;
}
static int verify_coord(struct ili2102_ts_data *ts,unsigned int *x,unsigned int *y)
{
- DBG("%s:(%d/%d)\n",__FUNCTION__,*x, *y);
+ //DBG("%s:(%d/%d)\n",__FUNCTION__,*x, *y);
+ #ifndef CONFIG_MACH_RK29_TD8801_V2
if((*x< ts->x_min) || (*x > ts->x_max))
return -1;
if((*y< ts->y_min) || (*y > ts->y_max))
return -1;
+ #endif
+
+ /*android do not support min and max value*/
+ if(*x == ts->x_min)
+ *x = ts->x_min + 1;
+ if(*y == ts->y_min)
+ *y = ts->y_min + 1;
+ if(*x == ts->x_max)
+ *x = ts->x_max - 1;
+ if(*y == ts->y_max)
+ *y = ts->y_max - 1;
+
return 0;
}
static int ili2102_init_panel(struct ili2102_ts_data *ts)
{
- gpio_set_value(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_HIGH:GPIO_LOW);
gpio_set_value(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_LOW:GPIO_HIGH);
mdelay(1);
gpio_set_value(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_HIGH:GPIO_LOW);
- mdelay(100);//need?
return 0;
}
static void ili2102_ts_work_func(struct work_struct *work)
{
- int i,ret;
+ int i,ret,num=1;
int syn_flag = 0;
unsigned int x, y;
struct i2c_msg msg[2];
msg[0].flags = ts->client->flags;
msg[0].len = 1;
msg[0].buf = &start_reg;
- msg[0].scl_rate = 400*1000;
- msg[0].udelay = 0;
-
- ret = i2c_transfer(ts->client->adapter, msg, 1);
- if (ret < 0)
- {
- printk("%s:i2c_transfer fail, ret=%d\n",__FUNCTION__,ret);
- goto out;
- }
-
- udelay(200); //tp need delay
+ msg[0].scl_rate = 200*1000;
+ msg[0].udelay = 200;
- msg[0].addr = ts->client->addr;
- msg[0].flags = ts->client->flags | I2C_M_RD;
- msg[0].len = 9;
- msg[0].buf = buf;
- msg[0].scl_rate = 400*1000;
- msg[0].udelay = 0;
+ msg[1].addr = ts->client->addr;
+ msg[1].flags = ts->client->flags | I2C_M_RD;
+ msg[1].len = 9;
+ msg[1].buf = buf;
+ msg[1].scl_rate = 200*1000;
+ msg[1].udelay = 0;
- ret = i2c_transfer(ts->client->adapter, msg, 1);
+ ret = i2c_transfer(ts->client->adapter, msg, 2);
if (ret < 0)
{
printk("%s:i2c_transfer fail, ret=%d\n",__FUNCTION__,ret);
goto out;
}
-
- for(i=0; i<TOUCH_NUMBER; i++)
+ if(buf[0]&0x02 == 0x02)
+ num = 2;
+ else
+ num = 1;
+
+ for(i=0; i<num; i++)
{
if(!((buf[0]>>i)&0x01))
input_mt_sync(ts->input_dev);
syn_flag = 1;
touch_state[i] = TOUCH_UP;
- DBG("touch_up \n");
+ DBG("i=%d,touch_up \n",i);
}
}
x = g_x[i];
y = g_y[i];
}
-
+ #ifdef CONFIG_MACH_RK29_TD8801_V2
+ if( y >=80 ) y-=80;
+ if( x >= 50 ) x-=50;
+ #endif
g_x[i] = x;
g_y[i] = y;
input_event(ts->input_dev, EV_ABS, ABS_MT_TRACKING_ID, i);
- input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); //Finger Size
- input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
- input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 5); //Touch Size
- input_mt_sync(ts->input_dev);
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 1); //Finger Size
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 5); //Touch Size
+ input_mt_sync(ts->input_dev);
syn_flag = 1;
touch_state[i] = TOUCH_DOWN;
ts->pendown = 1;
- DBG("touch_down X = %d, Y = %d\n", x, y);
+ DBG("touch_down i=%d X = %d, Y = %d\n",i, x, y);
}
}
if(syn_flag)
input_sync(ts->input_dev);
out:
+#if 0
if(ts->pendown)
{
- schedule_delayed_work(&ts->work, msecs_to_jiffies(10));
+ schedule_delayed_work(&ts->work, msecs_to_jiffies(12));
ts->pendown = 0;
}
else
if (ts->use_irq)
enable_irq(ts->client->irq);
}
-
- DBG("pin=%d,level=%d,irq=%d\n",irq_to_gpio(ts->client->irq),gpio_get_value(irq_to_gpio(ts->client->irq)),ts->client->irq);
+#else
+ enable_irq(ts->client->irq);//intterupt pin will be high after i2c read so could enable irq at once
+#endif
+ DBG("pin=%d,level=%d,irq=%d\n\n",irq_to_gpio(ts->client->irq),gpio_get_value(irq_to_gpio(ts->client->irq)),ts->client->irq);
}
DBG("ili2102_ts_irq_handler=%d,%d\n",ts->client->irq,ts->use_irq);
disable_irq_nosync(ts->client->irq); //disable_irq(ts->client->irq);
- schedule_delayed_work(&ts->work, 0);
+ queue_delayed_work(ts->ts_wq, &ts->work, 0);
return IRQ_HANDLED;
}
ts->gpio_reset);
return err;
}
- gpio_direction_output(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_HIGH:GPIO_LOW);
- mdelay(100);
+
+ //gpio_direction_output(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_HIGH:GPIO_LOW);
err = gpio_direction_output(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_LOW:GPIO_HIGH);
if (err) {
return err;
}
- mdelay(1);
+ mdelay(5);
gpio_set_value(ts->gpio_reset, ts->gpio_reset_active_low? GPIO_HIGH:GPIO_LOW);
- mdelay(100);
+ mdelay(200);
return 0;
}
printk("ili2102 TS setup_pendown fail\n");
goto err_input_register_device_failed;
}
- ret = request_irq(client->irq, ili2102_ts_irq_handler, IRQF_DISABLED | IRQF_TRIGGER_LOW, client->name, ts);
- if (ret == 0) {
- DBG("ili2102 TS register ISR (irq=%d)\n", client->irq);
- ts->use_irq = 1;
- }
- else
+
+ ret = request_irq(client->irq, ili2102_ts_irq_handler, IRQF_DISABLED | IRQF_TRIGGER_LOW, client->name, ts);
+ if (ret == 0) {
+ DBG("ili2102 TS register ISR (irq=%d)\n", client->irq);
+ ts->use_irq = 1;
+ }
+ else
dev_err(&client->dev, "request_irq failed\n");
}
ts->early_suspend.resume = ili2102_ts_late_resume;
register_early_suspend(&ts->early_suspend);
#endif
+
+ struct proc_dir_entry *ili2102_proc_entry;
+ ili2102_proc_entry = proc_create("driver/ili2102", 0777, NULL, &ili2102_proc_fops);
printk(KERN_INFO "ili2102_ts_probe: Start touchscreen %s in %s mode\n", ts->input_dev->name, ts->use_irq ? "interrupt" : "polling");
{
int ret;
struct ili2102_ts_data *ts = i2c_get_clientdata(client);
- uint8_t buf[2] = {0x30,0x30};
+ uint8_t buf[1] = {0x30};
struct i2c_msg msg[1];
-
- if (ts->use_irq)
- disable_irq(client->irq);
- else
- hrtimer_cancel(&ts->timer);
-
- ret = cancel_delayed_work_sync(&ts->work);
- if (ret && ts->use_irq) /* if work was pending disable-count is now 2 */
- enable_irq(client->irq);
//to do suspend
msg[0].addr =client->addr;
msg[0].flags = 0;
- msg[0].len = 2;
+ msg[0].len = 1;
msg[0].buf = buf;
ret = i2c_transfer(client->adapter, msg, 1);
if (ret < 0) {
printk("%s:err\n",__FUNCTION__);
}
+
+ ret = cancel_delayed_work_sync(&ts->work);
+ if (ret && ts->use_irq) /* if work was pending disable-count is now 2 */
+ enable_irq(client->irq);
+ if (ts->use_irq)
+ {
+ free_irq(client->irq, ts);
+ //change irq type to IRQF_TRIGGER_FALLING to avoid system death
+ ret = request_irq(client->irq, ili2102_ts_irq_handler, IRQF_DISABLED | IRQF_TRIGGER_FALLING, client->name, ts);
+ if (ret == 0) {
+ disable_irq_nosync(client->irq);
+ ts->use_irq = 1;
+ }
+ else
+ printk("%s:request irq=%d failed,ret=%d\n",__FUNCTION__, ts->client->irq, ret);
+ }
+ else
+ hrtimer_cancel(&ts->timer);
+
DBG("%s\n",__FUNCTION__);
return 0;
}
-static int ili2102_ts_resume(struct i2c_client *client)
+
+static void ili2102_ts_resume_work_func(struct work_struct *work)
{
- struct ili2102_ts_data *ts = i2c_get_clientdata(client);
+ struct ili2102_ts_data *ts = container_of(work, struct ili2102_ts_data, work);
+ int ret;
+
+ //report touch up to android
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0); //Finger Size
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0); //Touch Size
+ input_mt_sync(ts->input_dev);
+ input_sync(ts->input_dev);
- //to do resume
- ili2102_init_panel(ts);
+ PREPARE_DELAYED_WORK(&ts->work, ili2102_ts_work_func);
+ mdelay(100); //wait for 100ms before i2c operation
- if (ts->use_irq) {
- printk("enabling IRQ %d\n", client->irq);
- enable_irq(client->irq);
+ free_irq(ts->client->irq, ts);
+ ret = request_irq(ts->client->irq, ili2102_ts_irq_handler, IRQF_DISABLED | IRQF_TRIGGER_LOW, ts->client->name, ts);
+ if (ret == 0) {
+ ts->use_irq = 1;
+ //enable_irq(ts->client->irq);
}
- //else
- //hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ else
+ printk("%s:request irq=%d failed,ret=%d\n",__FUNCTION__,ts->client->irq,ret);
+
+ DBG("%s,irq=%d\n",__FUNCTION__,ts->client->irq);
+}
+
+
+static int ili2102_ts_resume(struct i2c_client *client)
+{
+ struct ili2102_ts_data *ts = i2c_get_clientdata(client);
+
+ ili2102_init_panel(ts);
+
+ if (ts->use_irq) {
+ if(!delayed_work_pending(&ts->work)){
+ PREPARE_DELAYED_WORK(&ts->work, ili2102_ts_resume_work_func);
+ queue_delayed_work(ts->ts_wq, &ts->work, 0);
+ }
+ }
+ else {
+ hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ }
DBG("%s\n",__FUNCTION__);
return 0;
}
+
#ifdef CONFIG_HAS_EARLYSUSPEND
static void ili2102_ts_early_suspend(struct early_suspend *h)
{