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");
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|