S3C2440 Linux 触摸屏驱动
S3C2440 Linux 触摸屏驱动
主机:VM - RedHat 9.0
开发板:FL2440,linux-2.6.12
arm-linux-gcc:3.4.1
代码中的第90行,若不支持拖拽,则可以获取到笔触坐标,但是LCD上的图标没有响应,不知什么原因。
- #include <linux/config.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/device.h>
- #include <linux/miscdevice.h>
- #include <linux/delay.h>
- #include <linux/poll.h>
- #include <linux/spinlock.h>
- #include <linux/interrupt.h>
- #include <linux/delay.h>
- #include <linux/devfs_fs_kernel.h>
- #include <asm/hardware/clock.h>
- #include <asm/hardware.h>
- #include <asm/io.h>
- #include <asm/arch/regs-gpio.h>
- // YM_SEN输出驱动器使能,XP_SEN,YP_SEN输出驱动器禁止
- // S3C2410_ADCTSC_XY_PST(3) -- 手动测量X、Y方向,等待中断模式
- // x=0, 将ADCTSC[8]设置为0,即检测笔尖落下中断信号
- #define WAIT4INT(x) (((x)<<8) | \
- S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
- S3C2410_ADCTSC_XY_PST(3))
- /* ADCTSC Register Bits */
- #define S3C2410_ADCTSC_YM_SEN (1<<7)
- #define S3C2410_ADCTSC_YP_SEN (1<<6)
- #define S3C2410_ADCTSC_XM_SEN (1<<5)
- #define S3C2410_ADCTSC_XP_SEN (1<<4)
- #define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3)
- #define S3C2410_ADCTSC_AUTO_PST (1<<2)
- #define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0)
- /* ADCCON Register Bits */
- #define S3C2410_ADCCON_ECFLG (1<<15)
- #define S3C2410_ADCCON_PRSCEN (1<<14)
- #define S3C2410_ADCCON_PRSCVL(x) (((x)&0xFF)<<6)
- #define S3C2410_ADCCON_PRSCVLMASK (0xFF<<6)
- #define S3C2410_ADCCON_SELMUX(x) (((x)&0x7)<<3)
- #define S3C2410_ADCCON_MUXMASK (0x7<<3)
- #define S3C2410_ADCCON_STDBM (1<<2)
- #define S3C2410_ADCCON_READ_START (1<<1)
- #define S3C2410_ADCCON_ENABLE_START (1<<0)
- #define S3C2410_ADCCON_STARTMASK (0x3<<0)
- #ifdef S3C2410_ADCCON
- #undef S3C2410_ADCCON
- #endif
- #ifdef S3C2410_ADCTSC
- #undef S3C2410_ADCTSC
- #endif
- #ifdef S3C2410_ADCDLY
- #undef S3C2410_ADCDLY
- #endif
- #ifdef S3C2410_ADCDAT0
- #undef S3C2410_ADCDAT0
- #endif
- #ifdef S3C2410_ADCDAT1
- #undef S3C2410_ADCDAT1
- #endif
- #ifdef S3C2410_PA_ADC
- #undef S3C2410_PA_ADC
- #endif
- #define S3C2410_PA_ADC (0x58000000)
- static void __iomem *base_addr;
- #define S3C2410_ADCCON (base_addr+(0x00))
- #define S3C2410_ADCTSC (base_addr+(0x04))
- #define S3C2410_ADCDLY (base_addr+(0x08))
- #define S3C2410_ADCDAT0 (base_addr+(0x0c))
- #define S3C2410_ADCDAT1 (base_addr+(0x10))
- #ifdef CONFIG_PM
- #include <linux/pm.h>
- #endif
- // 支持拖拽
- // 若不支持拖拽,则可以获取到笔触坐标,但是LCD上的图标没有响应。
- // 可以看到read接口被调用到,不知为何图标没有响应。
- #define HOOK_FOR_DRAG
- //#define DEBUG
- #ifdef DEBUG
- #define DPRINTK printk
- #else
- #define DPRINTK
- #endif
- typedef struct {
- unsigned short pressure;
- unsigned short x;
- unsigned short y;
- unsigned short pad;
- } TS_RET;
- typedef struct {
- int xscale;
- int xtrans;
- int yscale;
- int ytrans;
- int xyswap;
- } TS_CAL;
- #define PEN_UP 0
- #define PEN_DOWN 1
- #define PEN_FLEETING 2
- #define MAX_TS_BUF 16 /* how many do we want to buffer */
- #undef USE_ASYNC
- #define DEVICE_NAME "s3c2410-ts"
- #define TSRAW_MINOR 1
- typedef struct {
- unsigned int penStatus; /* PEN_UP, PEN_DOWN, PEN_SAMPLE */
- TS_RET buf[MAX_TS_BUF]; /* protect against overrun */
- unsigned int head, tail; /* head and tail for queued events */
- wait_queue_head_t wq;
- spinlock_t lock;
- #ifdef USE_ASYNC
- struct fasync_struct *aq;
- #endif
- #ifdef CONFIG_PM
- struct pm_dev *pm_dev;
- #endif
- } TS_DEV;
- static TS_DEV tsdev;
- #define BUF_HEAD (tsdev.buf[tsdev.head])
- #define BUF_TAIL (tsdev.buf[tsdev.tail])
- #define INCBUF(x,mod) ((++(x)) & ((mod) - 1))
- static int tsMajor = 0;
- static void (*tsEvent)(void);
- #ifdef HOOK_FOR_DRAG
- #define TS_TIMER_DELAY (HZ/100) /* 10 ms */
- static struct timer_list ts_timer;
- #endif
- // pick-up regs val from 2.4.18&2440
- // YM_SEN输出驱动器使能,XP上拉使能,正常ADC转换,检测笔尖落下中断信号,等待中断模式
- #define wait_down_int() __raw_writel(0x000000d3,S3C2410_ADCTSC)
- // YM_SEN输出驱动器使能,XP上拉使能,正常ADC转换,检测笔尖抬起中断信号,等待中断模式
- #define wait_up_int() __raw_writel(0x000001d3, S3C2410_ADCTSC)
- // XM_SEN、XP_SEN输出驱动器使能,XP上拉禁止,正常ADC转换,X方向测量模式
- #define mode_x_axis() __raw_writel(0x00000069, S3C2410_ADCTSC)
- // 相当于__raw_writel(0x00000068, S3C2410_ADCTSC),即
- // XM_SEN、YP_SEN使能,XP上拉禁止,正常ADC转换,无操作模式
- #define mode_x_axis_n() __raw_writel(XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | \
- XP_PULL_UP_DIS | XP_PST(NOP_MODE), S3C2410_ADCTSC)
- // YM_SEN、YP_SEN使能,XP上拉禁止,正常ADC转换,Y方向测量模式
- #define mode_y_axis() __raw_writel(0x0000009a, S3C2410_ADCTSC)
- // __raw_writel(0x00007ffa, S3C2410_ADCCON); -- A/D转换器预分频器使能,预分频值0xff,模拟输入通道SEL_MUX为XP,正常工作模式,使能读启动操作
- // __raw_readl(S3C2410_ADCDAT0); -- 读取ADCDAT)的值
- #define start_adc_x() do {__raw_writel(0x00007ffa, S3C2410_ADCCON); \
- __raw_readl(S3C2410_ADCDAT0); } while(0)
- // 怎么跟start_adc_x()配置一样?应该为0x00007fea?
- #define start_adc_y() do {__raw_writel(0x00007ffa, S3C2410_ADCCON); \
- __raw_readl(S3C2410_ADCDAT1); } while(0)
- // 禁止读启动操作,即READ_START位置0
- #define disable_ts_adc() __raw_writel(__raw_readl(S3C2410_ADCCON)&0xfffffffd, S3C2410_ADCCON)
- static int adc_state = 0;
- static int x, y; /* touch screen coorinates */
- #ifdef HOOK_FOR_DRAG
- #define RT_BT_EMU_TM ((HZ>>1)+(HZ>>2)) //0.75S
- //static u16 ts_r_x[5];
- //static u16 ts_r_y[5];
- //static u16 ts_r_idx;
- //static u16 ts_r_beg;
- static u32 dn_start;
- #endif
- static void tsEvent_raw(void)
- {
- DPRINTK("@@@@@@@@ tvEvent_raw() @@@@@@@@@\n");
- if (tsdev.penStatus == PEN_DOWN)
- {
- //u16 i, j;
- #ifdef HOOK_FOR_DRAG
- ts_timer.expires = jiffies + TS_TIMER_DELAY;
- add_timer(&ts_timer);
- #endif
- BUF_HEAD.x = x;
- BUF_HEAD.y = y;
- #ifdef HOOK_FOR_DRAG
- BUF_HEAD.pressure = ((jiffies - dn_start) >= RT_BT_EMU_TM) ? PEN_FLEETING : PEN_DOWN;
- #else
- BUF_HEAD.pressure = PEN_DOWN;
- #endif
- }/* if (tsdev.penStatus == PEN_DOWN) */
- else
- {
- #ifdef HOOK_FOR_DRAG
- del_timer(&ts_timer);
- #endif
- BUF_HEAD.x = x;
- BUF_HEAD.y = y;
- BUF_HEAD.pressure = PEN_UP;
- }
- tsdev.head = INCBUF(tsdev.head, MAX_TS_BUF);
- DPRINTK("@@@@@@@@ wake_up_interruptible() in tvEvent_raw() @@@@@@@@@\n");
- wake_up_interruptible(&(tsdev.wq));
- #ifdef USE_ASYNC
- if (tsdev.aq)
- kill_fasync(&(tsdev.aq), SIGIO, POLL_IN);
- #endif
- #ifdef CONFIG_PM
- pm_access(tsdev.pm_dev);
- #endif
- }
- static int tsRead(TS_RET * ts_ret)
- {
- spin_lock_irq(&(tsdev.lock));
- ts_ret->x = BUF_TAIL.x;
- ts_ret->y = BUF_TAIL.y;
- ts_ret->pressure = BUF_TAIL.pressure;
- tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);
- spin_unlock_irq(&(tsdev.lock));
- return sizeof(TS_RET);
- }
- static ssize_t s3c2410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
- {
- TS_RET ts_ret;
- retry:
- if (tsdev.head != tsdev.tail)
- {
- int count;
- count = tsRead(&ts_ret);
- if (count)
- {
- printk("@@@@@ ts_ret.x: %hd, ts_ret.y: %hd @@@@@@@\n", ts_ret.x, ts_ret.y);
- copy_to_user(buffer, (char *)&ts_ret, count);
- }
- return count;
- }
- else
- {
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- interruptible_sleep_on(&(tsdev.wq));
- if (signal_pending(current))
- return -ERESTARTSYS;
- goto retry;
- }
- return sizeof(TS_RET);
- }
- #ifdef USE_ASYNC
- static int s3c2410_ts_fasync(int fd, struct file *filp, int mode)
- {
- return fasync_helper(fd, filp, mode, &(tsdev.aq));
- }
- #endif
- static unsigned int s3c2410_ts_poll(struct file *filp, struct poll_table_struct *wait)
- {
- poll_wait(filp, &(tsdev.wq), wait);
- return (tsdev.head == tsdev.tail) ? 0 : (POLLIN | POLLRDNORM);
- }
- static inline void start_ts_adc(void)
- {
- adc_state = 0;
- mode_x_axis();
- start_adc_x();
- }
- static inline void s3c2410_get_XY(void)
- {
- if (adc_state == 0)
- {
- adc_state = 1;
- disable_ts_adc();
- y = __raw_readl(S3C2410_ADCDAT1) & 0x3ff; //x:f04 y:f0e dh by pht.
- mode_y_axis();
- start_adc_y();
- }
- else if (adc_state == 1)
- {
- adc_state = 0;
- disable_ts_adc();
- x = __raw_readl(S3C2410_ADCDAT0) & 0x3ff; //y:f04 x:f0e dh by pht.
- printk("@@@@@@ PEN DOWN: x: %d, y: %d @@@@@@\n", x, y);
- wait_up_int();
- tsdev.penStatus = PEN_DOWN;
- tsEvent();
- }
- }
- static irqreturn_t s3c2410_isr_adc(int irq, void *dev_id, struct pt_regs *reg)
- {
- DPRINTK("@@@@@@@@ s3c2410_isr_adc() @@@@@@@@\n");
- spin_lock_irq(&(tsdev.lock));
- if (tsdev.penStatus == PEN_UP)
- {
- DPRINTK("@@@@@@ s3c2410_isr_adc 1 @@@@@@\n");
- s3c2410_get_XY();
- }
- #ifdef HOOK_FOR_DRAG
- else
- {
- DPRINTK("@@@@@@ s3c2410_isr_adc 2 @@@@@@\n");
- s3c2410_get_XY();
- }
- #endif
- spin_unlock_irq(&(tsdev.lock));
- return IRQ_HANDLED;
- }
- static irqreturn_t s3c2410_isr_tc(int irq, void *dev_id, struct pt_regs *reg)
- {
- DPRINTK("@@@@@@@@ s3c2410_isr_tc() @@@@@@@@\n");
- spin_lock_irq(&(tsdev.lock));
- if (tsdev.penStatus == PEN_UP)
- {
- DPRINTK("@@@@@@@@ s3c2410_isr_tc 1 @@@@@@@@\n");
- #ifdef HOOK_FOR_DRAG
- dn_start = jiffies; // add by gzliu
- #endif
- start_ts_adc();
- }
- else
- {
- tsdev.penStatus = PEN_UP;
- DPRINTK("@@@@@@@@ s3c2410_isr_tc 2 @@@@@@@@\n");
- printk("@@@@@@@ PEN UP: x: %d, y: %d @@@@@@@\n", x, y);
- wait_down_int();
- tsEvent();
- }
- spin_unlock_irq(&(tsdev.lock));
- return IRQ_HANDLED;
- }
- #ifdef HOOK_FOR_DRAG
- static void ts_timer_handler(unsigned long data)
- {
- spin_lock_irq(&(tsdev.lock));
- if (tsdev.penStatus == PEN_DOWN)
- {
- start_ts_adc();
- }
- spin_unlock_irq(&(tsdev.lock));
- }
- #endif
- static int s3c2410_ts_open(struct inode *inode, struct file *filp)
- {
- tsdev.head = tsdev.tail = 0;
- tsdev.penStatus = PEN_UP;
- #ifdef HOOK_FOR_DRAG
- init_timer(&ts_timer);
- ts_timer.function = ts_timer_handler;
- #endif
- tsEvent = tsEvent_raw;
- init_waitqueue_head(&(tsdev.wq));
- //MOD_INC_USE_COUNT;
- return 0;
- }
- static int s3c2410_ts_release(struct inode *inode, struct file *filp)
- {
- #ifdef HOOK_FOR_DRAG
- del_timer(&ts_timer);
- #endif
- //MOD_DEC_USE_COUNT;
- return 0;
- }
- static struct file_operations s3c2410_fops = {
- owner: THIS_MODULE,
- open: s3c2410_ts_open,
- read: s3c2410_ts_read,
- release: s3c2410_ts_release,
- #ifdef USE_ASYNC
- fasync: s3c2410_ts_fasync,
- #endif
- poll: s3c2410_ts_poll,
- };
- void tsEvent_dummy(void) {}
- #ifdef CONFIG_PM
- static int s3c2410_ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
- void *data)
- {
- switch (req) {
- case PM_SUSPEND:
- tsEvent = tsEvent_dummy;
- break;
- case PM_RESUME:
- tsEvent = tsEvent_raw;
- wait_down_int();
- break;
- }
- return 0;
- }
- #endif
- static struct clk *adc_clock;
- static int __init s3c2410ts_probe(struct device *dev)
- {
- int ret;
- tsEvent = tsEvent_dummy;
- DPRINTK("@@@@@@@@@@ s3c2410ts_probe @@@@@@@@@@\n");
- ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);
- if (ret < 0) {
- printk(DEVICE_NAME " can't get major number\n");
- return ret;
- }
- tsMajor = ret;
- adc_clock = clk_get(NULL, "adc");
- if (!adc_clock) {
- printk(KERN_ERR "failed to get adc clock source\n");
- return -ENOENT;
- }
- clk_use(adc_clock);
- clk_enable(adc_clock);
- base_addr = ioremap(S3C2410_PA_ADC, 0x20);
- __raw_writel(WAIT4INT(0), S3C2410_ADCTSC);
- __raw_writel(30000, S3C2410_ADCDLY); // 30000--20000
- ret = request_irq(IRQ_ADC, s3c2410_isr_adc, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_adc);
- if (ret)
- goto adc_failed;
- ret = request_irq(IRQ_TC, s3c2410_isr_tc, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_tc);
- if (ret)
- goto tc_failed;
- /* Wait for touch screen interrupts */
- wait_down_int();
- #ifdef CONFIG_DEVFS_FS
- devfs_mk_dir("touchscreen");
- devfs_mk_cdev(MKDEV(tsMajor, TSRAW_MINOR), S_IFCHR|S_IRUGO|S_IWUSR, "touchscreen/%s", "0raw");
- #endif
- #ifdef CONFIG_PM
- tsdev.pm_dev = pm_register(PM_DEBUG_DEV, PM_USER_INPUT, s3c2410_ts_pm_callback);
- #endif
- return 0;
- tc_failed:
- {
- printk(KERN_ERR "tc failed!!!!!!!!!!!!!\n");
- free_irq(IRQ_ADC, s3c2410_isr_adc);
- }
- adc_failed:
- {
- printk(KERN_ERR "adc failed!!!!!!!!!!!!!\n");
- return ret;
- }
- }
- static struct device_driver s3c2410ts_driver = {
- .name = DEVICE_NAME,
- .bus = &platform_bus_type,
- .probe = s3c2410ts_probe,
- #ifdef CONFIG_PM
- .suspend = s3c2410ts_suspend,
- .resume = s3c2410ts_resume,
- #endif
- };
- static int __init s3c2410ts_init(void)
- {
- int ret;
- printk("@@@@@@@@ s3c2410ts init() @@@@@@@\n");
- ret = driver_register(&s3c2410ts_driver);
- if(ret)
- {
- printk("register %s driver failed, return code is %d\n", DEVICE_NAME, ret);
- }
- else
- {
- printk("@@@@@@@ register %s driver success, return code is %d @@@@@@@@@@\n", DEVICE_NAME, ret);
- }
- return ret;
- }
- static void __exit s3c2410ts_exit(void)
- {
- #ifdef CONFIG_DEVFS_FS
- devfs_remove("touchscreen/%d", 0);
- devfs_remove("touchscreen");
- #endif
- unregister_chrdev(tsMajor, DEVICE_NAME);
- #ifdef CONFIG_PM
- pm_unregister(tsdev.pm_dev);
- #endif
- free_irq(IRQ_ADC, s3c2410_isr_adc);
- free_irq(IRQ_TC, s3c2410_isr_tc);
- driver_unregister(&s3c2410ts_driver);
- }
- module_init(s3c2410ts_init);
- module_exit(s3c2410ts_exit);
评论暂时关闭