420 lines
10 KiB
C
420 lines
10 KiB
C
|
#include <linux/module.h>
|
|||
|
#include <linux/slab.h>
|
|||
|
#include <linux/input.h>
|
|||
|
#include <linux/interrupt.h>
|
|||
|
#include <linux/i2c.h>
|
|||
|
#include <linux/delay.h>
|
|||
|
#include <linux/jiffies.h>
|
|||
|
#include <linux/time.h>
|
|||
|
#include <linux/cdev.h>
|
|||
|
#include <asm/uaccess.h>
|
|||
|
#include <linux/pm_runtime.h>
|
|||
|
#include <linux/input/mt.h>
|
|||
|
#include <linux/errno.h>
|
|||
|
#include <linux/kernel.h>
|
|||
|
#include <linux/module.h>
|
|||
|
#include <linux/platform_device.h>
|
|||
|
#include <linux/async.h>
|
|||
|
#include <linux/hrtimer.h>
|
|||
|
#include <linux/init.h>
|
|||
|
#include <linux/input.h>
|
|||
|
#include <linux/ioport.h>
|
|||
|
#include <linux/workqueue.h>
|
|||
|
#include <linux/gpio.h>
|
|||
|
#include <linux/irq.h>
|
|||
|
#include <gsc3280/gpio.h>
|
|||
|
#include <gsc3280/sysctl.h>
|
|||
|
#include <asm/io.h>
|
|||
|
#include <linux/i2c.h>
|
|||
|
|
|||
|
#define USING_IRQ 1
|
|||
|
|
|||
|
#ifdef CONFIG_NS2009_DEBUG
|
|||
|
#define dbg(msg...) printk(KERN_INFO msg)
|
|||
|
#else
|
|||
|
#define dbg(msg...) do{}while(0)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
struct gpio gsc3280_gpio[1] = {
|
|||
|
{GSC3280_GPA(5), GPIOF_IN, "TP_IRQ"},
|
|||
|
};
|
|||
|
|
|||
|
#define gsc3280_set_gpio_reg_bit(reg) do{\
|
|||
|
unsigned int reg_val = 0; \
|
|||
|
reg_val = __raw_readl((volatile unsigned int *)(reg));\
|
|||
|
reg_val |= (0x1<<gsc3280_gpio[0].gpio);\
|
|||
|
__raw_writel(reg_val, (volatile unsigned int *)(reg));\
|
|||
|
}while(0)
|
|||
|
|
|||
|
#define gsc3280_clr_gpio_reg_bit(reg) do{\
|
|||
|
unsigned int reg_val = 0; \
|
|||
|
reg_val = __raw_readl((volatile unsigned int *)(reg));\
|
|||
|
reg_val &= ~(0x1<<gsc3280_gpio[0].gpio);\
|
|||
|
__raw_writel(reg_val, (volatile unsigned int *)(reg));\
|
|||
|
}while(0)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
enum finger_state {
|
|||
|
FLAG_UP = 0,
|
|||
|
FLAG_DOWN = 1,
|
|||
|
FLAG_INVALID = 2,
|
|||
|
};
|
|||
|
|
|||
|
struct ns2009_event {
|
|||
|
int touch_point;
|
|||
|
u16 x1[5];
|
|||
|
u16 y1[5];
|
|||
|
u16 id;
|
|||
|
enum finger_state state;
|
|||
|
unsigned int x;
|
|||
|
unsigned int y;
|
|||
|
unsigned int pressure;
|
|||
|
};
|
|||
|
|
|||
|
struct ns2009_data{
|
|||
|
struct input_dev *input_dev;
|
|||
|
struct ns2009_event *event;
|
|||
|
struct work_struct work;
|
|||
|
struct workqueue_struct *queue;
|
|||
|
struct timer_list touch_timer;
|
|||
|
struct timer_list charge_detect;
|
|||
|
int irq;
|
|||
|
int (*power)(struct ns2009_data * ts, int on);
|
|||
|
};
|
|||
|
|
|||
|
u32 x_old;
|
|||
|
u32 y_old;
|
|||
|
u32 flag;
|
|||
|
struct ns2009_data *ns2009_dev;
|
|||
|
struct i2c_client *i2cdev;
|
|||
|
static unsigned int int_handle = 0;
|
|||
|
|
|||
|
int ns2009_i2c_write_bytes(struct i2c_client *client, uint8_t *reg, uint16_t len)
|
|||
|
{
|
|||
|
return i2c_master_send(client, reg, len);
|
|||
|
}
|
|||
|
|
|||
|
int ns2009_i2c_read_bytes(struct i2c_client *client, uint8_t *data, uint16_t len)
|
|||
|
{
|
|||
|
return i2c_master_recv(client, data, len);
|
|||
|
}
|
|||
|
|
|||
|
static void gsc3280_report_event(struct ns2009_data *dev, u16 x, u16 y , u16 z)
|
|||
|
{
|
|||
|
input_report_abs(dev->input_dev,ABS_X,y);
|
|||
|
input_report_abs(dev->input_dev,ABS_Y,x);
|
|||
|
input_report_abs(dev->input_dev,ABS_PRESSURE,z);
|
|||
|
dbg("x = %d , y = %d , z = %d\n",x,y,z);
|
|||
|
if(z > 0)
|
|||
|
input_report_key(dev->input_dev,BTN_TOUCH,1);
|
|||
|
else
|
|||
|
input_report_key(dev->input_dev,BTN_TOUCH,0);
|
|||
|
input_sync(dev->input_dev);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static void gpio_int_enable(void)
|
|||
|
{
|
|||
|
gsc3280_set_gpio_reg_bit(GSC3280_REGADDR_GPIO_INTEN);
|
|||
|
gsc3280_set_gpio_reg_bit(GSC3280_REGADDR_GPIO_INTTYPE_LEVEL);
|
|||
|
gsc3280_clr_gpio_reg_bit(GSC3280_REGADDR_GPIO_INT_POLARITY);
|
|||
|
gsc3280_set_gpio_reg_bit(GSC3280_REGADDR_GPIO_DEBOUNCE);
|
|||
|
gsc3280_clr_gpio_reg_bit(GSC3280_REGADDR_GPIO_INTMASK);
|
|||
|
gsc3280_set_gpio_reg_bit(GSC3280_REGADDR_GPIO_PORTA_EOI);
|
|||
|
}
|
|||
|
|
|||
|
static void gpio_int_disable(void)
|
|||
|
{
|
|||
|
gsc3280_clr_gpio_reg_bit(GSC3280_REGADDR_GPIO_INTEN);
|
|||
|
gsc3280_set_gpio_reg_bit(GSC3280_REGADDR_GPIO_INTMASK);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
static irqreturn_t ns2009_interrupt_handle(int irq, void *dev_id)
|
|||
|
{
|
|||
|
dbg("ns2009 irq happen\n");
|
|||
|
gpio_int_disable();
|
|||
|
gsc3280_set_gpio_reg_bit(GSC3280_REGADDR_GPIO_PORTA_EOI);
|
|||
|
flush_workqueue(ns2009_dev->queue);
|
|||
|
schedule_work(&ns2009_dev->work);
|
|||
|
//<2F><><EFBFBD>ж<EFBFBD>
|
|||
|
|
|||
|
return IRQ_HANDLED;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static int report_func(struct ns2009_data *work)
|
|||
|
{
|
|||
|
int i = 0;
|
|||
|
struct ns2009_event *event = ns2009_dev->event;
|
|||
|
//int buf0[2] = {0};
|
|||
|
u16 buf1[2] = {0xC0}; //X 12ADC
|
|||
|
u16 buf2[2] = {0xD0}; //Y 12ADC
|
|||
|
u16 buf3[2] = {0xE0}; //Z1
|
|||
|
u16 buf_z1[2] = {0};
|
|||
|
u16 buf_x[2] = {0};
|
|||
|
u16 buf_y[2] = {0};
|
|||
|
u16 x = 0;
|
|||
|
u16 y = 0;
|
|||
|
u16 z = 0;
|
|||
|
u16 x_old = 0;
|
|||
|
u16 y_old = 0;
|
|||
|
u16 x_avrg = 0;
|
|||
|
u16 y_avrg = 0;
|
|||
|
unsigned int value;
|
|||
|
down:
|
|||
|
ns2009_i2c_write_bytes(i2cdev,buf3,1);
|
|||
|
ns2009_i2c_read_bytes(i2cdev,buf_z1,2);
|
|||
|
z =(buf_z1[0]<<4) | (buf_z1[1]>>4);
|
|||
|
|
|||
|
for(i=0;i<10;i++)
|
|||
|
{
|
|||
|
ns2009_i2c_write_bytes(i2cdev,buf1,1);
|
|||
|
ns2009_i2c_read_bytes(i2cdev,buf_x,2);
|
|||
|
x =(buf_x[0]<<4) | (buf_x[1]>>4);
|
|||
|
|
|||
|
ns2009_i2c_write_bytes(i2cdev,buf2,1);
|
|||
|
ns2009_i2c_read_bytes(i2cdev,buf_y,2);
|
|||
|
y = (buf_y[0]<<4) | (buf_y[1]>>4);
|
|||
|
|
|||
|
if(x < 144)
|
|||
|
x=144;
|
|||
|
if(x > 3956)
|
|||
|
x=3956;
|
|||
|
if(y < 32)
|
|||
|
y=32;
|
|||
|
if(y > 4080)
|
|||
|
y=4080;
|
|||
|
|
|||
|
x = ((3956-x)*480)/(3956-144); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>yֵ
|
|||
|
//y = ((4080-y)*800)/(4080-32);
|
|||
|
y = ((y-32)*800)/(4080-32); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>xֵ
|
|||
|
|
|||
|
x_avrg += x;
|
|||
|
y_avrg += y;
|
|||
|
}
|
|||
|
x = x_avrg/10;
|
|||
|
y = y_avrg/10;
|
|||
|
|
|||
|
x_avrg = 0;
|
|||
|
y_avrg = 0;
|
|||
|
|
|||
|
|
|||
|
value = *(volatile unsigned int *)0xbc110050;
|
|||
|
if(value&(1<<5))
|
|||
|
{
|
|||
|
goto up;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
gsc3280_report_event(ns2009_dev,x,y,z);
|
|||
|
x_old = x;
|
|||
|
y_old = y;
|
|||
|
goto down;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
up:
|
|||
|
gsc3280_report_event(ns2009_dev,x_old,y_old,0);
|
|||
|
|
|||
|
//dbg("-----------GPIO_EXT_PORTA = 0x%x-----------\n",*(volatile unsigned int *)0xbc110050);
|
|||
|
/*
|
|||
|
if(buf_z1[0]<1)
|
|||
|
{
|
|||
|
input_report_abs(ns2009_dev->input_dev,ABS_X,x_old);
|
|||
|
input_report_abs(ns2009_dev->input_dev,ABS_Y,y_old);
|
|||
|
input_report_key(ns2009_dev->input_dev,BTN_TOUCH,0);
|
|||
|
input_sync(ns2009_dev->input_dev);
|
|||
|
gpio_int_enable();
|
|||
|
return 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ns2009_i2c_write_bytes(i2cdev,buf1,1);
|
|||
|
ns2009_i2c_read_bytes(i2cdev,buf_x,2);
|
|||
|
// dbg("buf_x[0] = 0x%x,buf_x[1] = 0x%x\n",buf_x[0],buf_x[1]);
|
|||
|
buf_x[0] =(buf_x[0]<<4) | (buf_x[1]>>4);
|
|||
|
if(buf_x[0] == 0)
|
|||
|
{
|
|||
|
gpio_int_enable();
|
|||
|
return 0;
|
|||
|
}
|
|||
|
ns2009_i2c_write_bytes(i2cdev,buf2,1);
|
|||
|
ns2009_i2c_read_bytes(i2cdev,buf_y,2);
|
|||
|
//dbg("buf_y[0] = 0x%x,buf_y[1] = 0x%x\n",buf_y[0],buf_y[1]);
|
|||
|
buf_y[0] = (buf_y[0]<<4) | (buf_y[1]>>4);
|
|||
|
dbg("buf_x = %d, buf_y= %d\n",buf_x[0],buf_y[0]);
|
|||
|
}
|
|||
|
*/
|
|||
|
gpio_int_enable();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static int ns2009_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
|
{
|
|||
|
int err = 0;
|
|||
|
dbg("ns2009 probe .........\n");
|
|||
|
/*<2A><><EFBFBD>鵱ǰ<E9B5B1><C7B0><EFBFBD><EFBFBD>֧<EFBFBD>ֵĴ<D6B5><C4B4>䷽ʽ*/
|
|||
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|||
|
err = -ENODEV;
|
|||
|
return -1;
|
|||
|
}
|
|||
|
i2cdev = client;
|
|||
|
i2cdev->addr = client->addr;
|
|||
|
ns2009_dev = kzalloc(sizeof(*ns2009_dev),GFP_KERNEL);
|
|||
|
dbg(".......GPIO_EXT_PORTA = 0x%x\n",*(volatile unsigned int *)0xbc110050);
|
|||
|
if(!ns2009_dev)
|
|||
|
{
|
|||
|
err = -ENOMEM;
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
i2c_set_clientdata(i2cdev,ns2009_dev);
|
|||
|
|
|||
|
ns2009_dev->queue = create_singlethread_workqueue("TS");
|
|||
|
if(!ns2009_dev->queue)
|
|||
|
{
|
|||
|
printk(KERN_INFO"creat_single_thread failed\n");
|
|||
|
err = -ESRCH;
|
|||
|
goto exit_create_singlethread;
|
|||
|
}
|
|||
|
|
|||
|
INIT_WORK(&ns2009_dev->work,(void *)report_func);
|
|||
|
|
|||
|
ns2009_dev->input_dev = input_allocate_device();
|
|||
|
if(!ns2009_dev->input_dev)
|
|||
|
{
|
|||
|
err = -ENOMEM;
|
|||
|
printk(KERN_INFO"ns2009 alloc input dev fail\n");
|
|||
|
goto alloc_input_dev;
|
|||
|
}
|
|||
|
|
|||
|
ns2009_dev->input_dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS)| BIT(ABS_PRESSURE);
|
|||
|
set_bit(BTN_TOUCH, ns2009_dev->input_dev->keybit);
|
|||
|
input_set_abs_params(ns2009_dev->input_dev, ABS_X, 0, 800, 0, 0);
|
|||
|
input_set_abs_params(ns2009_dev->input_dev, ABS_Y, 0, 480, 0, 0);
|
|||
|
input_set_abs_params(ns2009_dev->input_dev, ABS_PRESSURE, 0, 255, 0, 0);
|
|||
|
input_set_abs_params(ns2009_dev->input_dev, ABS_MT_TOUCH_MAJOR, 0, 50, 0, 0);
|
|||
|
|
|||
|
ns2009_dev->input_dev->name = "ns2009";
|
|||
|
ns2009_dev->input_dev->phys = "input/ns2009";
|
|||
|
ns2009_dev->input_dev->id.bustype = BUS_HOST ;
|
|||
|
ns2009_dev->input_dev->id.vendor = 0x0001;
|
|||
|
ns2009_dev->input_dev->id.product = 0x0001;
|
|||
|
ns2009_dev->input_dev->id.version = 0x0100;
|
|||
|
|
|||
|
err = input_register_device(ns2009_dev->input_dev);
|
|||
|
if(err){
|
|||
|
printk(KERN_INFO"......failed to register input device ns2009\n");
|
|||
|
goto input_register_device_failed;
|
|||
|
}
|
|||
|
dbg("-------register input_device ok!----------\n");
|
|||
|
#ifdef USING_IRQ
|
|||
|
/*get gpio irq number */
|
|||
|
dbg("-------ns2009 use irq--------------\n");
|
|||
|
gpio_int_enable();
|
|||
|
i2cdev->irq = gpio_to_irq(5);
|
|||
|
dbg("-------TP_IRQ = %d\n",i2cdev->irq);
|
|||
|
|
|||
|
/*request virq,set virq type to high level trigger*/
|
|||
|
int_handle = request_irq(i2cdev->irq, ns2009_interrupt_handle,IRQF_SHARED,"gsc3280-ns2009",ns2009_dev);
|
|||
|
if(IS_ERR_VALUE(int_handle)){
|
|||
|
printk(KERN_INFO"request irq faild int ns2009\n");
|
|||
|
return -EINVAL;
|
|||
|
}
|
|||
|
pr_info("int_handle=%d, apply for irq succeed!\n" ,int_handle);
|
|||
|
#else
|
|||
|
/*<2A><>ʱ<EFBFBD><CAB1> */
|
|||
|
//setup_timer(&mytimer, timer_work, (unsigned long)"Timer_Out!");
|
|||
|
//mytimer.expires = jiffies + HZ/10;
|
|||
|
//add_timer(&mytimer);
|
|||
|
#endif
|
|||
|
return 0;
|
|||
|
|
|||
|
input_register_device_failed:
|
|||
|
input_free_device(ns2009_dev->input_dev);
|
|||
|
alloc_input_dev:
|
|||
|
exit_create_singlethread:
|
|||
|
// i2c_set_clientdata(ns2009_dev, NULL);
|
|||
|
kfree(ns2009_dev);
|
|||
|
|
|||
|
return err;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
static const struct i2c_device_id ns2009_id[] = {
|
|||
|
{ "ns2009", 0 },
|
|||
|
{}
|
|||
|
};
|
|||
|
|
|||
|
static int __devexit ns2009_ts_remove(struct i2c_client *client){
|
|||
|
/*
|
|||
|
pr_info("====ns2009_ts_remove====\n");
|
|||
|
//rtp_disable_irq(this_client->irq);
|
|||
|
//free_irq(this_client->irq, &RTP_NAME);
|
|||
|
del_timer(&mytimer);
|
|||
|
cancel_work_sync(&ts_work->work);
|
|||
|
destroy_workqueue(ts_work->queue);
|
|||
|
i2c_set_clientdata(this_client, NULL);
|
|||
|
input_unregister_device(ts_work->input_dev);
|
|||
|
kfree(ts_work->input_dev);
|
|||
|
*/
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
static struct i2c_driver ns2009_driver = {
|
|||
|
.probe = ns2009_probe,
|
|||
|
.remove = __devexit_p(ns2009_ts_remove),
|
|||
|
.id_table = ns2009_id,
|
|||
|
.driver = {
|
|||
|
.name = "ns2009",
|
|||
|
.owner = THIS_MODULE,
|
|||
|
},
|
|||
|
.address_list = NULL,
|
|||
|
.detect = NULL,
|
|||
|
.suspend = NULL,
|
|||
|
.resume = NULL,
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
static int __init ns2009_init(void)
|
|||
|
{
|
|||
|
int ret = -1;
|
|||
|
ret =i2c_add_driver(&ns2009_driver);
|
|||
|
if(ret < 0)
|
|||
|
printk(KERN_INFO"add ns2009 driver fail......\n");
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
static int __exit ns2009_exit(void)
|
|||
|
{
|
|||
|
printk(KERN_INFO"ns2009 driver exit...\n");
|
|||
|
i2c_del_driver(&ns2009_driver);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
module_init(ns2009_init);
|
|||
|
module_init(ns2009_exit);
|
|||
|
|
|||
|
MODULE_AUTHOR("linshangsheng@163.com");
|
|||
|
MODULE_DESCRIPTION("TOUCH SCREEN DRIVER");
|
|||
|
MODULE_LICENSE("GPL");
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|