diff options
Diffstat (limited to 'recipes/linux/linux-2.6.28/collie/0012-move-ucb1200-ts-driver.patch')
-rw-r--r-- | recipes/linux/linux-2.6.28/collie/0012-move-ucb1200-ts-driver.patch | 981 |
1 files changed, 0 insertions, 981 deletions
diff --git a/recipes/linux/linux-2.6.28/collie/0012-move-ucb1200-ts-driver.patch b/recipes/linux/linux-2.6.28/collie/0012-move-ucb1200-ts-driver.patch deleted file mode 100644 index c1aafef5e2..0000000000 --- a/recipes/linux/linux-2.6.28/collie/0012-move-ucb1200-ts-driver.patch +++ /dev/null @@ -1,981 +0,0 @@ -From 9e0d71c4a6247d88d3b772f6b05bcaa39711a937 Mon Sep 17 00:00:00 2001 -From: Thomas Kunze <thommycheck@gmx.de> -Date: Tue, 10 Feb 2009 19:31:25 +0100 -Subject: [PATCH 12/23] move ucb1200-ts driver - -Move the touchscreen driver to drivers/input/touchscreen -where touchscreen drivers belong. - -Conflicts: - - drivers/input/touchscreen/Makefile - drivers/mfd/Kconfig - drivers/mfd/Makefile - -Conflicts: - - drivers/mfd/Kconfig - drivers/mfd/Makefile ---- - drivers/input/touchscreen/Kconfig | 7 + - drivers/input/touchscreen/Makefile | 1 + - drivers/input/touchscreen/ucb1x00-ts.c | 438 ++++++++++++++++++++++++++++++++ - drivers/mfd/Kconfig | 3 - - drivers/mfd/Makefile | 3 +- - drivers/mfd/ucb1x00-ts.c | 438 -------------------------------- - 6 files changed, 447 insertions(+), 443 deletions(-) - create mode 100644 drivers/input/touchscreen/ucb1x00-ts.c - delete mode 100644 drivers/mfd/ucb1x00-ts.c - -diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig -index 3d1ab8f..3ac8cd6 100644 ---- a/drivers/input/touchscreen/Kconfig -+++ b/drivers/input/touchscreen/Kconfig -@@ -221,6 +221,13 @@ config TOUCHSCREEN_ATMEL_TSADCC - To compile this driver as a module, choose M here: the - module will be called atmel_tsadcc. - -+config TOUCHSCREEN_UCB1200_TS -+ tristate "Philips UCB1200 touchscreen" -+ depends on MCP_UCB1200 -+ help -+ This enabled support for the Pilips UCB1200 touchscreen interface -+ and compatible. -+ - config TOUCHSCREEN_UCB1400 - tristate "Philips UCB1400 touchscreen" - depends on AC97_BUS -diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile -index 15cf290..77ba930 100644 ---- a/drivers/input/touchscreen/Makefile -+++ b/drivers/input/touchscreen/Makefile -@@ -25,6 +25,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o - obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o - obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o - obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o -+obj-$(CONFIG_TOUCHSCREEN_UCB1200_TS) += ucb1x00-ts.o - obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o - obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o - wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o -diff --git a/drivers/input/touchscreen/ucb1x00-ts.c b/drivers/input/touchscreen/ucb1x00-ts.c -new file mode 100644 -index 0000000..b5feae9 ---- /dev/null -+++ b/drivers/input/touchscreen/ucb1x00-ts.c -@@ -0,0 +1,438 @@ -+/* -+ * Touchscreen driver for UCB1x00-based touchscreens -+ * -+ * Copyright (C) 2001 Russell King, All Rights Reserved. -+ * Copyright (C) 2005 Pavel Machek -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * 21-Jan-2002 <jco@ict.es> : -+ * -+ * Added support for synchronous A/D mode. This mode is useful to -+ * avoid noise induced in the touchpanel by the LCD, provided that -+ * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin. -+ * It is important to note that the signal connected to the ADCSYNC -+ * pin should provide pulses even when the LCD is blanked, otherwise -+ * a pen touch needed to unblank the LCD will never be read. -+ */ -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/init.h> -+#include <linux/smp.h> -+#include <linux/sched.h> -+#include <linux/completion.h> -+#include <linux/delay.h> -+#include <linux/string.h> -+#include <linux/input.h> -+#include <linux/device.h> -+#include <linux/freezer.h> -+#include <linux/slab.h> -+#include <linux/kthread.h> -+#include <linux/mfd/ucb1x00.h> -+ -+#include <asm/dma.h> -+#include <mach/collie.h> -+#include <asm/mach-types.h> -+ -+ -+ -+struct ucb1x00_ts { -+ struct input_dev *idev; -+ struct ucb1x00 *ucb; -+ -+ wait_queue_head_t irq_wait; -+ struct task_struct *rtask; -+ u16 x_res; -+ u16 y_res; -+ -+ unsigned int restart:1; -+ unsigned int adcsync:1; -+}; -+ -+static int adcsync; -+ -+static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y) -+{ -+ struct input_dev *idev = ts->idev; -+ -+ input_report_abs(idev, ABS_X, x); -+ input_report_abs(idev, ABS_Y, y); -+ input_report_abs(idev, ABS_PRESSURE, pressure); -+ input_sync(idev); -+} -+ -+static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) -+{ -+ struct input_dev *idev = ts->idev; -+ -+ input_report_abs(idev, ABS_PRESSURE, 0); -+ input_sync(idev); -+} -+ -+/* -+ * Switch to interrupt mode. -+ */ -+static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -+ UCB_TS_CR_MODE_INT); -+} -+ -+/* -+ * Switch to pressure mode, and read pressure. We don't need to wait -+ * here, since both plates are being driven. -+ */ -+static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts) -+{ -+ if (machine_is_collie()) { -+ ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW | -+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -+ -+ udelay(55); -+ -+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_AD2, ts->adcsync); -+ } else { -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ -+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); -+ } -+} -+ -+/* -+ * Switch to X position mode and measure Y plate. We switch the plate -+ * configuration in pressure mode, then switch to position mode. This -+ * gives a faster response time. Even so, we need to wait about 55us -+ * for things to stabilise. -+ */ -+static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts) -+{ -+ if (machine_is_collie()) -+ ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); -+ else { -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ } -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -+ -+ udelay(55); -+ -+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); -+} -+ -+/* -+ * Switch to Y position mode and measure X plate. We switch the plate -+ * configuration in pressure mode, then switch to position mode. This -+ * gives a faster response time. Even so, we need to wait about 55us -+ * for things to stabilise. -+ */ -+static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts) -+{ -+ if (machine_is_collie()) -+ ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); -+ else { -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ } -+ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -+ -+ udelay(55); -+ -+ return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); -+} -+ -+/* -+ * Switch to X plate resistance mode. Set MX to ground, PX to -+ * supply. Measure current. -+ */ -+static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); -+} -+ -+/* -+ * Switch to Y plate resistance mode. Set MY to ground, PY to -+ * supply. Measure current. -+ */ -+static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts) -+{ -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -+ UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -+ UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -+ return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); -+} -+ -+static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts) -+{ -+ unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); -+ -+ if (machine_is_collie()) -+ return (!(val & (UCB_TS_CR_TSPX_LOW))); -+ else -+ return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)); -+} -+ -+/* -+ * This is a RT kernel thread that handles the ADC accesses -+ * (mainly so we can use semaphores in the UCB1200 core code -+ * to serialise accesses to the ADC). -+ */ -+static int ucb1x00_thread(void *_ts) -+{ -+ struct ucb1x00_ts *ts = _ts; -+ DECLARE_WAITQUEUE(wait, current); -+ int valid = 0; -+ -+ set_freezable(); -+ add_wait_queue(&ts->irq_wait, &wait); -+ while (!kthread_should_stop()) { -+ unsigned int x, y, p; -+ signed long timeout; -+ -+ ts->restart = 0; -+ -+ ucb1x00_adc_enable(ts->ucb); -+ -+ x = ucb1x00_ts_read_xpos(ts); -+ y = ucb1x00_ts_read_ypos(ts); -+ p = ucb1x00_ts_read_pressure(ts); -+ -+ /* -+ * Switch back to interrupt mode. -+ */ -+ ucb1x00_ts_mode_int(ts); -+ ucb1x00_adc_disable(ts->ucb); -+ -+ msleep(10); -+ -+ ucb1x00_enable(ts->ucb); -+ -+ -+ if (ucb1x00_ts_pen_down(ts)) { -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); -+ ucb1x00_disable(ts->ucb); -+ -+ /* -+ * If we spat out a valid sample set last time, -+ * spit out a "pen off" sample here. -+ */ -+ if (valid) { -+ ucb1x00_ts_event_release(ts); -+ valid = 0; -+ } -+ -+ timeout = MAX_SCHEDULE_TIMEOUT; -+ } else { -+ ucb1x00_disable(ts->ucb); -+ -+ /* -+ * Filtering is policy. Policy belongs in user -+ * space. We therefore leave it to user space -+ * to do any filtering they please. -+ */ -+ if (!ts->restart) { -+ ucb1x00_ts_evt_add(ts, p, x, y); -+ valid = 1; -+ } -+ -+ set_current_state(TASK_INTERRUPTIBLE); -+ timeout = HZ / 100; -+ } -+ -+ try_to_freeze(); -+ -+ schedule_timeout(timeout); -+ } -+ -+ remove_wait_queue(&ts->irq_wait, &wait); -+ -+ ts->rtask = NULL; -+ return 0; -+} -+ -+/* -+ * We only detect touch screen _touches_ with this interrupt -+ * handler, and even then we just schedule our task. -+ */ -+static void ucb1x00_ts_irq(int idx, void *id) -+{ -+ struct ucb1x00_ts *ts = id; -+ -+ ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); -+ wake_up(&ts->irq_wait); -+} -+ -+static int ucb1x00_ts_open(struct input_dev *idev) -+{ -+ struct ucb1x00_ts *ts = input_get_drvdata(idev); -+ int ret = 0; -+ -+ BUG_ON(ts->rtask); -+ -+ init_waitqueue_head(&ts->irq_wait); -+ ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); -+ if (ret < 0) -+ goto out; -+ -+ /* -+ * If we do this at all, we should allow the user to -+ * measure and read the X and Y resistance at any time. -+ */ -+ ucb1x00_adc_enable(ts->ucb); -+ ts->x_res = ucb1x00_ts_read_xres(ts); -+ ts->y_res = ucb1x00_ts_read_yres(ts); -+ ucb1x00_adc_disable(ts->ucb); -+ -+ ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd"); -+ if (!IS_ERR(ts->rtask)) { -+ ret = 0; -+ } else { -+ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); -+ ts->rtask = NULL; -+ ret = -EFAULT; -+ } -+ -+ out: -+ return ret; -+} -+ -+/* -+ * Release touchscreen resources. Disable IRQs. -+ */ -+static void ucb1x00_ts_close(struct input_dev *idev) -+{ -+ struct ucb1x00_ts *ts = input_get_drvdata(idev); -+ -+ if (ts->rtask) -+ kthread_stop(ts->rtask); -+ -+ ucb1x00_enable(ts->ucb); -+ ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); -+ ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); -+ ucb1x00_disable(ts->ucb); -+} -+ -+#ifdef CONFIG_PM -+static int ucb1x00_ts_resume(struct ucb1x00_dev *dev) -+{ -+ struct ucb1x00_ts *ts = dev->priv; -+ -+ if (ts->rtask != NULL) { -+ /* -+ * Restart the TS thread to ensure the -+ * TS interrupt mode is set up again -+ * after sleep. -+ */ -+ ts->restart = 1; -+ wake_up(&ts->irq_wait); -+ } -+ return 0; -+} -+#else -+#define ucb1x00_ts_resume NULL -+#endif -+ -+ -+/* -+ * Initialisation. -+ */ -+static int ucb1x00_ts_add(struct ucb1x00_dev *dev) -+{ -+ struct ucb1x00_ts *ts; -+ struct input_dev *idev; -+ int err; -+ -+ ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); -+ idev = input_allocate_device(); -+ if (!ts || !idev) { -+ err = -ENOMEM; -+ goto fail; -+ } -+ -+ ts->ucb = dev->ucb; -+ ts->idev = idev; -+ ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; -+ -+ idev->name = "Touchscreen panel"; -+ idev->id.product = ts->ucb->id; -+ idev->open = ucb1x00_ts_open; -+ idev->close = ucb1x00_ts_close; -+ -+ __set_bit(EV_ABS, idev->evbit); -+ __set_bit(ABS_X, idev->absbit); -+ __set_bit(ABS_Y, idev->absbit); -+ __set_bit(ABS_PRESSURE, idev->absbit); -+ -+ input_set_drvdata(idev, ts); -+ -+ err = input_register_device(idev); -+ if (err) -+ goto fail; -+ -+ dev->priv = ts; -+ -+ return 0; -+ -+ fail: -+ input_free_device(idev); -+ kfree(ts); -+ return err; -+} -+ -+static void ucb1x00_ts_remove(struct ucb1x00_dev *dev) -+{ -+ struct ucb1x00_ts *ts = dev->priv; -+ -+ input_unregister_device(ts->idev); -+ kfree(ts); -+} -+ -+static struct ucb1x00_driver ucb1x00_ts_driver = { -+ .add = ucb1x00_ts_add, -+ .remove = ucb1x00_ts_remove, -+ .resume = ucb1x00_ts_resume, -+}; -+ -+static int __init ucb1x00_ts_init(void) -+{ -+ return ucb1x00_register_driver(&ucb1x00_ts_driver); -+} -+ -+static void __exit ucb1x00_ts_exit(void) -+{ -+ ucb1x00_unregister_driver(&ucb1x00_ts_driver); -+} -+ -+module_param(adcsync, int, 0444); -+module_init(ucb1x00_ts_init); -+module_exit(ucb1x00_ts_exit); -+ -+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); -+MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 2572773..bbc137d 100644 ---- a/drivers/mfd/Kconfig -+++ b/drivers/mfd/Kconfig -@@ -172,8 +172,5 @@ config MCP_UCB1200 - tristate "Support for UCB1200 / UCB1300" - depends on MCP - --config MCP_UCB1200_TS -- tristate "Touchscreen interface support" -- depends on MCP_UCB1200 && INPUT - - endmenu -diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index 9a5ad8a..4981aff 100644 ---- a/drivers/mfd/Makefile -+++ b/drivers/mfd/Makefile -@@ -24,11 +24,10 @@ obj-$(CONFIG_MFD_CORE) += mfd-core.o - obj-$(CONFIG_MCP) += mcp-core.o - obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o - obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o --obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o - - ifeq ($(CONFIG_SA1100_ASSABET),y) - obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o - endif - obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o - --obj-$(CONFIG_PMIC_DA903X) += da903x.o -\ No newline at end of file -+obj-$(CONFIG_PMIC_DA903X) += da903x.o -diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c -deleted file mode 100644 -index b5feae9..0000000 ---- a/drivers/mfd/ucb1x00-ts.c -+++ /dev/null -@@ -1,438 +0,0 @@ --/* -- * Touchscreen driver for UCB1x00-based touchscreens -- * -- * Copyright (C) 2001 Russell King, All Rights Reserved. -- * Copyright (C) 2005 Pavel Machek -- * -- * This program is free software; you can redistribute it and/or modify -- * it under the terms of the GNU General Public License version 2 as -- * published by the Free Software Foundation. -- * -- * 21-Jan-2002 <jco@ict.es> : -- * -- * Added support for synchronous A/D mode. This mode is useful to -- * avoid noise induced in the touchpanel by the LCD, provided that -- * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin. -- * It is important to note that the signal connected to the ADCSYNC -- * pin should provide pulses even when the LCD is blanked, otherwise -- * a pen touch needed to unblank the LCD will never be read. -- */ --#include <linux/module.h> --#include <linux/moduleparam.h> --#include <linux/init.h> --#include <linux/smp.h> --#include <linux/sched.h> --#include <linux/completion.h> --#include <linux/delay.h> --#include <linux/string.h> --#include <linux/input.h> --#include <linux/device.h> --#include <linux/freezer.h> --#include <linux/slab.h> --#include <linux/kthread.h> --#include <linux/mfd/ucb1x00.h> -- --#include <asm/dma.h> --#include <mach/collie.h> --#include <asm/mach-types.h> -- -- -- --struct ucb1x00_ts { -- struct input_dev *idev; -- struct ucb1x00 *ucb; -- -- wait_queue_head_t irq_wait; -- struct task_struct *rtask; -- u16 x_res; -- u16 y_res; -- -- unsigned int restart:1; -- unsigned int adcsync:1; --}; -- --static int adcsync; -- --static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y) --{ -- struct input_dev *idev = ts->idev; -- -- input_report_abs(idev, ABS_X, x); -- input_report_abs(idev, ABS_Y, y); -- input_report_abs(idev, ABS_PRESSURE, pressure); -- input_sync(idev); --} -- --static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts) --{ -- struct input_dev *idev = ts->idev; -- -- input_report_abs(idev, ABS_PRESSURE, 0); -- input_sync(idev); --} -- --/* -- * Switch to interrupt mode. -- */ --static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts) --{ -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | -- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -- UCB_TS_CR_MODE_INT); --} -- --/* -- * Switch to pressure mode, and read pressure. We don't need to wait -- * here, since both plates are being driven. -- */ --static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts) --{ -- if (machine_is_collie()) { -- ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0); -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW | -- UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -- -- udelay(55); -- -- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_AD2, ts->adcsync); -- } else { -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | -- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | -- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -- -- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); -- } --} -- --/* -- * Switch to X position mode and measure Y plate. We switch the plate -- * configuration in pressure mode, then switch to position mode. This -- * gives a faster response time. Even so, we need to wait about 55us -- * for things to stabilise. -- */ --static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts) --{ -- if (machine_is_collie()) -- ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); -- else { -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -- } -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -- UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -- -- udelay(55); -- -- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync); --} -- --/* -- * Switch to Y position mode and measure X plate. We switch the plate -- * configuration in pressure mode, then switch to position mode. This -- * gives a faster response time. Even so, we need to wait about 55us -- * for things to stabilise. -- */ --static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts) --{ -- if (machine_is_collie()) -- ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK); -- else { -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -- } -- -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -- UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); -- -- udelay(55); -- -- return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync); --} -- --/* -- * Switch to X plate resistance mode. Set MX to ground, PX to -- * supply. Measure current. -- */ --static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts) --{ -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | -- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -- return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); --} -- --/* -- * Switch to Y plate resistance mode. Set MY to ground, PY to -- * supply. Measure current. -- */ --static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts) --{ -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, -- UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | -- UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); -- return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync); --} -- --static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts) --{ -- unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR); -- -- if (machine_is_collie()) -- return (!(val & (UCB_TS_CR_TSPX_LOW))); -- else -- return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)); --} -- --/* -- * This is a RT kernel thread that handles the ADC accesses -- * (mainly so we can use semaphores in the UCB1200 core code -- * to serialise accesses to the ADC). -- */ --static int ucb1x00_thread(void *_ts) --{ -- struct ucb1x00_ts *ts = _ts; -- DECLARE_WAITQUEUE(wait, current); -- int valid = 0; -- -- set_freezable(); -- add_wait_queue(&ts->irq_wait, &wait); -- while (!kthread_should_stop()) { -- unsigned int x, y, p; -- signed long timeout; -- -- ts->restart = 0; -- -- ucb1x00_adc_enable(ts->ucb); -- -- x = ucb1x00_ts_read_xpos(ts); -- y = ucb1x00_ts_read_ypos(ts); -- p = ucb1x00_ts_read_pressure(ts); -- -- /* -- * Switch back to interrupt mode. -- */ -- ucb1x00_ts_mode_int(ts); -- ucb1x00_adc_disable(ts->ucb); -- -- msleep(10); -- -- ucb1x00_enable(ts->ucb); -- -- -- if (ucb1x00_ts_pen_down(ts)) { -- set_current_state(TASK_INTERRUPTIBLE); -- -- ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING); -- ucb1x00_disable(ts->ucb); -- -- /* -- * If we spat out a valid sample set last time, -- * spit out a "pen off" sample here. -- */ -- if (valid) { -- ucb1x00_ts_event_release(ts); -- valid = 0; -- } -- -- timeout = MAX_SCHEDULE_TIMEOUT; -- } else { -- ucb1x00_disable(ts->ucb); -- -- /* -- * Filtering is policy. Policy belongs in user -- * space. We therefore leave it to user space -- * to do any filtering they please. -- */ -- if (!ts->restart) { -- ucb1x00_ts_evt_add(ts, p, x, y); -- valid = 1; -- } -- -- set_current_state(TASK_INTERRUPTIBLE); -- timeout = HZ / 100; -- } -- -- try_to_freeze(); -- -- schedule_timeout(timeout); -- } -- -- remove_wait_queue(&ts->irq_wait, &wait); -- -- ts->rtask = NULL; -- return 0; --} -- --/* -- * We only detect touch screen _touches_ with this interrupt -- * handler, and even then we just schedule our task. -- */ --static void ucb1x00_ts_irq(int idx, void *id) --{ -- struct ucb1x00_ts *ts = id; -- -- ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING); -- wake_up(&ts->irq_wait); --} -- --static int ucb1x00_ts_open(struct input_dev *idev) --{ -- struct ucb1x00_ts *ts = input_get_drvdata(idev); -- int ret = 0; -- -- BUG_ON(ts->rtask); -- -- init_waitqueue_head(&ts->irq_wait); -- ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts); -- if (ret < 0) -- goto out; -- -- /* -- * If we do this at all, we should allow the user to -- * measure and read the X and Y resistance at any time. -- */ -- ucb1x00_adc_enable(ts->ucb); -- ts->x_res = ucb1x00_ts_read_xres(ts); -- ts->y_res = ucb1x00_ts_read_yres(ts); -- ucb1x00_adc_disable(ts->ucb); -- -- ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd"); -- if (!IS_ERR(ts->rtask)) { -- ret = 0; -- } else { -- ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); -- ts->rtask = NULL; -- ret = -EFAULT; -- } -- -- out: -- return ret; --} -- --/* -- * Release touchscreen resources. Disable IRQs. -- */ --static void ucb1x00_ts_close(struct input_dev *idev) --{ -- struct ucb1x00_ts *ts = input_get_drvdata(idev); -- -- if (ts->rtask) -- kthread_stop(ts->rtask); -- -- ucb1x00_enable(ts->ucb); -- ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts); -- ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0); -- ucb1x00_disable(ts->ucb); --} -- --#ifdef CONFIG_PM --static int ucb1x00_ts_resume(struct ucb1x00_dev *dev) --{ -- struct ucb1x00_ts *ts = dev->priv; -- -- if (ts->rtask != NULL) { -- /* -- * Restart the TS thread to ensure the -- * TS interrupt mode is set up again -- * after sleep. -- */ -- ts->restart = 1; -- wake_up(&ts->irq_wait); -- } -- return 0; --} --#else --#define ucb1x00_ts_resume NULL --#endif -- -- --/* -- * Initialisation. -- */ --static int ucb1x00_ts_add(struct ucb1x00_dev *dev) --{ -- struct ucb1x00_ts *ts; -- struct input_dev *idev; -- int err; -- -- ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL); -- idev = input_allocate_device(); -- if (!ts || !idev) { -- err = -ENOMEM; -- goto fail; -- } -- -- ts->ucb = dev->ucb; -- ts->idev = idev; -- ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC; -- -- idev->name = "Touchscreen panel"; -- idev->id.product = ts->ucb->id; -- idev->open = ucb1x00_ts_open; -- idev->close = ucb1x00_ts_close; -- -- __set_bit(EV_ABS, idev->evbit); -- __set_bit(ABS_X, idev->absbit); -- __set_bit(ABS_Y, idev->absbit); -- __set_bit(ABS_PRESSURE, idev->absbit); -- -- input_set_drvdata(idev, ts); -- -- err = input_register_device(idev); -- if (err) -- goto fail; -- -- dev->priv = ts; -- -- return 0; -- -- fail: -- input_free_device(idev); -- kfree(ts); -- return err; --} -- --static void ucb1x00_ts_remove(struct ucb1x00_dev *dev) --{ -- struct ucb1x00_ts *ts = dev->priv; -- -- input_unregister_device(ts->idev); -- kfree(ts); --} -- --static struct ucb1x00_driver ucb1x00_ts_driver = { -- .add = ucb1x00_ts_add, -- .remove = ucb1x00_ts_remove, -- .resume = ucb1x00_ts_resume, --}; -- --static int __init ucb1x00_ts_init(void) --{ -- return ucb1x00_register_driver(&ucb1x00_ts_driver); --} -- --static void __exit ucb1x00_ts_exit(void) --{ -- ucb1x00_unregister_driver(&ucb1x00_ts_driver); --} -- --module_param(adcsync, int, 0444); --module_init(ucb1x00_ts_init); --module_exit(ucb1x00_ts_exit); -- --MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>"); --MODULE_DESCRIPTION("UCB1x00 touchscreen driver"); --MODULE_LICENSE("GPL"); --- -1.5.6.5 - |