免费注册 查看新帖 |

Chinaunix

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

s3c2440 触摸屏驱动(针对android版) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-17 21:05 |只看该作者 |倒序浏览
和原来的触摸屏驱动区别不是很大,增加了report函数来将事件发送到应用层。
驱动结构:
很简单的字符设备+平台设备驱动,总的结构来说,主要四个部分构成:
probe
remove
resume
suspend
工作机制则是注册设备,然后发生ts按下事件后产生ts中断以及adc中断,获得按下坐标。
没有读写函数,重点就是在两个中断处理函数上。
1,平台设备架构部分分析:
probe函数:
流程:ts基址的重映射->获得并启动时钟->ADCCON、ADCDLY、ADCTSC的初始化->初始化input设备完善ts结构体->建立ts_filter_chain->申请中断->注册input设备(2.6.27后为event0不再是ts0)。
static int __init s3c2410ts_probe(struct platform_device *pdev)
{
    int rc;
    struct s3c2410_ts_mach_info *info;
    struct input_dev *input_dev;
    int ret = 0;
    dev_info(&pdev->dev, "Starting\n");
    info = (struct s3c2410_ts_mach_info *)pdev->dev.platform_data;//获得平台设备数据
    if (!info)
    {
        dev_err(&pdev->dev, "Hm... too bad: no platform data for ts\n");
        return -EINVAL;
    }
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
    printk(DEBUG_LVL "Entering s3c2410ts_init\n");
#endif
    adc_clock = clk_get(NULL, "adc");
    if (!adc_clock) {
        dev_err(&pdev->dev, "failed to get adc clock source\n");
        return -ENOENT;
    }
    clk_enable(adc_clock);
#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
    printk(DEBUG_LVL "got and enabled clock\n");
#endif
    base_addr = ioremap(S3C2410_PA_ADC,0x20);//将PA_ADC寄存器重映射到内存上
    if (base_addr == NULL) {
        dev_err(&pdev->dev, "Failed to remap register block\n");
        ret = -ENOMEM;
        goto bail0;
    }
    /* If we acutally are a S3C2410: Configure GPIOs */
    if (!strcmp(pdev->name, "s3c2410-ts"))
        s3c2410_ts_connect();//初始化相关gpio口
    if ((info->presc & 0xff) > 0)
        writel(S3C2410_ADCCON_PRSCEN |
               S3C2410_ADCCON_PRSCVL(info->presc&0xFF),
                            base_addr + S3C2410_ADCCON);
    else
        writel(0, base_addr+S3C2410_ADCCON);
    /* Initialise registers */
    if ((info->delay & 0xffff) > 0)
        writel(info->delay & 0xffff,  base_addr + S3C2410_ADCDLY);
    writel(WAIT4INT(0), base_addr + S3C2410_ADCTSC);
    /* Initialise input stuff */
    memset(&ts, 0, sizeof(struct s3c2410ts));
    input_dev = input_allocate_device();
    if (!input_dev) {
        dev_err(&pdev->dev, "Unable to allocate the input device\n");
        ret = -ENOMEM;
        goto bail1;
    }
//初始化input设备
    ts.dev = input_dev;
    ts.dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) |
               BIT_MASK(EV_ABS);
    ts.dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
    input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);
    input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
    input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
    ts.dev->name = s3c2410ts_name;
    ts.dev->id.bustype = BUS_RS232;
    ts.dev->id.vendor = 0xDEAD;
    ts.dev->id.product = 0xBEEF;
    ts.dev->id.version = S3C2410TSVERSION;
    ts.state = TS_STATE_STANDBY;//设置ts状态为就绪
    ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL);//为event队列申请内存空间
    if (IS_ERR(ts.event_fifo)) {
        ret = -EIO;
        goto bail2;
    }
    /* create the filter chain set up for the 2 coordinates we produce */
    ts.chain = ts_filter_chain_create(pdev, info->filter_config, 2);//针对android的,建立filter_chain
    if (IS_ERR(ts.chain))
        goto bail2;
    ts_filter_chain_clear(ts.chain);
    /* Get irqs */
    if (request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,
                            "s3c2410_action", ts.dev)) {
        dev_err(&pdev->dev, "Could not allocate ts IRQ_ADC !\n");
        iounmap(base_addr);
        ret = -EIO;
        goto bail3;
    }
    if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
            "s3c2410_action", ts.dev)) {
        dev_err(&pdev->dev, "Could not allocate ts IRQ_TC !\n");
        free_irq(IRQ_ADC, ts.dev);
        iounmap(base_addr);
        ret = -EIO;
        goto bail4;
    }
    dev_info(&pdev->dev, "Successfully loaded\n");
    /* All went ok, so register to the input system */
    rc = input_register_device(ts.dev);
    if (rc) {
        ret = -EIO;
        goto bail5;
    }
    return 0;
bail5:
    free_irq(IRQ_TC, ts.dev);
    free_irq(IRQ_ADC, ts.dev);
    clk_disable(adc_clock);
    iounmap(base_addr);
    disable_irq(IRQ_TC);
bail4:
    disable_irq(IRQ_ADC);
bail3:
    ts_filter_chain_destroy(ts.chain);
    kfifo_free(ts.event_fifo);
bail2:
    input_unregister_device(ts.dev);
bail1:
    iounmap(base_addr);
bail0:
    return ret;
}
remove:
就是probe的逆运算,
static int s3c2410ts_remove(struct platform_device *pdev)
{
    disable_irq(IRQ_ADC);
    disable_irq(IRQ_TC);
    free_irq(IRQ_TC,ts.dev);
    free_irq(IRQ_ADC,ts.dev);
    if (adc_clock) {
        clk_disable(adc_clock);
        clk_put(adc_clock);
        adc_clock = NULL;
    }
    input_unregister_device(ts.dev);
    iounmap(base_addr);
    ts_filter_chain_destroy(ts.chain);
    kfifo_free(ts.event_fifo);
    return 0;
}
resume与suspend函数可有可无,完成触摸屏的激活和挂起,
2,中断处理分析:
三种模式转换过程:等待down中断模式->x,y连续坐标转换模式->等待up中断模式->等待down中断模式->..
两个中断的发生:触摸屏按下,发生ts中断,开始ad转换,ad转换结束,发生adc中断。
              触摸屏抬起,发生ts中断。
ts中断处理函数:
//判断ts中断是up还是down
static irqreturn_t stylus_updown(int irq, void *dev_id)
{
    unsigned long data0;
    unsigned long data1;
    int event_type;
    data0 = readl(base_addr+S3C2410_ADCDAT0);
    data1 = readl(base_addr+S3C2410_ADCDAT1);
    ts.is_down = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
                        (!(data1 & S3C2410_ADCDAT0_UPDOWN));
    event_type = ts.is_down ? 'D' : 'U';
    if (unlikely(__kfifo_put(ts.event_fifo, (unsigned char *)&event_type,
             sizeof(int)) != sizeof(int))) /* should not happen */
        printk(KERN_ERR __FILE__": stylus_updown lost event!\n");
    if (ts.is_down)
        s3c2410_ts_start_adc_conversion();//down
    else
        writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);//up
    mod_timer(&event_send_timer, jiffies + 1);//延时
    return IRQ_HANDLED;
}
adc中断处理函数:
static irqreturn_t stylus_action(int irq, void *dev_id)
{//新加入进来的机制,通过filter来处理adc转换得到的数据,并用过fifo来存储
    int buf[3];
    /* Grab the ADC results. */
    buf[1] = readl(base_addr + S3C2410_ADCDAT0) &
               S3C2410_ADCDAT0_XPDATA_MASK;
    buf[2] = readl(base_addr + S3C2410_ADCDAT1) &
               S3C2410_ADCDAT1_YPDATA_MASK;
    switch (ts_filter_chain_feed(ts.chain, &buf[1])) {
    case 0:
        /* The filter wants more points. */
        s3c2410_ts_start_adc_conversion();
        return IRQ_HANDLED;
    case 1:
        /* We have a point from the filters or no filtering enabled. */
        buf[0] = 'P';
        break;
    default:
        printk(KERN_ERR __FILE__
               ":%d Invalid ts_filter_chain_feed return value.\n",
               __LINE__);
    case -1:
        /* Error. Ignore the event. */
        ts_filter_chain_clear(ts.chain);
        writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC);
        return IRQ_HANDLED;
    };
    if (unlikely(__kfifo_put(ts.event_fifo, (unsigned char *)buf,
             sizeof(int) * 3) != sizeof(int) * 3))
        printk(KERN_ERR __FILE__":stylus_action bug.\n");
    writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC);
    mod_timer(&event_send_timer, jiffies + 1);
    return IRQ_HANDLED;
}


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/97285/showart_1967792.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP