ckfwq/linux-3.0.4/drivers/input/touchscreen/gsc3280_ns2009.c

420 lines
10 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 = ((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_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");