Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48704
  • 博文数量: 26
  • 博客积分: 1175
  • 博客等级: 少尉
  • 技术积分: 300
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-14 19:16
文章分类
文章存档

2011年(1)

2010年(25)

我的朋友

分类: 嵌入式

2010-03-29 20:33:30

ADC和s3c2440 触摸屏驱动

10 位 CMOS 的 ADC(模数转换器)是有 8 通道模拟输入的循环类型设备。其转换模拟输入
信号到 10 位的数字编码,最大的转换率是在 2.5MHz 转换时钟下达到 500KSPS。AD 转换
器支持片上采样和保持功能及掉电模式。
触摸屏接口可以控制或选择触摸屏触点用于 XY 坐标的转换。触摸屏接口包括触摸触点控
制逻辑和有中断产生逻辑的 ADC 接口逻辑。

 触摸屏接口模式
(1) 正常转换模式
单个转换模式可能多数是使用在通用目的的ADC转换。该模式可以通过设置
ADCCON(ADC控制寄存器)来初始化并且完成对ADCDAT0 的读写操作(ADC数据寄存
器 0)。

(2) 分离XY坐标转换模式
触摸屏控制器可以在两种转换模式中的一种模式下操作。分离的XY坐标转换模式由以下方
法操作。X坐标模式写X坐标转换数据到ADCDAT0,触摸屏接口产生中断源到中断控制
器。Y坐标模式写Y坐标转换数据到ADCDAT1,触摸屏接口产生中断源到中断控制器

(3) 自动(连续)XY坐标转换模式
自动(连续)XY坐标转换模式是如下操作,触摸屏控制器连续的转换触摸X坐标和Y坐
标。在触摸控制器写X测量数据到ADCDAT0 且写Y测量数据到ADCDAT1 后,触摸屏接口
产生中断源到自动坐标转换模式下的中断控制器。

(4) 等待中断模式
当光标按下,触摸屏控制器产生中断信号(INT_TC)。触摸屏控制器的等待中断模式必须
设定为触摸屏接口中触点的状态(XP、XM、YP、YM)。
在触摸屏控制器产生中断信号(INT_TC),等待中断模式必须被清除。(XY_PST设置到
无操作模式)

首先就是要初始化了。
     //configure TS
     ADCCON  = (1 << 14) | (25 << 6);
     ADCDLY  = 10000;

我们设的就是等待中断模式。说明要求设置的位
Touch Screen Controller generates interrupt (INT_TC) signal when the Stylus is down. Waiting for Interrupt Mode
setting value is rADCTSC=0xd3; // XP_PU, XP_Dis, XM_Dis, YP_Dis, YM_En.

    //    wait for down  YM en       YP dis     XM dis     XP dis    XP PU en  wait
    ADCTSC  = (0 << 8) | (1 << 7) | ( 1 << 6) | (0 << 5) | (1 << 4) | (0 << 3) | 0x3;
     //    wait for up  YM en       YP dis     XM dis     XP dis    XP PU en  wait
    ADCTSC  = (1 << 8) | (1 << 7) | ( 1 << 6) | (0 << 5) | (1 << 4) | (0 << 3) | 0x3;

基本的中断和转换过程是这样的。
ts中断进入-》ADC中断,
down中断 等ADC中断。
ADC中断等up中断
up中断等down中断
在ADC中断的时候就是自动处理X,Y坐标的时候

由于涉及到始终频率。所以函数在PROBE的时候要设好时钟!
在内核也要申请相关的中断源。由于中断不能处理太长的问题。所以这次用了工作队列来完成转换和打印的工作

有些地方是多余的。是自己加上去的。作用并不大
代码如下。只列出了重要的函数。由于采集到的坐标还没作相对的校验。你可以用ts_lib校验。或者3点成一个面写个算法校验一下
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

MODULE_LICENSE("GPL");
MODULE_AUTHOR("KK");

struct lcd {
    struct cdev dev;
    struct work_struct work;
    struct work_struct work1;
    dev_t no;
    int irq;
    int irq1;
    unsigned char *lcd_base;
    unsigned long adccon;
    unsigned long adctsc;
    unsigned long adcdly;
    unsigned long adcdat0;
    unsigned long adcdat1;
    unsigned long adcupnd;
    void (*on) (struct lcd * lcd);
    void (*off) (struct lcd * lcd);

};
struct lcd my_lcd;
void lcd_on(struct lcd *lcd)
{
    unsigned int value;
    value = ioread32(lcd->adccon);
    value = (1 << 14) | (25 << 6);
    iowrite32(value, lcd->adccon);

    value = ioread32(lcd->adcdly);
    value = 10000;
    iowrite32(value, lcd->adcdly);

    value = ioread32(lcd->adctsc);
    value =
        (0 << 8) | (1 << 7) | (1 << 6) | (0 << 5) | (1 << 4) | (0 << 3) |
        0x3;
    iowrite32(value, lcd->adctsc);

}

struct file_operations my_lcd_ops = {
    .open = lcd_open,
    .release = my_release,
};

int my_remove(struct device *dev);
int my_probe(struct device *dev);


struct device_driver my_driver = {
    .name = "s3c2410-ts",
    .probe = my_probe,
    .remove = my_remove,
    .bus = &platform_bus_type,

};
irqreturn_t irq1_handler(int irq, void *dev_id, struct pt_regs *regs)
{
    struct lcd *tmp = dev_id;

    schedule_work(&tmp->work1);
    return IRQ_HANDLED;


}

irqreturn_t irq0_handler(int irq, void *dev_id, struct pt_regs * regs)
{
    struct lcd *tmp = dev_id;

    schedule_work(&tmp->work);
    return IRQ_HANDLED;


}

void work_handler1(void *data)
{
    struct lcd *tmp = data;
    unsigned int val;
    unsigned int val1;
    unsigned int val2;
    val = ioread32(tmp->adcdat0);
    val1 = ioread32(tmp->adcdat1);
    printk("x = %d ,y = %d \n", val & 0x3ff, val1 & 0x3ff);
       
        input_report_abs(&tmp->dev, ABS_X, val & 0x3ff);  
        input_report_abs(&tmp->dev, ABS_Y,  val1 & 0x3ff);
        input_report_key(&tmp->dev, ABS_PRESSURE, 1);
        input_sync(&tmp->dev);
                                                                                                           
    val2 = ioread32(tmp->adctsc);
    val2 =
        (0 << 8) | (1 << 7) | (1 << 6) | (0 << 5) | (1 << 4) | (0 << 3) |
        0x3;
    iowrite32(val2, tmp->adctsc);


}
void work_handler(void *data)
{
    struct lcd *tmp = data;
    unsigned int val;
    val = ioread32(tmp->adcdat0);
    if (val & (1 << 15)) {
        printk("up\n");
        val = ioread32(tmp->adctsc);
        val =
            (0 << 8) | (1 << 7) | (1 << 6) | (0 << 5) | (1 << 4) | (0 << 3)
            | 0x3;
        iowrite32(val, tmp->adctsc);
    } else {
        printk("down\n");
        val = ioread32(tmp->adctsc);
        val = (1 << 2) | 0x0;
        iowrite32(val, tmp->adctsc);
        val = ioread32(tmp->adccon);
        val |= 1;
        iowrite32(val, tmp->adccon);
    }
}

struct class *test_class = NULL;
struct class_device *test_class_device = NULL;

struct clk *cl = 0;

int my_probe(struct device *dev)
{
    int ret;
    printk("test_xxx\n");

    cl = clk_get(NULL, "adc");

    clk_use(cl);
    clk_enable(cl);

#if 1
    test_class = class_create(THIS_MODULE, "KK");
    if (IS_ERR(test_class)) {
        return PTR_ERR(test_class);
    }

    test_class_device =
        class_device_create(test_class, my_lcd.no, NULL, "test");
    if (IS_ERR(test_class_device)) {
        return PTR_ERR(test_class_device);
    }
    my_lcd.no = MKDEV(27, 0);

#endif

    ret = register_chrdev_region(my_lcd.no, 1, "led");
    if (ret) {
        printk("register char device number failed.\n");
        return ret;
    }
    my_lcd.on = lcd_on;
    my_lcd.off = lcd_off;
    cdev_init(&my_lcd.dev, &my_lcd_ops);
    cdev_add(&my_lcd.dev, my_lcd.no, 1);
    char *p;
    p = request_mem_region(0x58000000, SZ_1M, "lcd");
    if (IS_ERR(p)) {
        printk("request io mem failed.\n");
        unregister_chrdev_region(my_lcd.no, 1);
        return PTR_ERR(p);
    }
    my_lcd.irq = IRQ_TC;
    my_lcd.irq1 = IRQ_ADC;
    my_lcd.lcd_base = ioremap_nocache(0x58000000, SZ_1M);
    /* ioremap_cahced */
    my_lcd.adccon = my_lcd.lcd_base;
    my_lcd.adctsc = my_lcd.lcd_base + 0x04;
    my_lcd.adcdly = my_lcd.lcd_base + 0x08;
    my_lcd.adcdat0 = my_lcd.lcd_base + 0x0c;
    my_lcd.adcdat1 = my_lcd.lcd_base + 0x10;
    my_lcd.adcupnd = my_lcd.lcd_base + 0x14;

    INIT_WORK(&my_lcd.work, work_handler, &my_lcd);
    INIT_WORK(&my_lcd.work1, work_handler1, &my_lcd);

    request_irq(my_lcd.irq, irq0_handler, SA_SAMPLE_RANDOM, "irq0",
                &my_lcd);
    request_irq(my_lcd.irq1, irq1_handler, SA_SAMPLE_RANDOM, "irq1",
                &my_lcd);

        ts.evbit[0] = BIT(EV_ABS) | BIT(EV_SYN);
               
        set_bit(EV_ABS, ts.evbit);
        set_bit(EV_SYN, ts.evbit);


        input_set_abs_params(&ts, ABS_X, 0, 0x3ff, 0, 0);
        input_set_abs_params(&ts, ABS_Y, 0, 0x3ff, 0, 0);
        input_set_abs_params(&ts, ABS_PRESSURE, 0, 1, 0, 0);


        input_register_device(&ts);

    return 0;
}
int my_remove(struct device *dev)
{
    printk("remove .... \n");
    cdev_del(&my_lcd);
    unregister_chrdev_region(my_lcd.no, 1);
    class_device_destroy(test_class, my_lcd.no);
    class_destroy(test_class);
    clk_disable(cl);
    clk_unuse(cl);
    clk_put(cl);

    return 0;
}
int test_init(void)
{
    driver_register(&my_driver);
    return 0;
}

module_init(test_init);
module_exit(test_exit);
 
阅读(667) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~