diff options
Diffstat (limited to 'packages/linux/linux-ezx-2.6.21/pcap-ts.patch')
-rw-r--r-- | packages/linux/linux-ezx-2.6.21/pcap-ts.patch | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/packages/linux/linux-ezx-2.6.21/pcap-ts.patch b/packages/linux/linux-ezx-2.6.21/pcap-ts.patch new file mode 100644 index 0000000000..a07ec1abe9 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.21/pcap-ts.patch @@ -0,0 +1,450 @@ +Index: linux-2.6.21/drivers/input/touchscreen/Kconfig +=================================================================== +--- linux-2.6.21.orig/drivers/input/touchscreen/Kconfig 2007-05-03 17:39:18.000000000 -0300 ++++ linux-2.6.21/drivers/input/touchscreen/Kconfig 2007-05-03 17:44:12.000000000 -0300 +@@ -164,4 +164,13 @@ + To compile this driver as a module, choose M here: the + module will be called ucb1400_ts. + ++config TOUCHSCREEN_PCAP ++ tristate "Motorola PCAP touchscreen" ++ depends on PXA_EZX ++ help ++ Say Y here if you have a Motorola EZX telephone and ++ want to support the built-in touchscreen. ++ ++ If unsure, say N. ++ + endif +Index: linux-2.6.21/drivers/input/touchscreen/pcap_ts.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/drivers/input/touchscreen/pcap_ts.c 2007-05-04 04:17:22.000000000 -0300 +@@ -0,0 +1,372 @@ ++/* ++ * pcap_ts.c - Touchscreen driver for Motorola PCAP2 based touchscreen as found ++ * in the EZX phone platform. ++ * ++ * Copyright (C) 2006 Harald Welte <laforge@openezx.org> ++ * ++ * Based on information found in the original Motorola 2.4.x ezx-ts.c driver. ++ * ++ * 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. ++ * ++ * May 3, 2007 - Daniel Ribeiro <drwyrm@gmail.com> ++ * Major cleanup ++ * PM Callbacks ++ * ++ * TODO: ++ * split this in a hardirq handler and a tasklet/bh ++ */ ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/fs.h> ++#include <linux/string.h> ++#include <linux/pm.h> ++#include <linux/timer.h> ++//#include <linux/config.h> ++#include <linux/interrupt.h> ++#include <linux/platform_device.h> ++#include <linux/input.h> ++ ++#include <asm/arch/hardware.h> ++#include <asm/arch/pxa-regs.h> ++#include <asm/arch/ezx-pcap.h> ++ ++#if 0 ++#define DEBUGP(x, args ...) printk(x, ## args) ++#else ++#define DEBUGP(x, args ...) ++#endif ++ ++#define PRESSURE 1 ++#define COORDINATE 2 ++#define STANDBY 3 ++ ++struct pcap_ts { ++ int irq_xy; ++ int irq_touch; ++ struct input_dev *input; ++ struct timer_list timer; ++ ++ u_int16_t x, y; ++ u_int16_t pressure; ++ ++ u_int8_t read_state; ++}; ++ ++#define X_AXIS_MIN 0 ++#define X_AXIS_MAX 1023 ++ ++#define Y_AXIS_MAX X_AXIS_MAX ++#define Y_AXIS_MIN X_AXIS_MIN ++ ++#define PRESSURE_MAX X_AXIS_MAX ++#define PRESSURE_MIN X_AXIS_MIN ++ ++/* if we try to read faster, pressure reading becomes unreliable */ ++#define SAMPLE_INTERVAL (HZ/50) ++ ++ ++static void pcap_ts_mode(u_int32_t mode) ++{ ++ u_int32_t tmp; ++ ++ ezx_pcap_read(SSP_PCAP_ADJ_ADC1_REGISTER, &tmp); ++ tmp &= ~SSP_PCAP_TOUCH_PANEL_POSITION_DETECT_MODE_MASK; ++ tmp |= mode; ++ ezx_pcap_write(SSP_PCAP_ADJ_ADC1_REGISTER, tmp); ++} ++ ++/* issue a XY read command to the ADC of PCAP2. Well get an ADCDONE2 interrupt ++ * once the result of the conversion is available */ ++static void pcap_ts_start_xy_read(struct pcap_ts *pcap_ts) ++{ ++ u_int32_t tmp; ++ ++ ezx_pcap_read(SSP_PCAP_ADJ_ADC1_REGISTER, &tmp); ++ tmp &= SSP_PCAP_ADC_START_VALUE_SET_MASK; ++ tmp |= SSP_PCAP_ADC_START_VALUE; ++ ezx_pcap_write(SSP_PCAP_ADJ_ADC1_REGISTER, tmp); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ADC2_ASC, 1); ++} ++ ++/* read the XY result from the ADC of PCAP2 */ ++static void pcap_ts_get_xy_value(struct pcap_ts *pcap_ts) ++{ ++ u_int32_t tmp; ++ ++ ezx_pcap_read(SSP_PCAP_ADJ_ADC2_REGISTER, &tmp); ++ ++ if (pcap_ts->read_state == COORDINATE && !(tmp & 0x00400000)) { ++ pcap_ts->x = (tmp & SSP_PCAP_ADD1_VALUE_MASK); ++ pcap_ts->y = (tmp & SSP_PCAP_ADD2_VALUE_MASK) ++ >>SSP_PCAP_ADD2_VALUE_SHIFT; ++ } else { ++ pcap_ts->pressure = (tmp & SSP_PCAP_ADD2_VALUE_MASK) ++ >>SSP_PCAP_ADD2_VALUE_SHIFT; ++ } ++ ++} ++ ++/* PCAP2 interrupts us when ADC conversion result is available */ ++static irqreturn_t pcap_ts_irq_xy(int irq, void *dev_id) ++{ ++ struct pcap_ts *pcap_ts = dev_id; ++ ++ pcap_ts_get_xy_value(pcap_ts); ++ DEBUGP(KERN_DEBUG "%s X=%4d, Y=%4d Z=%4d ", ++ pcap_ts->read_state == COORDINATE ? "COORD" : "PRESS", ++ pcap_ts->x, pcap_ts->y, pcap_ts->pressure); ++ ++ switch (pcap_ts->read_state) { ++ case PRESSURE: ++ if (pcap_ts->pressure >= PRESSURE_MAX || ++ pcap_ts->pressure <= PRESSURE_MIN ) { ++ /* pen has been released (or cant read pressure - WM)*/ ++ DEBUGP("UP\n"); ++ /* do nothing */ ++ } else { ++ /* pen has been touched down */ ++ DEBUGP("DOWN\n"); ++ input_report_key(pcap_ts->input, BTN_TOUCH, 1); ++ input_report_abs(pcap_ts->input, ABS_PRESSURE, pcap_ts->pressure); ++ } ++ /* switch state machine into coordinate read mode */ ++ pcap_ts->read_state = COORDINATE; ++ pcap_ts_mode(PCAP_TS_POSITION_XY_MEASUREMENT); ++ pcap_ts_start_xy_read(pcap_ts); ++ break; ++ case COORDINATE: ++ if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX || ++ pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) { ++ /* pen has been released */ ++ DEBUGP("UP END\n"); ++ ++ input_report_key(pcap_ts->input, BTN_TOUCH, 0); ++ input_report_abs(pcap_ts->input, ABS_PRESSURE, 0); ++ ++ /* no need for timer, we'll get interrupted with ++ * next touch down event */ ++ del_timer(&pcap_ts->timer); ++ ++ /* ask PCAP2 to interrupt us if touch event happens ++ * again */ ++ pcap_ts->read_state = STANDBY; ++ pcap_ts_mode(PCAP_TS_STANDBY_MODE); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ } else { ++ DEBUGP("DOWN\n"); ++ input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x); ++ input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y); ++ ++ /* switch back to pressure read mode */ ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_mode(PCAP_TS_PRESSURE_MEASUREMENT); ++ mod_timer(&pcap_ts->timer, jiffies + SAMPLE_INTERVAL); ++ } ++ input_sync(pcap_ts->input); ++ break; ++ default: ++ DEBUGP("ERROR\n"); ++ break; ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* PCAP2 interrupts us if the pen touches down (interrupts also on pen up - WM)*/ ++static irqreturn_t pcap_ts_irq_touch(int irq, void *dev_id) ++{ ++ struct pcap_ts *pcap_ts = dev_id; ++ ++ /* mask Touchscreen interrupt bit, prevents further touch events ++ * from being reported to us until we're finished with reading ++ * both pressure and x/y from ADC */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 1); ++ ++ DEBUGP("touched!!\n"); ++ pcap_ts_mode(PCAP_TS_PRESSURE_MEASUREMENT); ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_start_xy_read(pcap_ts); ++ ++ return IRQ_HANDLED; ++} ++ ++static void pcap_ts_timer_fn(unsigned long data) ++{ ++ struct pcap_ts *pcap_ts = (struct pcap_ts *) data; ++ ++ pcap_ts_start_xy_read(pcap_ts); ++} ++ ++static int __init ezxts_probe(struct platform_device *pdev) ++{ ++ int ret; ++ u_int32_t tmp; ++ struct pcap_ts *pcap_ts; ++ struct input_dev *input_dev; ++ int err = -ENOMEM; ++ ++ pcap_ts = kzalloc(sizeof(*pcap_ts), GFP_KERNEL); ++ input_dev = input_allocate_device(); ++ if (!pcap_ts || !input_dev) ++ goto fail; ++ ++ pcap_ts->irq_xy = platform_get_irq(pdev, 0); ++ if (pcap_ts->irq_xy < 0) { ++ err = pcap_ts->irq_xy; ++ goto fail; ++ } ++ ++ pcap_ts->irq_touch = platform_get_irq(pdev, 1); ++ if (pcap_ts->irq_touch < 0) { ++ err = pcap_ts->irq_touch; ++ goto fail; ++ } ++ ++ // Some initialization before done in ssp_pcap_open() ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC1_TS_REFENB, 0); ++ // ack interrupts ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ISR_ADCDONE2I, 1); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ISR_TSI, 1); ++ // unmask interrupts ++ // ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_MSR_ADCDONE2M, 0); ++ // set adc bits? FIXME I dont think its necessary - WM ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC2_ADINC1, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC2_ADINC2, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC1_ATO0, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC1_ATO1, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC1_ATO2, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC1_ATO3, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC1_ATOX, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC1_MTR1, 0); ++ ezx_pcap_bit_set( SSP_PCAP_ADJ_BIT_ADC1_MTR2, 0); ++ ++ ret = ezx_pcap_read(SSP_PCAP_ADJ_ADC1_REGISTER, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ tmp &= (~SSP_PCAP_TOUCH_PANEL_POSITION_DETECT_MODE_MASK); ++ tmp |= PCAP_TS_STANDBY_MODE; ++ ++ ret = ezx_pcap_write(SSP_PCAP_ADJ_ADC1_REGISTER, tmp); ++ if (ret < 0) ++ return ret; ++ ++ err = request_irq(pcap_ts->irq_xy, pcap_ts_irq_xy, SA_INTERRUPT, ++ "PCAP Touchscreen XY", pcap_ts); ++ if (err < 0) { ++ printk(KERN_ERR "pcap_ts: can't grab xy irq %d: %d\n", ++ pcap_ts->irq_xy, err); ++ goto fail; ++ } ++ ++ err = request_irq(pcap_ts->irq_touch, pcap_ts_irq_touch, SA_INTERRUPT, ++ "PCAP Touchscreen Touch", pcap_ts); ++ if (err < 0) { ++ printk(KERN_ERR "pcap_ts: can't grab touch irq %d: %d\n", ++ pcap_ts->irq_touch, err); ++ goto fail_xy; ++ } ++ ++ pcap_ts->input = input_dev; ++ init_timer(&pcap_ts->timer); ++ pcap_ts->timer.data = (unsigned long) pcap_ts; ++ pcap_ts->timer.function = &pcap_ts_timer_fn; ++ ++ platform_set_drvdata(pdev, pcap_ts); ++ ++ pcap_ts->read_state = STANDBY; ++ pcap_ts_mode(PCAP_TS_STANDBY_MODE); ++ ++ /* enable pressure interrupt */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ ++ input_dev->name = "EZX PCAP2 Touchscreen"; ++ input_dev->phys = "ezxts/input0"; ++ input_dev->id.bustype = BUS_HOST; ++ input_dev->id.vendor = 0x0001; ++ input_dev->id.product = 0x0002; ++ input_dev->id.version = 0x0100; ++ input_dev->cdev.dev = &pdev->dev; ++ input_dev->private = pcap_ts; ++ ++ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); ++ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); ++ input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0); ++ input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0); ++ input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN, ++ PRESSURE_MAX, 0, 0); ++ ++ input_register_device(pcap_ts->input); ++ ++ return 0; ++ ++fail_xy: ++ free_irq(pcap_ts->irq_xy, pcap_ts); ++fail: ++ input_free_device(input_dev); ++ kfree(pcap_ts); ++ ++ return err; ++} ++ ++static int ezxts_remove(struct platform_device *pdev) ++{ ++ struct pcap_ts *pcap_ts = platform_get_drvdata(pdev); ++ ++ del_timer_sync(&pcap_ts->timer); ++ ++ free_irq(pcap_ts->irq_touch, pcap_ts); ++ free_irq(pcap_ts->irq_xy, pcap_ts); ++ ++ input_unregister_device(pcap_ts->input); ++ kfree(pcap_ts); ++ ++ return 0; ++} ++ ++static int ezxts_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ADC1_TS_REF_LOWPWR, 1); ++ return 0; ++} ++ ++static int ezxts_resume(struct platform_device *dev) ++{ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ADC1_TS_REF_LOWPWR, 0); ++ /* just in case we suspend with TSI masked. */ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ return 0; ++} ++ ++ ++static struct platform_driver ezxts_driver = { ++ .probe = ezxts_probe, ++ .remove = ezxts_remove, ++ .suspend = ezxts_suspend, ++ .resume = ezxts_resume, ++ .driver = { ++ .name = "pcap-ts", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++static int __init ezxts_init(void) ++{ ++ return platform_driver_register(&ezxts_driver); ++} ++ ++static void __exit ezxts_exit(void) ++{ ++ platform_driver_unregister(&ezxts_driver); ++} ++ ++module_init(ezxts_init); ++module_exit(ezxts_exit); ++ ++MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver"); ++MODULE_AUTHOR("Harald Welte <laforge@openezx.org>"); ++MODULE_LICENSE("GPL"); +Index: linux-2.6.21/arch/arm/mach-pxa/ezx.c +=================================================================== +--- linux-2.6.21.orig/arch/arm/mach-pxa/ezx.c 2007-05-03 19:09:25.000000000 -0300 ++++ linux-2.6.21/arch/arm/mach-pxa/ezx.c 2007-05-03 19:15:57.000000000 -0300 +@@ -116,8 +116,32 @@ + .resource = ezxemu_resources, + }; + +-/* OHCI Controller */ ++/* PCAP_TS */ ++struct resource pcap_ts_resources[] = { ++ [0] = { ++ .start = EZX_IRQ_ADCDONE2, ++ .end = EZX_IRQ_ADCDONE2, ++ .flags = IORESOURCE_IRQ, ++ }, ++ [1] = { ++ .start = EZX_IRQ_TS, ++ .end = EZX_IRQ_TS, ++ .flags = IORESOURCE_IRQ, ++ } ++}; + ++struct platform_device pcap_ts_device = { ++ .name = "pcap-ts", ++ .id = -1, ++ .dev = { ++ .parent = &ezxpcap_device.dev, ++ }, ++ .num_resources = ARRAY_SIZE(pcap_ts_resources), ++ .resource = pcap_ts_resources, ++}; ++ ++ ++/* OHCI Controller */ + static int ezx_ohci_init(struct device *dev) + { + /* for A780 support (connected with Neptune) */ +@@ -342,6 +366,7 @@ + &ezxpcap_device, + &ezxbp_device, + &ezxemu_device, ++ &pcap_ts_device, + }; + + static void __init a780_init(void) +Index: linux-2.6.21/drivers/input/touchscreen/Makefile +=================================================================== +--- linux-2.6.21.orig/drivers/input/touchscreen/Makefile 2007-05-03 18:50:12.000000000 -0300 ++++ linux-2.6.21/drivers/input/touchscreen/Makefile 2007-05-03 18:50:59.000000000 -0300 +@@ -16,3 +16,4 @@ + obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o + obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o + obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o ++obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o |