blob: 8a4c718dd9f6382e5556ea45a7b635c289e3ffbc [file]
/*
* drivers/input/touchscreen/ar7643_ts.c
* Copyright (C) 2011 ANYKA
* Author: Zhou Wenyong
*
* AR7643 TouchScreen Driver for ak98
*/
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <mach/gpio.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
//#define AR7643_DEBUG
#define DEJITTER
#define AR7642TSVERSION 0x01
/* definitons of pin */
#define PIN_DOUT AK98_GPIO_0
#define PIN_CLK AK98_GPIO_1
#define PIN_CS AK98_GPIO_2
#define PIN_DIN AK98_GPIO_3
#define PIN_INT AK98_GPIO_19
#define AR7643_IRQ IRQ_GPIO_19
#define POLL_DELAY 5
#define PEROID_DELAY 1
#define MAX_12BIT (0xFFF)
#define SAMPLE_CNT 4
/* definitions of control byte */
#define START_BIT (1<<7)
#define ADDR_X (1<<4)
#define ADDR_Y (5<<4)
#define GET_X 0xD0
#define GET_Y 0x90
#define CS_KEEP_LOW 1
enum
{
DOUT_BIT = 0,
CLK_BIT = 1,
CS_BIT = 2,
DIN_BIT = 3,
INT_BIT = 18
};
#define SET_PIN_HIGH(pin) ak98_gpio_setpin(pin, AK98_GPIO_HIGH)
#define SET_PIN_LOW(pin) ak98_gpio_setpin(pin, AK98_GPIO_LOW)
#define READ_PIN(pin) ak98_gpio_getpin(pin)
#define IS_PEN_DOWN(pin) (ak98_gpio_getpin(pin) ? 0:1)
static struct workqueue_struct *ar7643_wq;
#undef PDEBUG /* undef it, just in case */
#ifdef AR7643_DEBUG
# ifdef __KERNEL__
/* This one if debugging is on, and kernel space */
# define PDEBUG(fmt, args...) printk( KERN_INFO fmt,## args)
# else
/* This one for user space */
# define PDEBUG(fmt, args...) fprintf(stderr, "%s %d: "fmt,__FILE__, __LINE__, ## args)
# endif
#else
# define PDEBUG(fmt, args...) /* not debugging: nothing */
#endif
/*
* Definitions & global arrays.
*/
static char *ar7643_name = "AR7643 SPI TouchScreen for AK98";
//static spinlock_t ar7643_lock;
static int ar7643_send_byte(u8 command);
struct AR7643_SAMPLE {
s32 x;
s32 y;
};
/*
* Per-touchscreen data.
*/
struct ar7643 {
struct input_dev *dev;
bool pendown;
bool first;
long xp;
long yp;
int count;
int shift;
char phys[32];
u32 speed_hz;
struct spi_device *spi;
struct delayed_work work;
};
static void ar7643_work(struct work_struct *work);//unsigned long data);
static void get_xy(struct AR7643_SAMPLE *samp);
static struct ar7643 ts;
#ifdef DEJITTER
#define NR_SAMPHISTLEN 4
static const unsigned char weight [NR_SAMPHISTLEN - 1][NR_SAMPHISTLEN + 1] =
{
/* The last element is pow2(SUM(0..3)) */
{ 5, 3, 0, 0, 3 }, /* When we have 2 samples ... */
{ 8, 5, 3, 0, 4 }, /* When we have 3 samples ... */
{ 6, 4, 3, 3, 4 }, /* When we have 4 samples ... */
};
struct dejitter_info {
int delta;
int x;
int y;
int nr;
int head;
struct AR7643_SAMPLE samp[NR_SAMPHISTLEN];
};
#define FAST_THRESHOLD 100
static struct dejitter_info djt;
static void average(struct dejitter_info *djt, struct AR7643_SAMPLE *samp);
static int dejitter(struct input_dev *dev, struct AR7643_SAMPLE *_samp, bool penup);
#endif
static void report_value(struct input_dev *dev, struct AR7643_SAMPLE *samp)
{
PDEBUG("==%4d %4d \n", samp->x, samp->y);
input_report_abs(dev, ABS_X, samp->x);
input_report_abs(dev, ABS_Y, samp->y);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
}
static void pin_init(void)
{
ak98_setpin_as_gpio(PIN_INT);
ak98_gpio_pullup(PIN_INT, AK98_PULLUP_ENABLE);
ak98_gpio_pulldown(PIN_INT, AK98_PULLDOWN_DISABLE);
ak98_gpio_cfgpin(PIN_INT, AK98_GPIO_DIR_INPUT);
ak98_gpio_intpol(PIN_INT, AK98_GPIO_INT_LOWLEVEL);
}
static int ar7643_read_12bit(u8 comand, int *v)
{
struct spi_message m;
struct spi_transfer xfer;
int status;
int a=0;
u8 cmd[3] = {0};
u8 buff[3] = {0};
cmd[0] = comand;
spi_message_init(&m);
xfer.tx_buf = cmd;
xfer.rx_buf = buff;
xfer.len = sizeof(cmd);
xfer.bits_per_word = 8;
xfer.speed_hz = ts.speed_hz;
xfer.cs_change = CS_KEEP_LOW ? 0:1; // 1: the #CS signal is LOW until all the data transmission has been finished
// 0: the #CS signal is HIGH after a transmission of 8 bits data
spi_message_add_tail(&xfer, &m);
status = spi_sync(ts.spi, &m);
a = buff[1]&0x7f;
a = ((a<<5) | ((buff[2]>>3)&0x1f));
*v = a;
return status;
}
static int get_pos(int *x, int *y)
{
//int count;
ar7643_read_12bit(GET_X, x);
ar7643_read_12bit(GET_Y, y);
//printk("x: %d y: %d\n", *x, *y);
return 0;
}
static void get_xy(struct AR7643_SAMPLE *samp)
{
if (ts.first == true);
{
udelay(100);
get_pos(&(samp->x), &(samp->y));
ts.first = false;
}
get_pos(&(samp->x), &(samp->y));
}
static void ar7643_sent_up_event(void )
{
struct input_dev *input = ts.dev;
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_sync(input);
}
/*
* touch screen interrupt handler.
*/
static irqreturn_t ar7643_irqhandler(int irq, void *handle)
{
PDEBUG("%s(): Entering...\n", __FUNCTION__);
if ( likely( IS_PEN_DOWN(PIN_INT) ) )
{
PDEBUG("pen down\n");
disable_irq_nosync(AR7643_IRQ);
ts.first = true;
queue_delayed_work(ar7643_wq, &(ts.work),
msecs_to_jiffies(PEROID_DELAY));
//mod_timer(&(touch_timer), jiffies + msecs_to_jiffies(PEROID_DELAY));
}
return IRQ_HANDLED;
}
static void variance( struct AR7643_SAMPLE *samp, int cnt)
{
int i, w[SAMPLE_CNT] = {0}, aver_x = 0, aver_y = 0, kmax;
int sum_x = 0, sum_y = 0;
for (i = 0; i < cnt; i++)
{
sum_x += samp[i].x;
sum_y += samp[i].y;
}
aver_x = sum_x / cnt;
aver_y = sum_y / cnt;
if (cnt < 3)
{
samp[0].x = aver_x;
samp[0].y = aver_y;
return;
}
w[0] = abs(samp[0].x - aver_x) + abs(samp[0].y - aver_y);
kmax = 0;
for (i = 1; i < cnt; i++)
{
w[i] = abs(samp[i].x - aver_x) + abs(samp[i].y - aver_y);
if (w[i] > w[kmax])
{
kmax = i;
}
}
samp[0].x = (sum_x - samp[kmax].x ) / (cnt - 1);
samp[0].y = (sum_y - samp[kmax].y ) / (cnt - 1);
}
static void ar7643_work(struct work_struct *work)//unsigned long data)
{
struct AR7643_SAMPLE samp[5];
int i;
//static int flg = 0;
if (unlikely(!IS_PEN_DOWN(PIN_INT)))
{
PDEBUG("pen up...\n");
dejitter(ts.dev, &(samp[0]), true);
ar7643_sent_up_event();
ts.pendown = false;
enable_irq(AR7643_IRQ);
}
else
{
if (ts.pendown == false)
{
input_report_key(ts.dev, BTN_TOUCH, 1);
ts.pendown = true;
}
for(i=0;i<SAMPLE_CNT;i++)
{
if (!IS_PEN_DOWN(PIN_INT))
break;
get_xy(&(samp[i]));
}
if (i == SAMPLE_CNT || (i && ts.first == true))
{
if (ts.first == true)
ts.first = false;
variance(samp, i);
PDEBUG("x = %4d\t y = %4d\n", samp[0].x, samp[0].y);
dejitter(ts.dev, &(samp[0]), false);
}
queue_delayed_work(ar7643_wq, &(ts.work),
msecs_to_jiffies(POLL_DELAY));
//mod_timer(&touch_timer, jiffies+ msecs_to_jiffies(POLL_DELAY));
}
}
static int ar7643_send_byte(u8 command)
{
struct spi_message m;
struct spi_transfer xfer;
int status;
u8 buff = command;
spi_message_init(&m);
xfer.tx_buf = &buff;
xfer.rx_buf = NULL;
xfer.len = sizeof(buff);
xfer.bits_per_word = 8;
xfer.speed_hz = ts.speed_hz;
spi_message_add_tail(&xfer, &m);
status = spi_sync(ts.spi, &m);
return status;
}
/*
* The functions for inserting/removing us as a module.
*/
static int __init ar7643_probe(struct spi_device *spi)
{
PDEBUG("%s(): Entering...\n", __FUNCTION__);
/* initialize hardware */
pin_init();
/* Initialise input stuff */
memset(&ts, 0, sizeof(struct ar7643));
ts.dev = input_allocate_device();
if (!ts.dev)
return -ENOMEM;
ts.dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
ts.dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(ts.dev, ABS_X, 0, MAX_12BIT, 0, 0);
input_set_abs_params(ts.dev, ABS_Y, 0, MAX_12BIT, 0, 0);
input_set_abs_params(ts.dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
sprintf(ts.phys, "ar7643-spi");
ts.dev->name = ar7643_name;
ts.dev->phys = ts.phys;
ts.speed_hz = spi->max_speed_hz;
ts.pendown = false;
ts.spi = spi;
INIT_DELAYED_WORK(&(ts.work), ar7643_work);
if (request_irq(AR7643_IRQ, ar7643_irqhandler, 0, "ar7643_spi", 0)) {
printk(KERN_ERR "Could not allocate IRQ %d\n", AR7643_IRQ);
return -EIO;
}
#ifdef DEJITTER
djt.head = 0;
djt.delta = FAST_THRESHOLD;
djt.nr = 0;
#endif
//power down and enable PENIRQ
ar7643_send_byte(0x80);
printk(KERN_INFO "%s successfully loaded\n", ar7643_name);
/* All went ok, so register to the input system */
return input_register_device(ts.dev);
}
static int ar7643_remove(struct spi_device *spi)
{
PDEBUG("%s(): Entering...\n", __FUNCTION__);
disable_irq(AR7643_IRQ);
free_irq(AR7643_IRQ, ts.dev);
input_unregister_device(ts.dev);
return 0;
}
#ifdef DEJITTER
static void average(struct dejitter_info *djt, struct AR7643_SAMPLE *samp)
{
const unsigned char *w;
int sn = djt->head;
int i, x = 0, y = 0;
// unsigned int p = 0;
w = weight [djt->nr - 2];
for (i = 0; i < djt->nr; i++)
{
sn = (sn - 1) & (NR_SAMPHISTLEN - 1);
x += djt->samp [sn].x * w [i];
y += djt->samp [sn].y * w [i];
// p += djt->samp [sn].p * w [i];
}
//printk("%4d\t%4d\t%d\n", x, y, djt->nr);
samp->x = x >> w [NR_SAMPHISTLEN];
samp->y = y >> w [NR_SAMPHISTLEN];
//samp->pressure = p >> w [NR_SAMPHISTLEN];
//PDEBUG("DEJITTER----------------> %d %d %d\n",samp->x, samp->y, 0);
}
static int dejitter(struct input_dev *dev, struct AR7643_SAMPLE *_samp, bool penup)
{
static struct AR7643_SAMPLE temp;
if (penup == true)
{
djt.head = 0;
djt.nr = 0;;
return 1;
}
/* If the pen moves too fast, reset the backlog. */
if (djt.nr)
{
int prev = (djt.head - 1) & (NR_SAMPHISTLEN - 1);
if (abs(_samp->x - djt.samp[prev].x) + abs(_samp->y - djt.samp[prev].y) > djt.delta)
djt.nr = 0;
}
djt.samp[djt.head] = *_samp;
djt.head = (djt.head + 1) & (NR_SAMPHISTLEN - 1);
if (djt.nr < NR_SAMPHISTLEN)
++djt.nr;
if (djt.nr == 1)
{
temp = *_samp;
}
else
{
average(&djt, &temp);
}
report_value(dev, &temp);
return 1;
}
#endif
#ifdef CONFIG_PM
static int ar7643_suspend(struct spi_device *spi, pm_message_t state)
{
PDEBUG("%s(): Entering...\n", __FUNCTION__);
return 0;
}
static int ar7643_resume(struct spi_device *spi)
{
PDEBUG("%s(): Entering...\n", __FUNCTION__);
return 0;
}
#endif
static struct spi_driver ar7643_driver = {
.driver = {
.name = "ar7643-spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = ar7643_probe,
.remove = ar7643_remove,
#ifdef CONFIG_PM
.suspend = ar7643_suspend,
.resume = ar7643_resume,
#endif
};
static int __init ar7643_init(void)
{
printk("AR7643 SPI Touchscreen Driver for AK98, (c) 2011 ANYKA\n");
ar7643_wq = create_singlethread_workqueue("ar7643_wq");
if (!ar7643_wq)
return -ENOMEM;
return spi_register_driver(&ar7643_driver);
}
static void __exit ar7643_exit(void)
{
if (ar7643_wq)
destroy_workqueue(ar7643_wq);
spi_unregister_driver(&ar7643_driver);
}
module_init(ar7643_init);
module_exit(ar7643_exit);
MODULE_AUTHOR("Anyka,Ltd");
MODULE_DESCRIPTION("AR7643 SPI TouchScreen Driver");
MODULE_LICENSE("GPL");