《Linux驱动:s3c2410/s3c2440 ts驱动分析--终结篇》

发布者:清新天空最新更新时间:2024-07-09 来源: elecfans关键字:Linux驱动  s3c2410  s3c2440 手机看文章 扫描二维码
随时随地手机看文章

一,前言

前面结合“平台总线-设备-驱动”模型分析了ts(触摸)驱动的加载过程,现在进入驱动程序分析下其具体的实现。涉及到输入子系统详解、input输入子系统核心层程序分析、evdev输入子系统事件处理层程序分析、ts输入子系统设备驱动层程序分析、字符设备驱动分析、主设备号和次设备号的使用、以及s3c2440的ADC转换和触摸控制器的操作。

二,涉及的寄存器


三,调用probe函数

根据上一篇的分析,驱动层通过platform_driver_register注册后,会调用到该驱动层的probe函数。

四,s3c2410ts_probe函数分析

4.1 硬件寄存器设置

4.1.1 获取设备参数

struct s3c2410_ts_mach_info *info;


    info = ( struct s3c2410_ts_mach_info *)pdev->dev.platform_data;


    /*

    info

        .delay = 10000,   // ADC conversion start delay value

        .presc = 49,      // ADC clk

        .oversampling_shift = 2, // 采样精度

    */


    if (!info)

    {

        printk(KERN_ERR 'Hm... too bad : no platform data for tsn');

        return -EINVAL;

    }

4.1.2 使能ADC

adc_clock = clk_get(NULL, 'adc');

if (!adc_clock) {

    printk(KERN_ERR 'failed to get adc clock sourcen');

    return -ENOENT;

}

clk_enable(adc_clock);

4.1.3 获取ADC & TOUCH SCREEN 寄存器

static inline void s3c2410_ts_connect(void)

{

    s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);

    s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);

    s3c2410_gpio_cfgpin(S3C2410_GPG14, S3C2410_GPG14_YMON);

    s3c2410_gpio_cfgpin(S3C2410_GPG15, S3C2410_GPG15_nYPON);

}


{

    .....

    base_addr=ioremap(S3C2410_PA_ADC,0x20);  //#define S3C2410_PA_ADC      (0x58000000)

    if (base_addr == NULL) {

        printk(KERN_ERR 'Failed to remap register blockn');

        return -ENOMEM;

    }


    /* Configure GPIOs */

    s3c2410_ts_connect(); // 设置GPIO功能

    .....

}

4.1.4 设置ADC转换频率

if ((info->presc&0xff) > 0)

        iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(info->presc&0xFF),

                 base_addr+S3C2410_ADCCON);    

// 设置ADC clk 

// A/D converter freq = PCLK/(info->presc+1)  

// 一次adc转换所需时间Conversion time = 1/(A/D converter freq / 5cycles)

4.1.5 设置ADC转换开始的延时时间

因为ADC中断产生后的一段时间内电压还未稳定,如果立即进行ADC转换,那么转换值会有误差,这时就可以通过设置延时时间,待电压稳定后再执行转换以确保数值的准确性。


// 设置ADC conversion start delay value

if ((info->delay&0xffff) > 0)

        iowrite32(info->delay & 0xffff,  base_addr+S3C2410_ADCDLY);

4.1.6 进入等待触摸按下模式

iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);  // 等待触摸按下中断模式

自此,ADC & TOUCH SCREEN 寄存器初始设置完成。

4.2 注册ADC和TC中断

注册TC中断,监测触摸屏的按下和抬起;注册ADC中断,进行ADC转换。


/* Get irqs */

if (request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM | SA_SHIRQ,

                's3c2410_action', ts.dev)) {

    printk(KERN_ERR 's3c2410_ts.c: Could not allocate ts IRQ_ADC !n');

    iounmap(base_addr);

    return -EIO;

}

if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,

                's3c2410_action', ts.dev)) {

    printk(KERN_ERR 's3c2410_ts.c: Could not allocate ts IRQ_TC !n');

    iounmap(base_addr);

    return -EIO;

}

4.2.1 TC中断处理函数 stylus_updown

static irqreturn_t stylus_updown(int irq, void *dev_id)

{

    unsigned long data0;

    unsigned long data1;

    int updown;


    // 读取寄存器DATA0和DATA1获取x,y轴的ADC转换值

    data0 = ioread32(base_addr+S3C2410_ADCDAT0);

    data1 = ioread32(base_addr+S3C2410_ADCDAT1);


    // ADCDAT0 bit[15] 0 为按下,1 为松开 即updown 为true 则按下,为false 则松开

    updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));


    /* TODO we should never get an interrupt with updown set while

     * the timer is running, but maybe we ought to verify that the

     * timer isn't running anyways. */


    if (updown)

    {

        // 如果为按下状态

        touch_timer_fire(0);

    }


    return IRQ_HANDLED;

}

4.2.2 ADC中断处理函数 stylus_action

static irqreturn_t stylus_action(int irq, void *dev_id)

{

    unsigned long data0;

    unsigned long data1;


//  if (bADCForTS) {


        data0 = ioread32(base_addr+S3C2410_ADCDAT0);

        data1 = ioread32(base_addr+S3C2410_ADCDAT1);


        ts.xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;  // 为四次adc转换值的累加

        ts.yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;  // 为四次adc转换值的累加

        ts.count++;


//      bADCForTS = 0;

//      up(&gADClock);

        //  ts.count < 4 ,即四次adc转换值为一次按下的结果                             

        if (ts.count < (1<//              if (!down_trylock(&gADClock)) {

//                  bADCForTS = 1;

                    iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC); // 进入 等待adc 转换模式 

                    iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON); // 开启adc转换,转换在info->delay后进行,转换完成后会产生一个ADC中断

//          }

        } else {


            mod_timer(&touch_timer, jiffies+1); // 启动一个定时器,一个jiffies(系统滴答时间) 后进入定时器处理函数 touch_timer_fire

            iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC); // 同时等待 触摸抬起中断

        }

//  }

    return IRQ_HANDLED;

}

4.2.3 定时器处理函数 touch_timer_fire

static struct timer_list touch_timer =

        TIMER_INITIALIZER(touch_timer_fire, 0, 0);


static void touch_timer_fire(unsigned long data)

{

    unsigned long data0;

    unsigned long data1;

    int updown;


    data0 = ioread32(base_addr+S3C2410_ADCDAT0);

    data1 = ioread32(base_addr+S3C2410_ADCDAT1);


    updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));

    // updown 为true 则按下,为false 则松开


    if (updown) {

        // 处于按下状态的处理


        // 首次按下 产生了四次ADC转换后,才去处理x,y值

        if (ts.count != 0) {

            long tmp;  


            // 横纵坐标转换

            tmp = ts.xp;

            ts.xp = ts.yp;

            ts.yp = tmp;


            ts.xp >>= ts.shift; // 四次adc转换值的平均值为一次按下的结果

            ts.yp >>= ts.shift; // 四次adc转换值的平均值为一次按下的结果


#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG

            {

                struct timeval tv;

                do_gettimeofday(&tv);

                printk(DEBUG_LVL 'T: %06d, X: %03ld, Y: %03ldn', (int)tv.tv_usec, ts.xp, ts.yp);

            }

#endif


            input_report_abs(ts.dev, ABS_X, ts.xp);   // 上报x的坐标

            input_report_abs(ts.dev, ABS_Y, ts.yp);   // 上报y的坐标


            input_report_key(ts.dev, BTN_TOUCH, 1);     // 上报BIN_TOUCH 按下

            input_report_abs(ts.dev, ABS_PRESSURE, 1);  // 上报ABS_PRESSURE 按下

            input_sync(ts.dev);                         // 上报事件完成

        }


        ts.xp = 0;

        ts.yp = 0;

        ts.count = 0;


//      if (!down_trylock(&gADClock)) {

//          bADCForTS = 1;

        iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);  // 进入 等待adc 转换模式 

        iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON); // 开启adc转换,完成后会产生一个ADC中断

//      }

    } else {

        // 松开的处理


        ts.count = 0;


        input_report_key(ts.dev, BTN_TOUCH, 0);   // 上报BIN_TOUCH 松开

        input_report_abs(ts.dev, ABS_PRESSURE, 0);// 上报ABS_PRESSURE 松开

        input_sync(ts.dev);                       // 上报事件完成


        iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);  // 进入等待触摸按下中断

    }

}

4.3 注册到输入子系统

4.3.1 申请input_dev

input_dev = input_allocate_device();


if (!input_dev) {

    printk(KERN_ERR 'Unable to allocate the input device !!n');

    return -ENOMEM;

}

4.3.2 设置input_dev

ts.dev = input_dev;

// 设置产生的事件类型,同步类事件、按键类事件和绝对位移事件

ts.dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);

// 设置某类事件类型中的具体事件

// 按键类事件中的触摸事件

ts.dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);

// 绝对位移类事件中的ABS_X、ABS_Y、压力值的值范围,0x3ff是该ADC转换器是10bit精度的,最大为0x3fff

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); // 只设置有按下和抬起(0,1),没有具体的压力值


ts.dev->private = &ts;

ts.dev->name = s3c2410ts_name;

[1] [2] [3]
关键字:Linux驱动  s3c2410  s3c2440 引用地址:《Linux驱动:s3c2410/s3c2440 ts驱动分析--终结篇》

上一篇:《Linux驱动:s3c2440 lcd 驱动分析》
下一篇:《Linux驱动:s3c2410/s3c2440 ts驱动分析 之二》

推荐阅读最新更新时间:2024-11-02 06:53

LCD基础及S3C2410 LCD控制器
一、超薄平面显示器时代来临 电视机所采用的 CRT(阴极射线管)有着体积大、重量重、尺寸受限等缺点。随着电子科技的发展,对移动显示的要求越来越多,CRT 的先天限制,让其小型化、行动化的理想受到阻碍。这使得开发新一代的显示器技术变得更有其必要! 新一代的显示器讲求几个重点:平面直角,画面显示不变形、轻薄短小耗能少,携带方便且同时要与现有的影像信号技术兼容。目前谈论到超薄型显示器技术,最普及当是 TFT LCD 的应用了,举凡数字相机、笔记型计算机、PDA 等,需要显示复杂信息的电子产品通通少不了它。TFT LCD 技术又包含了,低温多硅晶TFT LCD、反射式TFT LCD 等,多项不同的显示技术,下面我们就要来一探 LCD
[应用]
S3C2440 体系结构图
ARM bank: Arm State 寄存器: Thumb State 寄存器: CPRS 寄存器: 模式控制 M0-M4: PC 值计算: 大小端: 中断向量:
[单片机]
<font color='red'>S3C2440</font> 体系结构图
剖析S3C2410路由器整体结构及原理
0 引言 据预测,到2015年全球路由器市场的规模将达到159亿美元。其中家用路由器的发展尤为迅猛,目前需求最大的地区为北美和欧洲,不过亚洲地区已经成为家用路由器市场增长最快的地区。所以在未来几年,亚洲的家用路由器需求将非常巨大。 传统路由器凭借其低廉的价格在市场上将会继续存在一段时间,但路由器的发展趋势是智能化,网络化,这正是以ARM及MIPS内核为代表的路由器的特点,所以ARM内核路由器将在未来不久的时间内,占据家用路由器市场的一席之地,并且随着ARM内核技术的普及,ARM内核路由器将具有更高的性价比,相比于其他家用路由器将更有竞争力。 1 ARM技术 ARM公司既不生产芯片也不销售芯片,它只出售芯片技术授权。嵌入式A
[单片机]
剖析<font color='red'>S3C2410</font>路由器整体结构及原理
基于S3C2410的氢气浓度监测系统设计
   引言   零碳排放的氢燃料作为一种高效、清洁、可再生的能源,得到了国际能源界的广泛认同。氢气也在石油化工、电子工业、食品工业、航空航天工业等领域有了广泛应用。然而,氢气是一种无色无味、携带极不方便、极易泄漏的气体,在室温和标准大气压下,氢气与空气的混合比例达到4.1%~74.1%时遇明火极易爆炸。为了减小使用氢气的安全隐患,开发出一套安全、可靠、灵敏度高的氢气浓度监测系统具有十分重要的意义。   1 系统总体结构设计   采集到的氢传感信号经过低噪声放大电路进行放大处理,并在低通滤波器滤除信号中的高频噪声。然后,经A/D转换器送入ARM处理器S3C2410,ARM 处理器再调用应用程序对采集到的数据进行数字处理,
[嵌入式]
S3c2410的触摸屏及模数转换
一、触摸屏的几个概念 所谓触摸屏,从市场概念来讲,就是一种人人都会使用的计算机输入设备,或者说是人人都会使用的与计算机沟通的设备。不用学习,人人都会使用,是触摸屏最大的魔力,这一点无论是键盘还是鼠标,都无法与其相比。 从技术原理角度讲,触摸屏是一套透明的绝对寻址系统,首先它必须保证是透明的,因此它必须通过材料科技来解决透明问题,像数字化仪、写字板、电梯开关,它们都不是触摸屏;其次它是绝对坐标,手指摸哪就是哪,不需要第二个动作,不像鼠标,是相对定位的一套系统,我们可以注意到,触摸屏软件都不需要游标,有游标反倒影响用户的注意力,因为游标是给相对定位的设备用的,相对定位的设备要移动到一个地方首先要知道现在在何处,往哪个方向去,每时每刻
[嵌入式]
S3C2440—1.熟悉裸机开发板
一.板载资源介绍 开发板使用了三星的JZ2440V3(基于S3C2440改进的版本),网上有丰富的资源,有助于学习,板载资源如图所示: 需要特别注意以下几点: 一般使用JTAG烧写口来烧写程序,用eop即可 有俩个USB接口,其中USB-SERIAL可以连接开发板与上位机,通过串口进行调试 另外一个USB口,可以用来下载程序 板载2M的 Nor FLASH,可将程序直接烧写在此 板载256M的 Nand FLASH,作为主要的数据存储中心,可以将程序烧写在此 启动方式可以选择:Nor 或 Nand 启动,一般用Nand 二.安装驱动及上位机 入门开始要安装以下这几个: 1.要安装USB串口的驱动以及上位机 2.要安装
[单片机]
<font color='red'>S3C2440</font>—1.熟悉裸机开发板
ARM-Linux S5PV210 UART驱动(3)----串口核心层、关键结构体、接口关系
尽管一个特定的UART设备驱动完全可以按照tty驱动的设计方法来设计,即定义tty_driver并实现tty_operations其中的成员函数,但是Linux已经在文件serial_core.c中实现了UART设备的通用tty驱动层,称为串口核心层,这样,UART驱动的主要任务变成了实现serial_core.c中定义的一组uart_xxx接口而非tty_xxx接口。   uart设备是继tty_driver的又一层封装.实际上uart_driver就是对应tty_driver.在它的操作函数中,将操作转入uart_port.在写操作的时候,先将数据放入一个叫做circ_buf的环形缓存区.然后uart_port从缓存
[单片机]
ARM-<font color='red'>Linux</font> S5PV210 UART<font color='red'>驱动</font>(3)----串口核心层、关键结构体、接口关系
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved