diff options
Diffstat (limited to 'packages/linux/linux-ezx-2.6.21/ezx-ts.patch')
-rw-r--r-- | packages/linux/linux-ezx-2.6.21/ezx-ts.patch | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/packages/linux/linux-ezx-2.6.21/ezx-ts.patch b/packages/linux/linux-ezx-2.6.21/ezx-ts.patch new file mode 100644 index 0000000000..1dd88efd6e --- /dev/null +++ b/packages/linux/linux-ezx-2.6.21/ezx-ts.patch @@ -0,0 +1,399 @@ +Index: linux-2.6.21/drivers/input/touchscreen/Kconfig +=================================================================== +--- linux-2.6.21.orig/drivers/input/touchscreen/Kconfig 2007-04-26 05:08:32.000000000 +0200 ++++ linux-2.6.21/drivers/input/touchscreen/Kconfig 2007-04-26 23:27:05.000000000 +0200 +@@ -164,4 +164,16 @@ + 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_PCAP ++ help ++ Say Y here if you have a Motorola EZX (E680, A780) telephone ++ and want to support the built-in touchscreen. ++ ++ If unsure, say N. ++ ++ To compile this driver as a module, choose M here: the ++ module will be called hp680_ts_input. ++ + endif +Index: linux-2.6.21/drivers/input/touchscreen/Makefile +=================================================================== +--- linux-2.6.21.orig/drivers/input/touchscreen/Makefile 2007-04-26 05:08:32.000000000 +0200 ++++ linux-2.6.21/drivers/input/touchscreen/Makefile 2007-04-26 23:27:52.000000000 +0200 +@@ -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 +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-04-26 23:27:05.000000000 +0200 +@@ -0,0 +1,364 @@ ++/* ++ * 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. ++ * ++ * TODO: ++ * split this in a hardirq handler and a tasklet/bh ++ * suspend/resume support ++ */ ++ ++#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 "../../misc/ezx/ssp_pcap.h" ++ ++#if 1 ++#define DEBUGP(x, args ...) printk(KERN_DEBUG "%s: " x, __FUNCTION__, ## args) ++#else ++#define DEBUGP(x, args ...) ++#endif ++ ++#define PRESSURE 1 ++#define COORDINATE 2 ++ ++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, pressure_last; ++ ++ 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 ++ ++static int pcap_ts_mode(u_int32_t mode) ++{ ++ int ret; ++ ++ u_int32_t tmp; ++ ++ 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 |= mode; ++ ret = ezx_pcap_write(SSP_PCAP_ADJ_ADC1_REGISTER, tmp); ++ ++ DEBUGP("set ts mode "); ++ if (mode == PCAP_TS_POSITION_XY_MEASUREMENT) ++ DEBUGP("COORD\n"); ++ else if (mode == PCAP_TS_PRESSURE_MEASUREMENT) ++ DEBUGP("PRESS\n"); ++ else if (mode == PCAP_TS_STANDBY_MODE) ++ DEBUGP("STANDBY\n"); ++ else ++ printk("UNKNOWN\n"); ++ ++ return ret; ++} ++ ++/* issue a XY read command to the ADC of PCAP2. Well get an ADCDONE2 interrupt ++ * once the result of the conversion is available */ ++static int pcap_ts_start_xy_read(struct pcap_ts *pcap_ts) ++{ ++ int ret; ++ u_int32_t tmp; ++ DEBUGP("start xy read in mode %s\n", ++ pcap_ts->read_state == COORDINATE ? "COORD" : "PRESS"); ++ ++ ret = ezx_pcap_read(SSP_PCAP_ADJ_ADC1_REGISTER, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ tmp &= SSP_PCAP_ADC_START_VALUE_SET_MASK; ++ tmp |= SSP_PCAP_ADC_START_VALUE; ++ ++ ret = ezx_pcap_write(SSP_PCAP_ADJ_ADC1_REGISTER, tmp); ++ if (ret < 0) ++ return ret; ++ ++ ret = ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_ADC2_ASC, 1); ++ ++ return ret; ++} ++ ++/* read the XY result from the ADC of PCAP2 */ ++static int pcap_ts_get_xy_value(struct pcap_ts *pcap_ts) ++{ ++ int ret; ++ u_int32_t tmp; ++ ++ DEBUGP("get xy value in mode %s\n", ++ pcap_ts->read_state == COORDINATE ? "COORD" : "PRESS"); ++ ++ ret = ezx_pcap_read(SSP_PCAP_ADJ_ADC2_REGISTER, &tmp); ++ if (ret < 0) ++ return ret; ++ ++ if (tmp & 0x00400000) ++ return -EIO; ++ ++ if (pcap_ts->read_state == COORDINATE) { ++ 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_last = pcap_ts->pressure; ++ pcap_ts->pressure = (tmp & SSP_PCAP_ADD2_VALUE_MASK) ++ >>SSP_PCAP_ADD2_VALUE_SHIFT; ++ } ++ ++ return 0; ++} ++ ++/* PCAP2 interrupts us when ADC conversion result is available */ ++static irqreturn_t pcap_ts_irq_xy(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct pcap_ts *pcap_ts = dev_id; ++ ++ if (pcap_ts_get_xy_value(pcap_ts) < 0) { ++ printk("pcap_ts: error reading XY value\n"); ++ return IRQ_HANDLED; ++ } ++ ++ DEBUGP("%s X=%4d, Y=%4d Z=%4d\n", ++ pcap_ts->read_state == COORDINATE ? "COORD" : "PRESS", ++ pcap_ts->x, pcap_ts->y, pcap_ts->pressure); ++ ++ if (pcap_ts->read_state == PRESSURE) { ++ input_report_abs(pcap_ts->input, ABS_PRESSURE, ++ pcap_ts->pressure); ++ if ((pcap_ts->pressure >= PRESSURE_MAX || ++ pcap_ts->pressure <= PRESSURE_MIN ) && ++ pcap_ts->pressure == pcap_ts->pressure_last) { ++ /* pen has been released */ ++ input_report_key(pcap_ts->input, BTN_TOUCH, 0); ++ input_sync(pcap_ts->input); ++ ++ pcap_ts->x = pcap_ts->y = 0; ++ ++ /* ask PCAP2 to interrupt us if touch event happens ++ * again */ ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_mode(PCAP_TS_STANDBY_MODE); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ ++ /* no need for timer, we'll get interrupted with ++ * next touch down event */ ++ del_timer(&pcap_ts->timer); ++ } else { ++ /* pen has been touched down */ ++ input_report_key(pcap_ts->input, BTN_TOUCH, 1); ++ /* don't input_sync(), we don't know position yet */ ++ ++ /* 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); ++ ++ mod_timer(&pcap_ts->timer, jiffies + HZ/20); ++ } ++ } else { ++ /* we are in coordinate mode */ ++ 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) { ++ DEBUGP("invalid x/y coordinate position: PEN_UP?\n"); ++#if 0 ++ input_report_key(pcap_ts->input, BTN_TOUCH, 0); ++ pcap_ts->x = pcap_ts->y = 0; ++#endif ++ } else { ++ input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x); ++ input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y); ++ } ++ input_sync(pcap_ts->input); ++ ++ /* switch back to pressure read mode */ ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_mode(PCAP_TS_STANDBY_MODE); ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 0); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++/* PCAP2 interrupts us if the pen touches down */ ++static irqreturn_t pcap_ts_irq_touch(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct pcap_ts *pcap_ts = dev_id; ++ DEBUGP("entered\n"); ++ ++ /* 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); ++ 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; ++ ++ ezx_pcap_bit_set(SSP_PCAP_ADJ_BIT_MSR_TSM, 1); ++ pcap_ts_mode(PCAP_TS_PRESSURE_MEASUREMENT); ++ pcap_ts->read_state = PRESSURE; ++ pcap_ts_start_xy_read(pcap_ts); ++} ++ ++static int __init ezxts_probe(struct platform_device *pdev) ++{ ++ 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; ++ } ++ ++ ssp_pcap_open(SSP_PCAP_TS_OPEN); ++ ++ 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; ++ pcap_ts->read_state = PRESSURE; ++ 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); ++ ++ /* 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 struct platform_driver ezxts_driver = { ++ .probe = ezxts_probe, ++ .remove = ezxts_remove, ++ //.suspend = ezxts_suspend, ++ //.resume = ezxts_resume, ++ .driver = { ++ .name = "pcap-ts", ++ }, ++}; ++ ++static int __devinit 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"); |