/*
- * drivers/input/touchscreen/xpt2046_cbn_ts.c - driver for rk2818 spi xpt2046 calibration device and console
+ * drivers/input/touchscreen/xpt2046_ts.c - driver for rk29 spi xpt2046 device and console
*
- * Copyright (C) 2010 ROCKCHIP, Inc.
+ * Copyright (C) 2011 ROCKCHIP, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <asm/irq.h>
-
+#include <mach/iomux.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
#include "xpt2046_cbn_ts.h"
#include "calibration_ts.h"
/*
#define xpt2046printk(msg...)
#endif
-//#define TS_POLL_DELAY (15 * 1000000) /* ns delay before the first sample */
-//#define TS_POLL_PERIOD (15 * 1000000) /* ns delay between samples */
#define TS_POLL_DELAY (10 * 1000000) /* ns delay before the first sample */
#define TS_POLL_PERIOD (20 * 1000000) /* ns delay between samples */
-
-#define DEBOUNCE_REPTIME 3
/* this driver doesn't aim at the peak continuous sample rate */
#define SAMPLE_BITS (8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
struct xpt2046 {
struct input_dev *input;
- char phys[32];
- char name[32];
-
+ char phys[32];
+ char name[32];
+ char pendown_iomux_name[IOMUX_NAME_SIZE];
struct spi_device *spi;
- u16 model;
- bool swap_xy;
-
+ u16 model;
+ u16 x_min, x_max;
+ u16 y_min, y_max;
+ u16 debounce_max;
+ u16 debounce_tol;
+ u16 debounce_rep;
+ u16 penirq_recheck_delay_usecs;
+ bool swap_xy;
+
struct xpt2046_packet *packet;
struct spi_transfer xfer[18];
struct spi_message msg[5];
struct spi_message *last_msg;
- int msg_idx;
- int read_cnt;
- int read_rep;
- int last_read;
-
- u16 debounce_max;
- u16 debounce_tol;
- u16 debounce_rep;
-
- u16 penirq_recheck_delay_usecs;
-
+ int msg_idx;
+ int read_cnt;
+ int read_rep;
+ int last_read;
+ int pendown_iomux_mode;
+ int touch_virtualkey_length;
spinlock_t lock;
- struct hrtimer timer;
+ struct hrtimer timer;
unsigned pendown:1; /* P: lock */
unsigned pending:1; /* P: lock */
// FIXME remove "irq_disabled"
unsigned is_suspended:1;
int (*filter)(void *data, int data_idx, int *val);
- void *filter_data;
- void (*filter_cleanup)(void *data);
+ void *filter_data;
+ void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
int gpio_pendown;
- void (*wait_for_sync)(void);
+ void (*wait_for_sync)(void);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+#endif
};
/* leave chip selected when we're done, for quicker re-select? */
struct spi_message msg;
struct spi_transfer xfer[4];
};
-typedef struct
-{
- s16 x;
- s16 y;
-}POINT;
-
-#if (0)
-static struct xpt2046_platform_data xpt2046_info = {
- .model = 2046,
- .keep_vref_on = 1,
- .swap_xy = 0,
- .x_min = 0,
- .x_max = 800,
- .y_min = 0,
- .y_max = 480,
- .debounce_max = 7,
- .debounce_rep = DEBOUNCE_REPTIME,
- .debounce_tol = 20,
- .gpio_pendown = RK2818_PIN_PE3,
- .penirq_recheck_delay_usecs = 1,
-};
-#endif /* (0) */
+volatile struct adc_point gADPoint;
+
static void xpt2046_enable(struct xpt2046 *ts);
static void xpt2046_disable(struct xpt2046 *ts);
-
-static POINT gADPoint;
-int screen_x[] = { 50, 750, 50, 750, 400};
-int screen_y[] = { 40, 40, 440, 440, 240};
-int uncali_x[] = {329, 3750, 331, 3757, 2046};
-int uncali_y[] = {593, 532, 3675, 3655, 2121};
-
-// This code is touch check
-static ssize_t xpt2046_mode_show(struct device_driver *drv,char *buf)
+static int xpt2046_verifyAndConvert(struct xpt2046 *ts,int adx, int ady,int *x, int *y)
{
- int count;
-
- count = sprintf(buf,"xpt2046_mode_show:%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
- uncali_x[0], uncali_y[0],
- uncali_x[1], uncali_y[1],
- uncali_x[2], uncali_y[2],
- uncali_x[3], uncali_y[3],
- uncali_x[4], uncali_y[4]);
-
- printk("buf: %s", buf);
+ xpt2046printk("%s:(%d/%d)\n",__FUNCTION__,*x, *y);
- return count;
-}
+ if((*x< ts->x_min) || (*x > ts->x_max))
+ return 1;
-static ssize_t xpt2046_mode_store(struct device_driver * drv, const char * buf, size_t count)
-{
- int i, j = 0;
- char temp[5];
+ if((*y< ts->y_min) || (*y > ts->y_max + ts->touch_virtualkey_length))
+ return 1;
- printk("xpt2046_mode_store: %s\n", buf);
-
- for (i = 0; i < 5; i++)
- {
- strncpy(temp, buf + 5 * (j++), 4);
- uncali_x[i] = simple_strtol(temp, NULL, 10);
- strncpy(temp, buf + 5 * (j++), 4);
- uncali_y[i] = simple_strtol(temp, NULL, 10);
- printk("SN=%d uncali_x=%d uncali_y=%d\n",
- i, uncali_x[i], uncali_y[i]);
- }
- return count;
-}
-
-//This code is Touch adc simple value
-static ssize_t xpt2046_adc_show(struct device_driver *drv,char *buf)
-{
- printk("xpt2046_adc_show: x=%d y=%d\n", gADPoint.x, gADPoint.y);
-
- return sprintf(buf, "%d,%d\n", gADPoint.x, gADPoint.y);
-}
-
-static ssize_t xpt2046_cali_status(struct device_driver *drv, char *buf)
-{
- int ret;
-
- ret = TouchPanelSetCalibration(4, screen_x, screen_y, uncali_x, uncali_y);
- if (ret == 1)
- ret = sprintf(buf, "successful\n");
- else
- ret = sprintf(buf, "fail\n");
-
- printk("xpt2046_cali_status: buf=<%s", buf);
-
- return ret;
+ return 0;
}
-
-//static DEVICE_ATTR(adc, 0666, xpt2046_adc_show, NULL);
-//static DEVICE_ATTR(calistatus, 0666, xpt2046_cali_status, NULL);
-//static DEVICE_ATTR(mode, 0666, xpt2046_mode_show, xpt2046_mode_store);
-static DRIVER_ATTR(touchadc, 0666, xpt2046_adc_show, NULL);
-static DRIVER_ATTR(calistatus, 0666, xpt2046_cali_status, NULL);
-static DRIVER_ATTR(touchcheck, 0666, xpt2046_mode_show, xpt2046_mode_store);
-#if (0)
-static struct attribute *xpt2046_attributes[] = {
- &dev_attr_touchadc.attr,
- &dev_attr_calistatus.attr,
- &dev_attr_touchcheck.attr,
- NULL,
-};
-
-static struct attribute_group xpt2046_attr_group = {
- .attrs = xpt2046_attributes,
-};
-#endif /* (0) */
-
static int device_suspended(struct device *dev)
{
struct xpt2046 *ts = dev_get_drvdata(dev);
* The SPI transfer completion callback does the real work. It reports
* touchscreen events and reactivates the timer (or IRQ) as appropriate.
*/
-
static void xpt2046_rx(void *xpt)
{
struct xpt2046 *ts = xpt;
struct xpt2046_packet *packet = ts->packet;
unsigned Rt = 1;
u16 x, y;
- int xd,yd;
+ int cal_x,cal_y;
/* xpt2046_rx_val() did in-place conversion (including byteswap) from
* on-the-wire format as part of debouncing to get stable readings.
*/
*/
if (Rt) {
struct input_dev *input = ts->input;
- if (!ts->pendown) {
- input_report_key(input, BTN_TOUCH, 1);
- ts->pendown = 1;
- xpt2046printk("***>%s:input_report_key(pen down)\n",__FUNCTION__);
- }
- TouchPanelCalibrateAPoint(x, y, &xd, &yd);
+ TouchPanelCalibrateAPoint(x, y, &cal_x, &cal_y);
- xd = xd / 4;
- yd = yd / 4;
+ cal_x = cal_x / 4;
+ cal_y = cal_y / 4;
gADPoint.x = x;
gADPoint.y = y;
if (ts->swap_xy)
- swap(x, y);
+ swap(cal_x, cal_y);
+ if(xpt2046_verifyAndConvert(ts,cal_x,cal_y,&cal_x,&cal_y))
+ {
+ xpt2046printk("***>%s:xpt2046_verifyAndConvert fail\n",__FUNCTION__);
+ goto out;
+ }
- input_report_abs(input, ABS_X, xd);
- input_report_abs(input, ABS_Y, yd);
+ if (!ts->pendown) {
+ input_report_key(input, BTN_TOUCH, 1);
+ ts->pendown = 1;
+ xpt2046printk("***>%s:input_report_key(pen down)\n",__FUNCTION__);
+ }
+
+ input_report_abs(input, ABS_X, cal_x);
+ input_report_abs(input, ABS_Y, cal_y);
input_sync(input);
- xpt2046printk("***>%s:input_report_abs(%4d/%4d)\n",__FUNCTION__,xd, yd);
+ xpt2046printk("***>%s:input_report_abs(%4d/%4d)\n",__FUNCTION__,cal_x, cal_y);
}
-
+out:
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
HRTIMER_MODE_REL);
}
abs(ts->last_read - *val),ts->debounce_tol,
ts->read_rep,ts->debounce_rep);
+ /* discard the first sample. */
+ //on info_it50, the top-left area(1cmx1cm top-left square ) is not responding cause the first sample is invalid, @sep 17th
+ if(!ts->read_cnt)
+ {
+ //udelay(100);
+ ts->read_cnt++;
+ return XPT2046_FILTER_REPEAT;
+ }
if(*val == 4095 || *val == 0)
{
ts->read_cnt = 0;
xpt2046printk("***>%s:*val == 4095 || *val == 0\n",__FUNCTION__);
return XPT2046_FILTER_IGNORE;
}
- /* discard the first sample. */
- if(!ts->read_cnt)
- {
- //udelay(100);
- ts->read_cnt++;
- return XPT2046_FILTER_REPEAT;
- }
+
if (ts->read_cnt==1 || (abs(ts->last_read - *val) > ts->debounce_tol)) {
/* Start over collecting consistent readings. */
int status = 0;
spin_lock(&ts->lock);
-
+
if (unlikely(!get_pendown_state(ts) ||
device_suspended(&ts->spi->dev))) {
if (ts->pendown) {
enable_irq(ts->spi->irq);
}
-static int xpt2046_suspend(struct spi_device *spi, pm_message_t message)
+static int xpt2046_pSuspend(struct xpt2046 *ts)
{
- struct xpt2046 *ts = dev_get_drvdata(&spi->dev);
-
spin_lock_irq(&ts->lock);
ts->is_suspended = 1;
spin_unlock_irq(&ts->lock);
return 0;
-
}
-static int xpt2046_resume(struct spi_device *spi)
+static int xpt2046_pResume(struct xpt2046 *ts)
{
- struct xpt2046 *ts = dev_get_drvdata(&spi->dev);
-
spin_lock_irq(&ts->lock);
ts->is_suspended = 0;
return 0;
}
+#if !defined(CONFIG_HAS_EARLYSUSPEND)
+static int xpt2046_suspend(struct spi_device *spi, pm_message_t message)
+{
+ struct xpt2046 *ts = dev_get_drvdata(&spi->dev);
+
+ printk("xpt2046_suspend\n");
+
+ xpt2046_pSuspend(ts);
+
+ return 0;
+}
+
+static int xpt2046_resume(struct spi_device *spi)
+{
+ struct xpt2046 *ts = dev_get_drvdata(&spi->dev);
+
+ printk("xpt2046_resume\n");
+
+ xpt2046_pResume(ts);
+
+ return 0;
+}
+
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+static void xpt2046_early_suspend(struct early_suspend *h)
+{
+ struct xpt2046 *ts;
+ ts = container_of(h, struct xpt2046, early_suspend);
+
+ printk("xpt2046_suspend early\n");
+
+ xpt2046_pSuspend(ts);
+
+ return;
+}
+
+static void xpt2046_late_resume(struct early_suspend *h)
+{
+ struct xpt2046 *ts;
+ ts = container_of(h, struct xpt2046, early_suspend);
+
+ printk("xpt2046_resume late\n");
+
+ xpt2046_pResume(ts);
+
+ return;
+}
+#endif
+
static int __devinit setup_pendown(struct spi_device *spi, struct xpt2046 *ts)
{
struct xpt2046_platform_data *pdata = spi->dev.platform_data;
return 0;
}
- if (pdata->io_init) {
+ if (pdata->io_init) {
err = pdata->io_init();
if (err)
dev_err(&spi->dev, "xpt2046 io_init fail\n");
}
+ ts->gpio_pendown = pdata->gpio_pendown;
+ strcpy(ts->pendown_iomux_name,pdata->pendown_iomux_name);
+ ts->pendown_iomux_mode = pdata->pendown_iomux_mode;
+
+ rk29_mux_api_set(ts->pendown_iomux_name,pdata->pendown_iomux_mode);
err = gpio_request(pdata->gpio_pendown, "xpt2046_pendown");
if (err) {
dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
pdata->gpio_pendown);
return err;
}
-
+
+ err = gpio_pull_updown(pdata->gpio_pendown, GPIOPullUp);
+ if (err) {
+ dev_err(&spi->dev, "failed to pullup pendown GPIO%d\n",
+ pdata->gpio_pendown);
+ return err;
+ }
ts->gpio_pendown = pdata->gpio_pendown;
return 0;
}
int vref;
int err;
-
-
if (!spi->irq) {
dev_dbg(&spi->dev, "no IRQ?\n");
return -ENODEV;
spi->irq = gpio_to_irq(spi->irq);
dev_dbg(&spi->dev, "no IRQ?\n");
}
-
- if (!pdata) {
+
+ if (!pdata) {
dev_err(&spi->dev, "empty platform_data\n");
return -EFAULT;
- }
-
+ }
+
/* don't exceed max specified sample rate */
if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
spin_lock_init(&ts->lock);
ts->model = pdata->model ? : 2046;
-
+
if (pdata->filter != NULL) {
if (pdata->filter_init != NULL) {
err = pdata->filter_init(pdata, &ts->filter_data);
pdata->penirq_recheck_delay_usecs;
ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
+ ts->x_min = pdata->x_min;
+ ts->x_max = pdata->x_max;
+ ts->y_min = pdata->y_min;
+ ts->y_max = pdata->y_max;
+
+ ts->touch_virtualkey_length = pdata->touch_virtualkey_length;
+
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
- snprintf(ts->name, sizeof(ts->name), "XPT%d Touchscreen", ts->model);
+ snprintf(ts->name, sizeof(ts->name), "xpt%d-touchscreen", ts->model);
input_dev->name = ts->name;
input_dev->phys = ts->phys;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
- pdata->x_min ? : 0,
- pdata->x_max ? : MAX_12BIT,
+ ts->x_min ? : 0,
+ ts->x_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_Y,
- pdata->y_min ? : 0,
- pdata->y_max ? : MAX_12BIT,
+ ts->y_min ? : 0,
+ ts->y_max ? : MAX_12BIT,
0, 0);
vref = pdata->keep_vref_on;
+ tp_calib_iface_init(pdata->screen_x,pdata->screen_y,pdata->uncali_x_default,pdata->uncali_y_default);
/* set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3.
*/
if (request_irq(spi->irq, xpt2046_irq, IRQF_TRIGGER_FALLING,
spi->dev.driver->name, ts)) {
- printk("%s:trying pin change workaround on irq %d\n",__FUNCTION__,spi->irq);
+ xpt2046printk("%s:trying pin change workaround on irq %d\n",__FUNCTION__,spi->irq);
err = request_irq(spi->irq, xpt2046_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
spi->dev.driver->name, ts);
*/
xpt2046_read12_dfr(&spi->dev,READ_X(1));
- //err = sysfs_create_group(&spi->dev.kobj, &xpt2046_attr_group);
- if (err)
- goto err_remove_hwmon;
-
err = input_register_device(input_dev);
if (err)
goto err_remove_attr_group;
- printk("xpt2046_ts: driver initialized\n");
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ ts->early_suspend.suspend = xpt2046_early_suspend;
+ ts->early_suspend.resume = xpt2046_late_resume;
+ ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
+ register_early_suspend(&ts->early_suspend);
+#endif
+
+ xpt2046printk("xpt2046_ts: driver initialized\n");
return 0;
err_remove_attr_group:
- //sysfs_remove_group(&spi->dev.kobj, &xpt2046_attr_group);
- err_remove_hwmon:
free_irq(spi->irq, ts);
err_free_gpio:
if (ts->gpio_pendown != -1)
return err;
}
+
static int __devexit xpt2046_remove(struct spi_device *spi)
{
struct xpt2046 *ts = dev_get_drvdata(&spi->dev);
input_unregister_device(ts->input);
-
+
+#if !defined(CONFIG_HAS_EARLYSUSPEND)
xpt2046_suspend(spi, PMSG_SUSPEND);
-
- //sysfs_remove_group(&spi->dev.kobj, &xpt2046_attr_group);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ xpt2046_early_suspend(&ts->early_suspend);
+ unregister_early_suspend(&ts->early_suspend);
+#endif
free_irq(ts->spi->irq, ts);
/* suspend left the IRQ disabled */
kfree(ts->packet);
kfree(ts);
-
+
+ tp_calib_iface_exit();
+
dev_dbg(&spi->dev, "unregistered touchscreen\n");
return 0;
}
},
.probe = xpt2046_probe,
.remove = __devexit_p(xpt2046_remove),
+#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = xpt2046_suspend,
.resume = xpt2046_resume,
+#endif
};
static int __init xpt2046_init(void)
{
- //return spi_register_driver(&xpt2046_driver);
- int ret = spi_register_driver(&xpt2046_driver);
+ int ret;
+ gADPoint.x = 0;
+ gADPoint.y = 0;
- if (ret == 0)
+ xpt2046printk("Touch panel drive XPT2046 driver init...\n");
+ ret = spi_register_driver(&xpt2046_driver);
+ if (ret)
{
- gADPoint.x = 0;
- gADPoint.y = 0;
- ret = driver_create_file(&xpt2046_driver.driver, &driver_attr_touchcheck);
- ret += driver_create_file(&xpt2046_driver.driver, &driver_attr_touchadc);
- ret += driver_create_file(&xpt2046_driver.driver, &driver_attr_calistatus);
+ printk("Register XPT2046 driver failed.\n");
+ return ret;
}
-
- return ret;
+
+ return 0;
+
}
-module_init(xpt2046_init);
+
static void __exit xpt2046_exit(void)
{
- //spi_unregister_driver(&xpt2046_driver);
- driver_remove_file(&xpt2046_driver.driver, &driver_attr_touchcheck);
- driver_remove_file(&xpt2046_driver.driver, &driver_attr_touchadc);
- driver_remove_file(&xpt2046_driver.driver, &driver_attr_calistatus);
-
+ xpt2046printk("Touch panel drive XPT2046 driver exit...\n");
spi_unregister_driver(&xpt2046_driver);
}
+module_init(xpt2046_init);
module_exit(xpt2046_exit);
-MODULE_DESCRIPTION("rk2818 spi xpt2046 TouchScreen Driver");
+MODULE_DESCRIPTION("rk29xx spi xpt2046 TouchScreen Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:xpt2046");