summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Konovalov <andrey.konovalov@linaro.org>2012-04-19 23:35:23 +0400
committerAndrey Konovalov <andrey.konovalov@linaro.org>2012-04-19 23:35:23 +0400
commitb653b77a84c1be41ae737806acb66deec731c8fb (patch)
treec7362466592c6b6235f1480f6eaa9dd0a3606953
parent68fa27d1420e8b590d310d2b310e68010b4c825d (diff)
parentcfa9fbfdddd980e45116e94384d6cf4833cdf44d (diff)
downloadlinux-topics-b653b77a84c1be41ae737806acb66deec731c8fb.tar.gz
Merge branch 'rebase-samslt-touch' into merge-linux-linaro
-rw-r--r--arch/arm/configs/exynos4_defconfig1
-rw-r--r--arch/arm/mach-exynos/include/mach/irqs.h1
-rw-r--r--arch/arm/mach-exynos/mach-origen.c6
-rw-r--r--configs/origen.conf1
-rw-r--r--drivers/input/touchscreen/Kconfig7
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/unidisplay_ts.c406
7 files changed, 423 insertions, 0 deletions
diff --git a/arch/arm/configs/exynos4_defconfig b/arch/arm/configs/exynos4_defconfig
index 42289fb55c0..6a19e5b567b 100644
--- a/arch/arm/configs/exynos4_defconfig
+++ b/arch/arm/configs/exynos4_defconfig
@@ -57,6 +57,7 @@ CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_UNIDISPLAY_TS=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_SAMSUNG=y
CONFIG_SERIAL_SAMSUNG_CONSOLE=y
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index bcc14e25156..ab390108bf1 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -462,6 +462,7 @@
#define S5P_GPIOINT_BASE (S5P_EINT_BASE1 + 32)
#define IRQ_GPIO_END (S5P_GPIOINT_BASE + S5P_GPIOINT_COUNT)
#define IRQ_TIMER_BASE (IRQ_GPIO_END + 64)
+#define IRQ_TS (S5P_EINT_BASE1 + 25)
/* Set the default NR_IRQS */
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c
index 65b1af7f73f..b2a248020b9 100644
--- a/arch/arm/mach-exynos/mach-origen.c
+++ b/arch/arm/mach-exynos/mach-origen.c
@@ -469,6 +469,12 @@ static struct i2c_board_info i2c0_devs[] __initdata = {
.platform_data = &origen_max8997_pdata,
.irq = IRQ_EINT(4),
},
+#ifdef CONFIG_TOUCHSCREEN_UNIDISPLAY_TS
+ {
+ I2C_BOARD_INFO("unidisplay_ts", 0x41),
+ .irq = IRQ_TS,
+ },
+#endif
};
static struct s3c_sdhci_platdata origen_hsmmc0_pdata __initdata = {
diff --git a/configs/origen.conf b/configs/origen.conf
index c5f430e01ef..1b2fdb2e62c 100644
--- a/configs/origen.conf
+++ b/configs/origen.conf
@@ -36,6 +36,7 @@ CONFIG_ATH6KL=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_UNIDISPLAY_TS=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_SAMSUNG=y
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 1e7c563c090..bd650ff1852 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -851,4 +851,11 @@ config TOUCHSCREEN_TPS6507X
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
+config TOUCHSCREEN_UNIDISPLAY_TS
+ tristate "Pixcir capacitive touchscreen driver"
+ depends on I2C
+ help
+ Say Y here if you have a Pixcir capacitive based touchscreen
+ controller.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 175d641404c..ce7273b7147 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -70,3 +70,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o
obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o
obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o
+obj-$(CONFIG_TOUCHSCREEN_UNIDISPLAY_TS) += unidisplay_ts.o
diff --git a/drivers/input/touchscreen/unidisplay_ts.c b/drivers/input/touchscreen/unidisplay_ts.c
new file mode 100644
index 00000000000..b0504d4c77a
--- /dev/null
+++ b/drivers/input/touchscreen/unidisplay_ts.c
@@ -0,0 +1,406 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/gpio.h>
+
+#include <mach/regs-gpio.h>
+
+#include <plat/gpio-cfg.h>
+
+/* 20 ms */
+#define TOUCH_READ_TIME msecs_to_jiffies(20)
+
+#define TOUCH_INT_PIN EXYNOS4_GPX3(1)
+#define TOUCH_INT_PIN_SHIFT 1
+#define TOUCH_RST_PIN EXYNOS4_GPE3(5)
+
+#define TOUCHSCREEN_MINX 0
+#define TOUCHSCREEN_MAXX 3968
+#define TOUCHSCREEN_MINY 0
+#define TOUCHSCREEN_MAXY 2304
+#define TOUCH_DEBUG
+#ifdef TOUCH_DEBUG
+#define DEBUG_PRINT(fmt, args...) printk(fmt, ##args)
+#else
+#define DEBUG_PRINT(fmt, args...)
+#endif
+
+#define INPUT_REPORT(x, y, p, val1, val2) \
+ { \
+ input_report_abs(tsdata->input, ABS_MT_POSITION_X, x); \
+ input_report_abs(tsdata->input, ABS_MT_POSITION_Y, y); \
+ input_report_abs(tsdata->input, ABS_MT_TOUCH_MAJOR, p); \
+ input_report_abs(tsdata->input, ABS_PRESSURE, val1); \
+ input_report_key(tsdata->input, BTN_TOUCH, val2); \
+ input_mt_sync(tsdata->input); \
+ }
+
+struct unidisplay_ts_data {
+ struct i2c_client *client;
+ struct input_dev *input;
+ struct task_struct *kidle_task;
+ wait_queue_head_t idle_wait;
+ struct delayed_work work;
+ int irq;
+ unsigned int irq_pending;
+};
+
+
+static irqreturn_t unidisplay_ts_isr(int irq, void *dev_id);
+
+static void unidisplay_ts_config(void)
+{
+ s3c_gpio_cfgpin(TOUCH_INT_PIN, S3C_GPIO_SFN(0x0F));
+ s3c_gpio_setpull(TOUCH_INT_PIN, S3C_GPIO_PULL_UP);
+
+ if (gpio_request(TOUCH_INT_PIN, "TOUCH_INT_PIN")) {
+ pr_err("%s : gpio request failed.\n", __func__);
+ return;
+ }
+ gpio_direction_input(TOUCH_INT_PIN);
+ gpio_free(TOUCH_INT_PIN);
+
+ s3c_gpio_setpull(TOUCH_RST_PIN, S3C_GPIO_PULL_NONE);
+ s3c_gpio_cfgpin(TOUCH_RST_PIN, S3C_GPIO_OUTPUT);
+
+ if (gpio_request(TOUCH_RST_PIN, "TOUCH_RST_PIN")) {
+ pr_err("%s : gpio request failed.\n", __func__);
+ return;
+ }
+ gpio_direction_output(TOUCH_RST_PIN, 1);
+ gpio_free(TOUCH_RST_PIN);
+}
+
+static void unidisplay_ts_start(void)
+{
+ if (gpio_request(TOUCH_RST_PIN, "TOUCH_RST_PIN")) {
+ pr_err("%s : gpio request failed.\n", __func__);
+ return;
+ }
+ gpio_set_value(TOUCH_RST_PIN, 0);
+ gpio_free(TOUCH_RST_PIN);
+}
+
+static void unidisplay_ts_stop(void)
+{
+ if (gpio_request(TOUCH_RST_PIN, "TOUCH_RST_PIN")) {
+ pr_err("%s : gpio request failed.\n", __func__);
+ return;
+ }
+ gpio_set_value(TOUCH_RST_PIN, 1);
+ gpio_free(TOUCH_RST_PIN);
+}
+
+static void unidisplay_ts_reset(void)
+{
+ unidisplay_ts_stop();
+ udelay(100);
+ unidisplay_ts_start();
+}
+
+static int unidisplay_ts_pen_up(void)
+{
+ return (gpio_get_value(TOUCH_INT_PIN) & 0x1);
+}
+
+static irqreturn_t unidisplay_ts_isr(int irq, void *dev_id)
+{
+ struct unidisplay_ts_data *tsdata = dev_id;
+ if (irq == tsdata->irq) {
+ disable_irq_nosync(tsdata->irq);
+ tsdata->irq_pending = 1;
+ wake_up(&tsdata->idle_wait);
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE;
+}
+
+static int unidisplay_ts_thread(void *kthread)
+{
+ struct unidisplay_ts_data *tsdata = kthread;
+ struct task_struct *tsk = current;
+ int ret = 0;
+ struct sched_param param = { .sched_priority = 1 };
+ sched_setscheduler(tsk, SCHED_FIFO, &param);
+ set_freezable();
+ while (!kthread_should_stop()) {
+ int x1 = 0, y1 = 0;
+ u8 buf[9];
+ u8 type = 0;
+ unsigned int pendown = 0;
+ long timeout = 0;
+ if (tsdata->irq_pending) {
+ tsdata->irq_pending = 0;
+ enable_irq(tsdata->irq);
+ }
+ pendown = !unidisplay_ts_pen_up();
+ if (pendown) {
+ u8 addr = 0x10;
+ memset(buf, 0, sizeof(buf));
+ ret = i2c_master_send(tsdata->client, &addr, 1);
+ if (ret != 1) {
+ dev_err(&tsdata->client->dev,\
+ "Unable to write to i2c touchscreen\n");
+ ret = -EIO;
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ goto wait_event;
+ }
+ ret = i2c_master_recv(tsdata->client, buf, 9);
+ if (ret != 9) {
+ dev_err(&tsdata->client->dev,\
+ "Unable to read to i2c touchscreen!\n");
+ ret = -EIO;
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ goto wait_event;
+ }
+ /* mark everything ok now */
+ ret = 0;
+ type = buf[0];
+ if (type & 0x1) {
+ x1 = buf[2];
+ x1 <<= 8;
+ x1 |= buf[1];
+ y1 = buf[4];
+ y1 <<= 8;
+ y1 |= buf[3];
+ INPUT_REPORT(x1, y1, 1, 255, 1);
+ }
+ if (type & 0x2) {
+ x1 = buf[6];
+ x1 <<= 8;
+ x1 |= buf[5];
+ y1 = buf[8];
+ y1 <<= 8;
+ y1 |= buf[7];
+ INPUT_REPORT(x1, y1, 2, 255, 1);
+ }
+ input_sync(tsdata->input);
+ timeout = msecs_to_jiffies(20);
+ } else {
+ INPUT_REPORT(0, 0, 0, 0 ,0);
+ INPUT_REPORT(0, 0, 0, 0, 0);
+ input_sync(tsdata->input);
+ timeout = MAX_SCHEDULE_TIMEOUT;
+ }
+wait_event:
+ wait_event_freezable_timeout(tsdata->idle_wait, \
+ tsdata->irq_pending || kthread_should_stop(), \
+ timeout);
+ }
+ return ret;
+}
+
+static int unidisplay_ts_open(struct input_dev *dev)
+{
+ struct unidisplay_ts_data *tsdata = input_get_drvdata(dev);
+ int ret = 0;
+ u8 addr = 0x10;
+ BUG_ON(tsdata->kidle_task);
+
+ ret = i2c_master_send(tsdata->client, &addr, 1);
+
+ if (ret != 1) {
+ dev_err(&tsdata->client->dev, "Unable to open touchscreen device\n");
+ return -ENODEV;
+ }
+
+ tsdata->kidle_task = kthread_run(unidisplay_ts_thread, tsdata, \
+ "unidisplay_ts");
+ if (IS_ERR(tsdata->kidle_task)) {
+ ret = PTR_ERR(tsdata->kidle_task);
+ tsdata->kidle_task = NULL;
+ return ret;
+ }
+ enable_irq(tsdata->irq);
+
+ return 0;
+}
+
+static void unidisplay_ts_close(struct input_dev *dev)
+{
+ struct unidisplay_ts_data *tsdata = input_get_drvdata(dev);
+
+ if (tsdata->kidle_task) {
+ kthread_stop(tsdata->kidle_task);
+ tsdata->kidle_task = NULL;
+ }
+
+ disable_irq(tsdata->irq);
+}
+
+static int unidisplay_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct unidisplay_ts_data *tsdata;
+ int err;
+
+ unidisplay_ts_config();
+ unidisplay_ts_reset();
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c func not supported\n");
+ err = -EIO;
+ goto end;
+ }
+
+ tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
+ if (!tsdata) {
+ dev_err(&client->dev, "failed to allocate driver data!\n");
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ dev_set_drvdata(&client->dev, tsdata);
+
+ tsdata->input = input_allocate_device();
+ if (!tsdata->input) {
+ dev_err(&client->dev, "failed to allocate input device!\n");
+ err = -ENOMEM;
+ goto fail2;
+ }
+
+ tsdata->input->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) |\
+ BIT_MASK(EV_ABS);
+ set_bit(EV_SYN, tsdata->input->evbit);
+ set_bit(EV_KEY, tsdata->input->evbit);
+ set_bit(EV_ABS, tsdata->input->evbit);
+
+ tsdata->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ set_bit(0, tsdata->input->absbit);
+ set_bit(1, tsdata->input->absbit);
+ set_bit(2, tsdata->input->absbit);
+
+ input_set_abs_params(tsdata->input, ABS_X, TOUCHSCREEN_MINX,\
+ TOUCHSCREEN_MAXX, 0, 0);
+ input_set_abs_params(tsdata->input, ABS_Y, TOUCHSCREEN_MINY,\
+ TOUCHSCREEN_MAXY, 0, 0);
+ input_set_abs_params(tsdata->input, ABS_HAT0X, TOUCHSCREEN_MINX,\
+ TOUCHSCREEN_MAXX, 0, 0);
+ input_set_abs_params(tsdata->input, ABS_HAT0Y, TOUCHSCREEN_MINY,\
+ TOUCHSCREEN_MAXY, 0, 0);
+ input_set_abs_params(tsdata->input, ABS_MT_POSITION_X,\
+ TOUCHSCREEN_MINX, TOUCHSCREEN_MAXX, 0, 0);
+ input_set_abs_params(tsdata->input, ABS_MT_POSITION_Y, \
+ TOUCHSCREEN_MINY, TOUCHSCREEN_MAXY, 0, 0);
+ input_set_abs_params(tsdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(tsdata->input, ABS_MT_WIDTH_MAJOR, 0, 25, 0, 0);
+
+ tsdata->input->name = client->name;
+ tsdata->input->id.bustype = BUS_I2C;
+ tsdata->input->dev.parent = &client->dev;
+
+ tsdata->input->open = unidisplay_ts_open;
+ tsdata->input->close = unidisplay_ts_close;
+
+ input_set_drvdata(tsdata->input, tsdata);
+
+ tsdata->client = client;
+ tsdata->irq = client->irq;
+
+ err = input_register_device(tsdata->input);
+ if (err)
+ goto fail2;
+
+ device_init_wakeup(&client->dev, 1);
+ init_waitqueue_head(&tsdata->idle_wait);
+
+ err = request_irq(tsdata->irq, unidisplay_ts_isr,\
+ IRQF_TRIGGER_FALLING, client->name, tsdata);
+ if (err != 0) {
+ dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
+ goto fail3;
+ }
+ /* disable irq for now, will be enabled when device is opened */
+ disable_irq(tsdata->irq);
+ pr_info("Unidisplay touch driver registered successfully\n");
+ return err;
+fail3:
+ input_unregister_device(tsdata->input);
+fail2:
+ input_free_device(tsdata->input);
+ kfree(tsdata);
+fail1:
+ dev_set_drvdata(&client->dev, NULL);
+end:
+ return err;
+}
+
+
+static int unidisplay_ts_remove(struct i2c_client *client)
+{
+ struct unidisplay_ts_data *tsdata = dev_get_drvdata(&client->dev);
+ disable_irq(tsdata->irq);
+ free_irq(tsdata->irq, tsdata);
+ input_unregister_device(tsdata->input);
+ kfree(tsdata);
+ dev_set_drvdata(&client->dev, NULL);
+ return 0;
+}
+#ifdef CONFIG_PM
+static int unidisplay_ts_suspend(struct device *dev)
+{
+ struct unidisplay_ts_data *tsdata = dev_get_drvdata(dev);
+ disable_irq(tsdata->irq);
+ return 0;
+}
+
+static int unidisplay_ts_resume(struct device *dev)
+{
+ struct unidisplay_ts_data *tsdata = dev_get_drvdata(dev);
+ enable_irq(tsdata->irq);
+ return 0;
+}
+static const struct dev_pm_ops unidisplay_ts_pm = {
+ .suspend = unidisplay_ts_suspend,
+ .resume = unidisplay_ts_resume,
+};
+#endif
+
+static const struct i2c_device_id unidisplay_ts_i2c_id[] = {
+ { "unidisplay_ts", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, unidisplay_ts_i2c_id);
+
+static struct i2c_driver unidisplay_ts_i2c_driver = {
+ .driver = {
+ .name = "Unidisplay Touch Driver",
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &unidisplay_ts_pm,
+#endif
+ },
+ .probe = unidisplay_ts_probe,
+ .remove = unidisplay_ts_remove,
+ .id_table = unidisplay_ts_i2c_id,
+};
+
+static int __init unidisplay_ts_init(void)
+{
+ return i2c_add_driver(&unidisplay_ts_i2c_driver);
+}
+module_init(unidisplay_ts_init);
+
+static void __exit unidisplay_ts_exit(void)
+{
+ i2c_del_driver(&unidisplay_ts_i2c_driver);
+}
+module_exit(unidisplay_ts_exit);
+
+MODULE_AUTHOR("JHKIM");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("unidisplay Touch-screen Driver");
+