📄 hx4700_ts.c
字号:
/* Touch screen driver for the TI something-or-other * * Copyright © 2005 SDG Systems, LLC * * Based on code that was based on the SAMCOP driver. * Copyright © 2003, 2004 Compaq Computer Corporation. * * Use consistent with the GNU GPL is permitted, * provided that this copyright notice is * preserved in its entirety in all copies and derived works. * * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS * FITNESS FOR ANY PARTICULAR PURPOSE. * * Author: Keith Packard <keith.packard@hp.com> * May 2003 * * Updates: * * 2004-02-11 Michael Opdenacker Renamed names from samcop to shamcop, * Goal:support HAMCOP and SAMCOP. * 2004-02-14 Michael Opdenacker Temporary fix for device id handling * * 2005-02-18 Aric Blumer Converted basic structure to support hx4700 * * 2005-06-07 Aric Blumer Added tssim device handling so we can * hook in the fbvncserver. */#include <linux/module.h>#include <linux/version.h>#include <linux/config.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <linux/pm.h>#include <linux/delay.h>#include <linux/input.h>#include <linux/input_pda.h>#include <linux/platform_device.h>#include <linux/battery.h>#include <asm/arch/hardware.h>#include <asm/irq.h>#include <asm/mach/irq.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/arch/pxa-regs.h>#include <asm/arch/hx4700-gpio.h>#include <asm/arch/hx4700-asic.h>#include <asm/hardware/ipaq-asic3.h>#include <linux/soc/asic3_base.h>extern struct platform_device hx4700_asic3;enum touchscreen_state { STATE_WAIT_FOR_TOUCH, /* Waiting for a PEN interrupt */ STATE_SAMPLING /* Actively sampling ADC */};struct touchscreen_data { enum touchscreen_state state; struct timer_list timer; int irq; struct input_dev *input;};struct key_data { int gpiod_val; int gpiod_bit; int rising; int key; int irq;} asic3_key[3];static unsigned long poll_sample_time = 10; /* Sample every 10 milliseconds */static struct touchscreen_data *ts_data;#define TS_SAMPLES 5module_param(poll_sample_time, ulong, 0644);MODULE_PARM_DESC(poll_sample_time, "Poll sample time");static inline voidreport_touchpanel(struct touchscreen_data *ts, int pressure, int x, int y){ input_report_abs(ts->input, ABS_PRESSURE, pressure); input_report_abs(ts->input, ABS_X, x); input_report_abs(ts->input, ABS_Y, y); input_sync(ts->input);}static struct work_struct serial_work;static irqreturn_tpen_isr(int irq, void *irq_desc, struct pt_regs *regs){ /* struct touchscreen_data *ts = dev_id->data; */ struct touchscreen_data *ts = ts_data; if(irq == HX4700_IRQ(TOUCHPANEL_IRQ_N)) { if (ts->state == STATE_WAIT_FOR_TOUCH) { /* * There is ground bounce or noise or something going on here: * when you write to the SSP port to get the X and Y values, it * causes a TOUCHPANEL_IRQ_N interrupt to occur. So if that * happens, we can check to make sure the pen is actually down and * disregard the interrupt if it's not. */ if(GET_HX4700_GPIO(TOUCHPANEL_IRQ_N) == 0) { /* * Disable the pen interrupt. It's reenabled when the user lifts the * pen. */ disable_irq(HX4700_IRQ(TOUCHPANEL_IRQ_N)); ts->state = STATE_SAMPLING; schedule_work(&serial_work); } } else { /* Shouldn't happen */ printk(KERN_ERR "Unexpected ts interrupt\n"); } } return IRQ_HANDLED;}static intkey_isr(int irq, void *dev_id, struct pt_regs *regs){ struct key_data *key = dev_id; int statusd; /* * alternate between rising and falling, based on pin status */ statusd = ipaq_asic3_read_gpio_status_d( &hx4700_asic3.dev ); key->rising = (statusd & key->gpiod_bit) == 0; set_irq_type( irq, key->rising ? IRQT_RISING : IRQT_FALLING ); input_report_key( ts_data->input, key->key, key->rising ); input_sync( ts_data->input ); return IRQ_HANDLED;}static voidssp_init(void){ pxa_set_cken(CKEN3_SSP2, 1); /* *** Set up the SPI Registers *** */ SSCR0_P2 = (1 << 20) /* Extended Data Size Select */ | (6 << 8) /* Serial Clock Rate */ | (0 << 7) /* Synchronous Serial Enable (Disable for now) */ | (0 << 4) /* Motorola SPI Interface */ | (7 << 0) /* Data Size Select (24-bit) */ ; SSCR1_P2 = 0; SSPSP_P2 = 0; /* Clear the Status */ SSSR_P2 = SSSR_P2 & 0x00fcfffc; /* Now enable it */ SSCR0_P2 = (1 << 20) /* Extended Data Size Select */ | (6 << 8) /* Serial Clock Rate */ | (1 << 7) /* Synchronous Serial Enable */ | (0 << 4) /* Motorola SPI Interface */ | (7 << 0) /* Data Size Select (24-bit) */ ; /* enable_irq(HX4700_IRQ(TOUCHPANEL_IRQ_N)); */}DECLARE_MUTEX(serial_mutex);static voidstart_read(void *in){ struct touchscreen_data *touch = in; unsigned long inc = (poll_sample_time * HZ) / 1000; int i; down(&serial_mutex); /* Write here to the serial port. * Then we have to wait for poll_sample_time before we read out the serial * port. Then, when we read it out, we check to see if the pen is still * down. If so, then we issue another request here. */ for(i = 0; i < TS_SAMPLES; i++) { while(!(SSSR_P2 & (1 << 2))) ; /* It's not full. Write the command for X */ SSDR_P2 = 0xd00000; while(!(SSSR_P2 & (1 << 2))) ; /* It's not full. Write the command for Y */ SSDR_P2 = 0x900000; } /* * Enable the timer. We should get an interrupt, but we want keep a timer * to ensure that we can detect missing data */ mod_timer(&touch->timer, jiffies + inc);}static intdo_delta_calc(int x1, int y1, int x2, int y2, int x3, int y3){ /* This is based on Jamey Hicks' description on IRC. */ int dx2_a, dy2_a, dx2_b, dy2_b; dx2_a = x2 - x1; dx2_a = dx2_a * dx2_a; /* If dx2_a was negative, it's not now */ dy2_a = y2 - y1; dy2_a = dy2_a * dy2_a; /* If dy2_a was negative, it's not now */ dx2_b = x3 - x2; dx2_b = dx2_b * dx2_b; /* If dx2_b was negative, it's not now */ dy2_b = y3 - y2; dy2_b = dy2_b * dy2_b; /* If dy2_b was negative, it's not now */#if 0 /* This was described in the algorithm by Jamey, but it doesn't do much * good. */ if(dx2_a + dy2_a < dx2_b + dy2_b) return 0;#endif /* dx2_a + dy2_a is the distance squared */ if( ((dx2_a + dy2_a) > 8000) || ((dx2_b + dy2_b) > 8000) ) { return 0; } else { return 1; } if((dx2_b + dy2_b) > 5000) { return 0; } else { return 1; }}static voidts_timer_callback(unsigned long data){ struct touchscreen_data *ts = (struct touchscreen_data *)data; int x, y; int ssrval; /* * Check here to see if there is anything in the SPI FIFO. If so, * return it if there has been a change. If not, then we have a * timeout. Generate an erro somehow. */ ssrval = SSSR_P2; if(ssrval & (1 << 3)) { /* Look at Rx Not Empty bit */ int number_of_entries_in_fifo; /* The FIFO is not emtpy. Good! Now make sure there are at least two * entries. */ number_of_entries_in_fifo = ((ssrval >> 12) & 0xf) + 1; if(number_of_entries_in_fifo < (TS_SAMPLES * 2)) { /* Not ready yet. Come back later. */ unsigned long inc = (poll_sample_time * HZ) / 1000; mod_timer(&ts->timer, jiffies + inc); return; } if(number_of_entries_in_fifo == TS_SAMPLES * 2) { int i, result, keep; int X[TS_SAMPLES], Y[TS_SAMPLES]; for(i = 0; i < TS_SAMPLES; i++) { X[i] = SSDR_P2; Y[i] = SSDR_P2; } up(&serial_mutex); keep = 0; x = y = 0; result = 0; if(do_delta_calc(X[0], Y[0], X[1], Y[1], X[2], Y[2])) { result |= (1 << 2); } if(do_delta_calc(X[1], Y[1], X[2], Y[2], X[3], Y[3])) { result |= (1 << 1); } if(do_delta_calc(X[2], Y[2], X[3], Y[3], X[4], Y[4])) { result |= (1 << 0); } switch(result) { case 0: /* Take average of point 0 and point 3 */ X[2] = (X[1] + X[3]) / 2; Y[2] = (Y[1] + Y[3]) / 2; /* don't keep */ break; case 1: /* Just ignore this one */ break; case 2: case 3: case 6: /* keep this sample */ x = (X[1] + (2 * X[2]) + X[3]) / 4; y = (Y[1] + (2 * Y[2]) + Y[3]) / 4; keep = 1; break; case 4: X[1] = (X[0] + X[2]) / 2; Y[1] = (Y[0] + Y[2]) / 2; /* don't keep */ break; case 5: case 7: x = (X[0] + (4 * X[1]) + (6 * X[2]) + (4 * X[3]) + X[4]) >> 4; y = (Y[0] + (4 * Y[1]) + (6 * Y[2]) + (4 * Y[3]) + Y[4]) >> 4; keep = 1; break; } if(GET_HX4700_GPIO(TOUCHPANEL_IRQ_N) == 0) { /* Still down */ if(keep) { report_touchpanel(ts, 1, x, y); } start_read(ts); } else { /* Up */ report_touchpanel(ts, 0, 0, 0); ts->state = STATE_WAIT_FOR_TOUCH; /* Re-enable pen down interrupt */ enable_irq(HX4700_IRQ(TOUCHPANEL_IRQ_N)); } } else { /* We have an error! Too many entries. */ printk(KERN_ERR "TS: Expected %d entries. Got %d\n", 2, number_of_entries_in_fifo); /* Try to clear the FIFO */ while(number_of_entries_in_fifo--) { (void)SSDR_P2; } up(&serial_mutex); if(GET_HX4700_GPIO(TOUCHPANEL_IRQ_N) == 0) { start_read(ts); } return; } } else { /* Not ready yet. Come back later. */ unsigned long inc = (poll_sample_time * HZ) / 1000; mod_timer(&ts->timer, jiffies + inc); return; }}static intts_probe (struct device *dev){ int retval; struct touchscreen_data *ts; unsigned int irq; int err; ts = ts_data = kmalloc (sizeof (*ts), GFP_KERNEL); if (ts == NULL) { printk( KERN_NOTICE "hx4700_ts: unable to allocate memory\n" ); return -ENOMEM; } memset (ts, 0, sizeof (*ts)); /* *** Set up the input subsystem stuff *** */ // memset(ts->input, 0, sizeof(struct input_dev)); ts->input = input_allocate_device(); if (ts->input == NULL) { printk( KERN_NOTICE "hx4700_ts: unable to allocation touchscreen input\n" ); kfree(ts); return -ENOMEM; } ts->input->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY); ts->input->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE); ts->input->absmin[ABS_X] = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -