免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1931 | 回复: 2
打印 上一主题 下一主题

[驱动] 写了一个tiny6410的触摸屏驱动,却怎么也运行不了 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-12-16 20:57 |只看该作者 |倒序浏览
板子用的是friendlyarm的tiny6410, linux内核2.6.38,已经卸载了内核自带的ADC和触摸屏驱动。加载.ko模块后,用cat proc/devices  和 cat proc/interrupts ,中断也成功注册了,设备也成功注册了,但按下触摸屏就是不产生TC中断 ,就是不进入中断处理函数(我在TC中断处理函数开头用了printk观察的,始终没有打印)。如果用2.6.38自带的mini6410-ts.c编译成驱动模块加载,也不能工作。触摸屏确定是好的。求大神帮忙,谢谢!
以下是代码:
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/err.h>
#include <mach/irqs.h>
#include <plat/regs-adc.h>
#include <asm/io.h>
#include <mach/hardware.h>

#define DEV_NAME "test_ts"
static unsigned int devno;
static struct class *myclass;
static struct clk *ts_clock;
static struct timer_list ts_timer;

static struct cdev ts_cdev;

#define HOOK_FOR_DRAG
#ifdef HOOK_FOR_DRAG
#define TS_TIMER_DELAY  (HZ/100) //HZ:每秒timer interrupt次数 /* 10 ms */
#endif

#define UD_SEN_0 (0<<  //Detect Stylus Down Interrupt Signal
#define UD_SEN_1 (1<<  //Detect Stylus up Interrupt Signal
#define YM_SEN_1 (1<<7)
#define YP_SEN_1 (1<<6)
#define XM_SEN_0 (0<<5)
#define XP_SEN_1 (1<<4)
#define PULL_UP_0 (0<<3) //XP Pull-up Enable
#define AUTO_PST_0 (0<<2)
#define XY_PST_11 (3) //Waiting for Interrupt Mode

#define PRSCEN_1 (1<<14) //A/D converter prescaler enable
#define PRSCVL_50 ((49<<6)|0xc03f) //A/D converter prescaler value : 50
#define STDBM_0 (~(1<<2))  //Standby mode select: Normal operation mode
#define ENABLE_START_1 (1) //A/D conversion starts by enable

static void __iomem *base_addr;

#define __ADCREG(name)        (*(volatile unsigned long *)(base_addr + name))
#define ADCCON                        __ADCREG(S3C_ADCCON)        // ADC control
#define ADCTSC                        __ADCREG(S3C_ADCTSC)        // ADC touch screen control
#define ADCDAT0                        __ADCREG(S3C_ADCDAT0)        // ADC conversion data 0
#define ADCDAT1                        __ADCREG(S3C_ADCDAT1)        // ADC conversion data 1
#define ADCUPDN                        __ADCREG(S3C_ADCUPDN)

//ADCTSC是指ADCTSC寄存器的内容
#define wait_down_int()        ADCTSC = ( UD_SEN_0 | PULL_UP_0 | XP_SEN_1 | XM_SEN_0 | YP_SEN_1 | YM_SEN_1 | XY_PST_11 )
#define wait_up_int()        ADCTSC = ( UD_SEN_1 | PULL_UP_0 | XP_SEN_1 | XM_SEN_0 | YP_SEN_1 | YM_SEN_1 | XY_PST_11 )
#define mode_x_axis()        ADCTSC = ( ADCTSC & 0xff1 )
#define mode_y_axis()        ADCTSC = ( ADCTSC & 0xff2 )
#define start_adc_x()   ADCCON = (( ADCCON | PRSCEN_1 | ENABLE_START_1 )& STDBM_0 & PRSCVL_50 )
#define start_adc_y()   ADCCON = (( ADCCON | PRSCEN_1 | ENABLE_START_1 )& STDBM_0 & PRSCVL_50 )
//#define start_adc_x()        { ADCCON = PRESCALE_EN | PRSCVL(49) | ADC_INPUT(ADC_IN5) | ADC_START_BY_RD_EN | ADC_NORMAL_MODE; ADCDAT0; }
//#define start_adc_y()        { ADCCON = PRESCALE_EN | PRSCVL(49) | ADC_INPUT(ADC_IN7) | ADC_START_BY_RD_EN | ADC_NORMAL_MODE; ADCDAT1; }
//#define mode_x_axis_n()        { ADCTSC = XP_EXTVLT | XM_GND | YP_AIN | YM_HIZ | XP_PULL_UP_DIS | XP_PST(NOP_MODE); }
//#define start_adc_x() ADCTSC = (ADCTSC&(~0x3ul))|0x1    //ADCTSC是指ADCTSC寄存器的内容,将ADCTSC后两位置01
//#define disable_ts_adc()
#define PEN_UP                0        //弹起       
#define PEN_DOWN        1        //按下
#define MAX_TS_BUF      8       //最大缓存数

typedef struct { //保存的转换数据结构
  unsigned short pressure;
  unsigned short x;
  unsigned short y;
} TS_RET;

static unsigned int penStatus; //弹起0;按下1
static TS_RET buf[MAX_TS_BUF]; //缓存队列
static unsigned int head, tail;
static wait_queue_head_t wq;
static spinlock_t lock;
static int adc_state = 0; //adc_state=0指转换x ; adc_state=1指转换y ,(x/y分开转换模式)
static unsigned short x;
static unsigned short y;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);//定义等待队列头
#define BUF_HEAD        (buf[head])
#define BUF_TAIL        (buf[tail])
#define INCBUF(x,mod)         ((++(x)) & ((mod) - 1)) //x=0,1,2,3,4,5,6,7,0...

static void tsEvent(void)
{
        if (penStatus == PEN_DOWN)
        { /* 保存按下时的坐标 */
                BUF_HEAD.x = x;
                BUF_HEAD.y = y;
                BUF_HEAD.pressure = PEN_DOWN;

#ifdef HOOK_FOR_DRAG
                ts_timer.expires = jiffies + TS_TIMER_DELAY; //expires:指定定时器到期的时间,到期时执行ts_timer_handler ,
                                                             // jiffies: 系统开机以来的timer interrupt次数,除以HZ就是时间
                add_timer(&ts_timer); /* 对长时间按下键的处理 */
#endif
        }
        else
        {
#ifdef HOOK_FOR_DRAG
                del_timer(&ts_timer);
#endif
               
                BUF_HEAD.x = 0;
                BUF_HEAD.y = 0;
                BUF_HEAD.pressure = PEN_UP; /* 保存弹起时的坐标 */ //弹起时不需转换
        }

        head = INCBUF(head, MAX_TS_BUF);
        wake_up_interruptible(&wq); /* 唤醒进程 */

}

static inline void start_ts_adc(void)//AD转换函数
{
        adc_state = 0;
        mode_x_axis();
        start_adc_x();
}

static inline void s3c6410_get_XY(void)
{
        if (adc_state == 0)  /* 转换x */
        {
                adc_state = 1; /* 下次转换y */
                //disable_ts_adc();
                x = (ADCDAT0 & 0x3ff); /* 获取x坐标 */
                mode_y_axis();
                start_adc_y(); /*启动y坐标转化*/
        }
        else if (adc_state == 1)   /*转换y*/
        {
                adc_state = 0;
                //disable_ts_adc();
                y = (ADCDAT1 & 0x3ff); /* 获取y坐标 */
                penStatus = PEN_DOWN; /* 改变屏状态为按下 */
                printk("EN DOWN: x: %08d, y: %08d\n", x, y);
                wait_up_int();   /* 等待弹起中断 */ //与程序是否阻塞无关!
                tsEvent();
        }
}

static irqreturn_t s3c6410_isr_adc(int irq, void *dev_id)
{
        printk("adc irq1";
        spin_lock_irq(&lock);
        printk("adc irq2";
        if (penStatus == PEN_UP) //如果是按下中断(按下之前是弹起的,penStatus=0)
                s3c6410_get_XY();
        #ifdef HOOK_FOR_DRAG
        else
                s3c6410_get_XY();
        #endif
        spin_unlock_irq(&lock);
        return IRQ_RETVAL(IRQ_HANDLED);
}


static irqreturn_t s3c6410_isr_tc(int irq, void *dev_id)
{
        printk("tc irq1";
        spin_lock_irq(&lock);
        printk("tc irq2";
        if (penStatus == PEN_UP) //如果是按下中断(按下之前是弹起的,penStatus=0)
        {
                  start_ts_adc(); /* 开始AD转化 */
        }
        else
        {
                  penStatus = PEN_UP; /* 如果是弹起中断*/
                  printk("EN UP: x: %08d, y: %08d\n", x, y);
                  wait_down_int(); /*等待按下中断*/
                  tsEvent(); /* 调用后续处理函数 */
        }
        spin_unlock_irq(&lock);
        return IRQ_RETVAL(IRQ_HANDLED);
}

#ifdef HOOK_FOR_DRAG
static void ts_timer_handler(unsigned long data)
{
        spin_lock_irq(&lock);
        if (penStatus == PEN_DOWN) {
                start_ts_adc();
        }
        spin_unlock_irq(&lock);
}
#endif

static int s3c6410_ts_open(struct inode *inode, struct file *filp)
{
        printk("open\n";
        head = tail = 0;
        penStatus = PEN_UP;//初始状态为弹起
#ifdef HOOK_FOR_DRAG
        init_timer(&ts_timer);
        ts_timer.function = ts_timer_handler;
#endif
        //tsEvent = tsEvent_raw;
        init_waitqueue_head(&wq);

        //MOD_INC_USE_COUNT;
        return 0;
}


static int s3c6410_ts_release(struct inode *inode, struct file *filp)
{
        printk("release\n";
        #ifdef HOOK_FOR_DRAG
        del_timer(&ts_timer);
#endif
        //MOD_DEC_USE_COUNT; //模块使用次数计数
        return 0;
}


static int s3c6410_ts_read(struct file *filp, char *buffer, size_t count, loff_t *offp)
{
        printk("read\n";
        TS_RET ts_ret;
        unsigned long err;
retry:
        if (head != tail)
        {
                int count;
               
                spin_lock_irq(&lock);
                ts_ret.x = BUF_TAIL.x;
                ts_ret.y = BUF_TAIL.y;
                ts_ret.pressure = BUF_TAIL.pressure;
                tail = INCBUF(tail, MAX_TS_BUF);
                spin_unlock_irq(&lock);
       
                count = sizeof(ts_ret);
                if (count)
                        err = copy_to_user(buffer, (char *)&ts_ret, count);
                return err ? -EFAULT : count;
        }
        else
        {
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
                interruptible_sleep_on(&wq);
                if (signal_pending(current))
                        return -ERESTARTSYS;
                goto retry;
        }

        return sizeof(TS_RET);
}


static unsigned int s3c6410_ts_poll(struct file *filp, struct poll_table_struct *wait)
{
        printk("poll\n";
        poll_wait(filp, &wq, wait);
        if(head != tail)
                return (POLLIN | POLLRDNORM);
        else
                return 0;
}


static struct file_operations dev_fops = {
    .owner   =   THIS_MODULE,
    .open    =   s3c6410_ts_open,
    .release =   s3c6410_ts_release,
    .read    =   s3c6410_ts_read,
    .poll    =   s3c6410_ts_poll,
};

static int __init s3c6410_ts_init(void)
{
        int ret;
        void __iomem *VIC1_INTENABLE;
        VIC1_INTENABLE = ioremap(0x71300010, 4);
        printk("%lx\n", (*(volatile unsigned long *)VIC1_INTENABLE) );
        //unsigned int devno;
        base_addr = ioremap(0x7E00B000, 4);
       
        ts_clock = clk_get( NULL, "adc" );
        printk("IS_ERR(ts_clock)= %ld\n", IS_ERR(ts_clock));
        if (IS_ERR(ts_clock))
        {
        printk("%ld, failed to find watchdog clock source\n", IS_ERR(ts_clock));
        //ret = PTR_ERR(ts_clock);
        //goto err_clk;
        }

        ret = clk_enable(ts_clock);
        printk("ret= %d\n", ret );
       
        alloc_chrdev_region(&devno, 0, 1, DEV_NAME);//动态分配设备号
        printk("%d\n",MAJOR(devno));
        cdev_init(&ts_cdev, &dev_fops);
        ts_cdev.owner = THIS_MODULE;
       
        ret=cdev_add(&ts_cdev, devno, 1);
        if(ret)
                printk(KERN_NOTICE "Error adding cdev\n";
               
        //set_gpio_ctrl(GPIO_YPON);
        //set_gpio_ctrl(GPIO_YMON);
        //set_gpio_ctrl(GPIO_XPON);
        //set_gpio_ctrl(GPIO_XMON);

       
        /* 注册中断 */
        ret = request_irq(IRQ_ADC, s3c6410_isr_adc, IRQF_DISABLED|IRQF_SHARED,  //IRQF_DISABLED禁止中断被中断
                          DEV_NAME, s3c6410_isr_adc);
        printk("adc ret=%d\n",ret);
        if (ret) goto adc_failed;
        ret = request_irq(IRQ_TC, s3c6410_isr_tc, IRQF_DISABLED,
                          DEV_NAME, s3c6410_isr_tc);
        printk("tc ret=%d\n",ret);                  
        if (ret) goto tc_failed;

        /* 等待触摸屏被按下的中断 */
                wait_down_int();
                //printk("ADCTSC=%lx\n", ADCTSC);
                printk(DEV_NAME"\tinitialized\n";
       
        myclass = class_create(THIS_MODULE, "char_dev");
        device_create(myclass, NULL, devno, NULL, DEV_NAME);        //struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)

        return 0;
       
tc_failed:
        //printk("tc failed");
        free_irq(IRQ_ADC, s3c6410_isr_adc);
adc_failed:
        //printk("adc failed");
        return ret;
       
}

static void __exit s3c6410_ts_exit(void)
{
        device_destroy(myclass, devno);         
        class_destroy(myclass);  
        cdev_del(&ts_cdev);                             
        free_irq(IRQ_ADC, s3c6410_isr_adc);
        free_irq(IRQ_TC, s3c6410_isr_tc);       
        clk_disable(ts_clock);       
}

module_init(s3c6410_ts_init);
module_exit(s3c6410_ts_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("QX");

论坛徽章:
0
2 [报告]
发表于 2013-12-17 14:54 |只看该作者
没有实际环境,很难帮你分析问题。
建议先确定硬件是OK的,用原三星的ADC驱动,触摸屏驱动,测试下触摸屏按下去是有中断的。
用cat proc/interrupts ,可以看到中断得次数。

硬件OK,不仅仅是指你的触摸屏OK,还得保证触摸屏到CPU的4根连线想通的。
回复 1# snakescrin


   

论坛徽章:
0
3 [报告]
发表于 2013-12-20 09:37 |只看该作者
我觉得应该用万用表先量下你的硬件有没有真的上电,然后用示波器看看触摸有没有真的产生中断。确保硬件没有问题。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP