⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hx4700_ts.c

📁 pocket pc hx4700 linux driver
💻 C
📖 第 1 页 / 共 2 页
字号:
/* 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 + -