×
单片机 > 单片机程序设计 > 详情

OK6410触摸屏驱动

发布时间:2020-06-08 发布时间:
|

ts.c源码:

#include "linux/module.h"

#include "linux/init.h"

#include "linux/fs.h"

#include "linux/interrupt.h"

#include "linux/irq.h"

#include "linux/sched.h"

#include "linux/pm.h"

#include "linux/sysctl.h"

#include "linux/proc_fs.h"

#include "linux/delay.h"

#include "linux/platform_device.h"

#include "linux/input.h"

#include "linux/io.h"

#include "linux/clk.h"

#include "linux/delay.h"

static struct timer_list ts_timer;

static struct input_dev *ts_dev;

struct adc_regs {

    unsigned long adccon;

    unsigned long adctsc;

    unsigned long adcdly;

    unsigned long adcdat0;

    unsigned long adcdat1;

    unsigned long adcupdn;

    unsigned long adcclrint;

    unsigned long reserved;

    unsigned long adcclrintpndnup;

};

static struct adc_regs *adc_regs;

static void enter_wait_for_pen_down(void)

{

    adc_regs->adctsc = 0xd3;

}

static void enter_wait_for_pen_up(void)

{

    adc_regs->adctsc = 0x1d3;

}

static void enter_measure_xy_mode(void)

{

    adc_regs->adctsc = ((1<<7) | (1<<6) | (1<<4) | (1<<3) | (1<<2));

}

static void start_adc(void)

{

    adc_regs->adccon |= (1<<0);

}

static irqreturn_t ts_pen_down_up_isr(int irq, void *dev_id)

{

    unsigned long data0, data1;

    int down;

    data0 = adc_regs->adcdat0;

    data1 = adc_regs->adcdat1;

    down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));

    

    if (!down)

    {

        //printk("pen up\n");

        enter_wait_for_pen_down();

        // 调用evdev_event: 保存,唤醒 

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);

        input_sync(ts_dev);

    }

    else

    {

        //printk("pen down\n");

        //enter_wait_for_pen_up();

        // 进入"自动测量x/y座标模式" 

        enter_measure_xy_mode();

        

        // 启动ADC 

        start_adc();

    }

    adc_regs->adcupdn   = 0;

    adc_regs->adcclrint = 0;

    adc_regs->adcclrintpndnup = 0;

    return IRQ_HANDLED;

}

static irqreturn_t adc_isr(int irq, void *dev_id)

{

    // 为何不在这里立刻处理ADC到结果?

    // 因为6410的ADC有个缺点: 

    // 当ADC刚完成时, 必须等待若干ms, 

    // 才能读取adcdat0,adcdata1来判断

    // 当前的触摸屏是被按下还是松开

    // 启动定时器, 是为了不在中断处理函数里等待 

    mod_timer(&ts_timer, jiffies + HZ/100);

    enter_wait_for_pen_up();

    adc_regs->adcupdn   = 0;

    adc_regs->adcclrint = 0;

    adc_regs->adcclrintpndnup = 0;

    return IRQ_HANDLED;

}

static irqreturn_t adc_isr_ok_old(int irq, void *dev_id)

{

    int x,y;

    int adcdat0,adcdat1;

    int down;

#if 1 // in auto xy mode, after adc interrupt, have to wait several ms to test up/down  

    udelay(1000);

    udelay(1000);

    udelay(1000);

    udelay(1000);

#endif

    adcdat0 = adc_regs->adcdat0;

    adcdat1 = adc_regs->adcdat1;

    x = adcdat0 & 0xfff;

    y = adcdat1 & 0xfff;

    

    down = (!(adcdat0 & (1<<15))) && (!(adcdat1 & (1<<15)));

    //printk("adcdat0 = 0x%x, adc_dat1 = 0x%x\n", adcdat0, adcdat1);

    if (down)

    {

        //printk("enter_wait_for_pen_up\n");

        enter_wait_for_pen_up();

        //printk("x = %d, y = %d\n", x, y);

        input_event(ts_dev, EV_ABS, ABS_X, x);

        input_event(ts_dev, EV_ABS, ABS_Y, y);

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 1);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 1);

        input_sync(ts_dev);

        // 启动定时器 

        mod_timer(&ts_timer, jiffies + HZ/100);

    }

    else

    {

        //printk("enter_wait_for_pen_down\n");

        enter_wait_for_pen_down();

        

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);

        input_sync(ts_dev);

    }

    adc_regs->adcupdn   = 0;

    adc_regs->adcclrint = 0;

    adc_regs->adcclrintpndnup = 0;

    return IRQ_HANDLED;

}

static void ts_timer_function_ok_old(unsigned long data)

{

    // 如果触摸笔已经松开, 就没必要再次启动ADC 

    // 否则, 启动ADC 

    unsigned long data0, data1;

    int down;

    data0 = adc_regs->adcdat0;

    data1 = adc_regs->adcdat1;

    down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));

    

    if (down)

    {

        enter_measure_xy_mode();

        start_adc();

    }

    else

    {

        enter_wait_for_pen_down();

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);

        input_sync(ts_dev);

    }

}

static void ts_timer_function(unsigned long data)

{

    // 如果触摸笔已经松开, 就没必要再次启动ADC 

    // 否则, 启动ADC 

    unsigned long data0, data1;

    int down;

    int x, y;

    data0 = adc_regs->adcdat0;

    data1 = adc_regs->adcdat1;

    down = (!(data0 & (1<<15))) && (!(data1 & (1<<15)));

    if (down)

    {

        x = data0 & 0xfff;

        y = data1 & 0xfff;

        input_event(ts_dev, EV_ABS, ABS_X, x);

        input_event(ts_dev, EV_ABS, ABS_Y, y);

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 1);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 1);

        input_sync(ts_dev);

        

        enter_measure_xy_mode();

        start_adc();

    }

    else

    {

        enter_wait_for_pen_down();

        input_event(ts_dev, EV_ABS, ABS_PRESSURE, 0);

        input_event(ts_dev, EV_KEY, BTN_TOUCH, 0);

        input_sync(ts_dev);

    }

}

static int ts_init(void)

{

    struct clk *clk;

    // 1. 分配input_dev 

    ts_dev = input_allocate_device();

    

    // 2. 设置 

    // 2.1 能产生哪类事件 

    set_bit(EV_KEY, ts_dev->evbit);

    set_bit(EV_ABS, ts_dev->evbit);

    

    // 2.2 能产生这类事件里的哪些事件 

    set_bit(BTN_TOUCH, ts_dev->keybit);

    input_set_abs_params(ts_dev, ABS_X, 0, 0xfff, 0, 0);

    input_set_abs_params(ts_dev, ABS_Y, 0, 0xfff, 0, 0);

    input_set_abs_params(ts_dev, ABS_PRESSURE, 0, 1, 0, 0);

    

    // 3. 注册 

    input_register_device(ts_dev);

    

    // 4. 硬件相关 

    adc_regs = ioremap(0x7E00B000, sizeof(struct adc_regs));

    clk = clk_get(NULL, "adc");

    clk_enable(clk);  // PCLK_GATE[12]设为1 

    // bit[16]   : 1 = 12-bit A/D conversion

    // bit[14]   : 1 - enable A/D converter prescaler enable

    // bit[13:6] : A/D converter prescaler value,

    //             PCLK=66500000, adcclk=pclk/(n+1)

    //             取值13, adclk=66.5MHz/14=4.75

     

    adc_regs->adccon = (1<<16) | (1<<14) | (65<<6);

    adc_regs->adcdly = 0xffff;

    adc_regs->adcclrintpndnup = 0;

    request_irq(IRQ_TC, ts_pen_down_up_isr, IRQF_SHARED, "pen_down_up", 1);

    request_irq(IRQ_ADC, adc_isr, IRQF_SHARED, "adc", 1);

    init_timer(&ts_timer);

    ts_timer.expires  = 0;

    ts_timer.function = ts_timer_function;

    add_timer(&ts_timer);

    // 进入"wait for interrupt mode", 等待触摸笔按下或松开的模式 

    enter_wait_for_pen_down();

    return 0;

}

static void ts_exit(void)

{

    del_timer(&ts_timer);

    free_irq(IRQ_TC, 1);

    free_irq(IRQ_ADC, 1);

    iounmap(adc_regs);

    input_unregister_device(ts_dev);

    input_free_device(ts_dev);

}

module_init(ts_init);

module_exit(ts_exit);

MODULE_LICENSE("GPL");

====================================================================

Mekefile文件:

KERN_DIR = /home/linux/linux-3.0.1

all:

    make -C $(KERN_DIR) M=`pwd` modules 

clean:

    make -C $(KERN_DIR) M=`pwd` modules clean

    rm -rf modules.order

obj-m += ts.o

=====================================================================

测试:

一、配置内核make menuconfig ARCH=arm 去掉第三张图片中touchscreens选项前的*



若只做这一步,编译内核会提示如下错误:

arch/arm/mach-s3c64xx/built-in.o: In function `smdk6410_machine_init':

/xh/work/linux-3.0.1/arch/arm/mach-s3c64xx/mach-smdk6410.c:1096: undefined reference to `s3c_ts_set_platdata'

arch/arm/mach-s3c64xx/built-in.o:(.init.data+0x26c): undefined reference to `s3c_device_ts'

make: *** [.tmp_vmlinux1] Error 1

[root@IVAN linux-3.0.1]#

二、打开/arch/arm/mach-s3c64xx/mach-smdk6410.c

    搜索 “s3c_ts_set_platdata”和“s3c_device_ts”,并注释掉这两行。

成功……


三、使用新内核启动:

1、编译内核:

make zImage                 //生成内核镜像文件

cp arch/arm/boot/zImage ../../zImage_no_ts

2、把开发板设置为SD卡启动,使用SD卡启动后按空格进入SD卡的u-boot;

3、用SD卡里面的u-boot烧写内核到0x000000200000-0x000000700000 : "Kernel"分区:

tftp 50008000 zImage_no_ts

nand erase 200000 500000

nand write 50008000 200000 500000

4、烧写完成后设置开发版为nand flash启动,使用新内核启动。

四、编译测试(详细可以参考JZ2440触摸屏驱动程序(输入子系统)):

insmod ts.ko

insmod lcd.ko

编译:

tar xzf tslib-1.4.tar.gz

cd tslib

./autogen.sh 

mkdir tmp

echo "ac_cv_func_malloc_0_nonnull=yes" >arm-linux.cache

./configure --host=arm-linux --cache-file=arm-linux.cache --prefix=$(pwd)/tmp

make

make install

set bootargs root=/dev/nfs nfsroot=10.1.0.124:/rootfs ip=10.1.0.126 console=ttySAC0

安装:

cd tmp

cp * -rf 开发板的/

使用:

1.

修改 /etc/ts.conf第1行(去掉#号):

# module_raw input

改为:

module_raw input

2.

export TSLIB_FBDEVICE=/dev/fb0             # LCD

export TSLIB_TSDEVICE=/dev/event2        # 触摸屏

export TSLIB_CALIBFILE=/etc/pointercal

export TSLIB_CONFFILE=/etc/ts.conf

export TSLIB_PLUGINDIR=/lib/ts

export TSLIB_CONSOLEDEVICE=none

测试:

ts_calibrate

ts_test

hexdump /dev/event2





『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多