嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之触摸屏驱动
2010-12-05 22:20
621 查看
嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便。如有错误之处,谢请指正。
一、移植环境
主 机:VMWare--Fedora 9
开发板:Mini2440--64MB Nand
编译器:arm-linux-gcc-4.3.2
二、移植步骤
1. 准备驱动源码。因为linux-2.6.30.4内核中没有提供合适的ADC驱动和触摸屏驱动,所以这里就直接用友善提供的驱动
s3c24xx-adc.h
mini2440_adc.c
s3c2410_ts.c
2. 部署驱动源代码到内核中
3. 将驱动模块添加到内核配置文件中
4. 修改内核配置选项
5. 编译内核并下载到开发板上,从启动信息可以看到触摸屏驱动加载成功
6. 创建触摸屏设备节点并测试。由启动信息得知触摸屏设备为输入类设备,如下图操作可以得知输入类设备的主设备号为13,又查看总线的具体输入设备可得知该设备的详细信息,根据这些信息我们建立好设备节点,设置内核调试级别为8,然后打开触摸屏设备,点击触摸屏,此时可以看到打印的坐标信息,即触摸屏可正常使用了
文章出处:http://hbhuanggang.cublog.cn
一、移植环境
主 机:VMWare--Fedora 9
开发板:Mini2440--64MB Nand
编译器:arm-linux-gcc-4.3.2
二、移植步骤
1. 准备驱动源码。因为linux-2.6.30.4内核中没有提供合适的ADC驱动和触摸屏驱动,所以这里就直接用友善提供的驱动
s3c24xx-adc.h
#ifndef _S3C2410_ADC_H_ #define _S3C2410_ADC_H_ #define ADC_WRITE(ch, prescale) ((ch)<<16|(prescale)) #define ADC_WRITE_GETCH(data) (((data)>>16)&0x7) #define ADC_WRITE_GETPRE(data) ((data)&0xff) #endif /* _S3C2410_ADC_H_ */ |
#include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/init.h> #include <linux/serio.h> #include <linux/delay.h> #include <linux/clk.h> #include <asm/io.h> #include <asm/irq.h> #include <asm/uaccess.h> #include <mach/regs-clock.h> #include <plat/regs-timer.h> #include <plat/regs-adc.h> #include <mach/regs-gpio.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include "s3c24xx-adc.h" #undef DEBUG //#define DEBUG #ifdef DEBUG #define DPRINTK(x...) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);} #else #define DPRINTK(x...) (void)(0) #endif #define DEVICE_NAME "adc" static void __iomem *base_addr; typedef struct { wait_queue_head_t wait; int channel; int prescale; }ADC_DEV; DECLARE_MUTEX(ADC_LOCK); static int OwnADC = 0; static ADC_DEV adcdev; static volatile int ev_adc = 0; static int adc_data; static struct clk *adc_clock; #define ADCCON (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON)) //ADC control #define ADCTSC (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC)) //ADC touch screen control #define ADCDLY (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY)) //ADC start or Interval Delay #define ADCDAT0 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0)) //ADC conversion data 0 #define ADCDAT1 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1)) //ADC conversion data 1 #define ADCUPDN (*(volatile unsigned long *)(base_addr + 0x14)) //Stylus Up/Down interrupt status #define PRESCALE_DIS (0 << 14) #define PRESCALE_EN (1 << 14) #define PRSCVL(x) ((x) << 6) #define ADC_INPUT(x) ((x) << 3) #define ADC_START (1 << 0) #define ADC_ENDCVT (1 << 15) #define START_ADC_AIN(ch, prescale) / do{ / ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; / ADCCON |= ADC_START; / }while(0) static irqreturn_t adcdone_int_handler(int irq, void *dev_id) { if (OwnADC) { adc_data = ADCDAT0 & 0x3ff; ev_adc = 1; wake_up_interruptible(&adcdev.wait); } return IRQ_HANDLED; } static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos) { char str[20]; int value; size_t len; if (down_trylock(&ADC_LOCK) == 0) { OwnADC = 1; START_ADC_AIN(adcdev.channel, adcdev.prescale); wait_event_interruptible(adcdev.wait, ev_adc); ev_adc = 0; DPRINTK("AIN[%d] = 0x%04x, %d/n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0); value = adc_data; sprintf(str,"%5d", adc_data); copy_to_user(buffer, (char *)&adc_data, sizeof(adc_data)); OwnADC = 0; up(&ADC_LOCK); } else { value = -1; } len = sprintf(str, "%d/n", value); if (count >= len) { int r = copy_to_user(buffer, str, len); return r ? r : len; } else { return -EINVAL; } } static int s3c2410_adc_open(struct inode *inode, struct file *filp) { init_waitqueue_head(&(adcdev.wait)); adcdev.channel=0; adcdev.prescale=0xff; DPRINTK( "adc opened/n"); return 0; } static int s3c2410_adc_release(struct inode *inode, struct file *filp) { DPRINTK( "adc closed/n"); return 0; } static struct file_operations dev_fops = { owner: THIS_MODULE, open: s3c2410_adc_open, read: s3c2410_adc_read, release: s3c2410_adc_release, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; base_addr=ioremap(S3C2410_PA_ADC,0x20); if (base_addr == NULL) { printk(KERN_ERR "Failed to remap register block/n"); return -ENOMEM; } adc_clock = clk_get(NULL, "adc"); if (!adc_clock) { printk(KERN_ERR "failed to get adc clock source/n"); return -ENOENT; } clk_enable(adc_clock); /* normal ADC */ ADCTSC = 0; ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev); if (ret) { iounmap(base_addr); return ret; } ret = misc_register(&misc); printk (DEVICE_NAME"/tinitialized/n"); return ret; } static void __exit dev_exit(void) { free_irq(IRQ_ADC, &adcdev); iounmap(base_addr); if (adc_clock) { clk_disable(adc_clock); clk_put(adc_clock); adc_clock = NULL; } misc_deregister(&misc); } EXPORT_SYMBOL(ADC_LOCK); module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("FriendlyARM Inc."); |
#include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/init.h> #include <linux/serio.h> #include <linux/delay.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <asm/io.h> #include <asm/irq.h> #include <plat/regs-adc.h> #include <mach/regs-gpio.h> /* For ts.dev.id.version */ #define S3C2410TSVERSION 0x0101 #define WAIT4INT(x) (((x)<<8) | / S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | / S3C2410_ADCTSC_XY_PST(3)) #define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | / S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0)) static char *s3c2410ts_name = "s3c2410 TouchScreen"; static struct input_dev *dev; static long xp; static long yp; static int count; extern struct semaphore ADC_LOCK; static int OwnADC = 0; static void __iomem *base_addr; 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); } 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)); if (updown) { if (count != 0) { long tmp; tmp = xp; xp = yp; yp = tmp; xp >>= 2; yp >>= 2; #ifdef CONFIG_TOUCHSCREEN_MY2440_DEBUG struct timeval tv; do_gettimeofday(&tv); printk(KERN_DEBUG "T: %06d, X: %03ld, Y: %03ld/n", (int)tv.tv_usec, xp, yp); #endif input_report_abs(dev, ABS_X, xp); input_report_abs(dev, ABS_Y, yp); input_report_key(dev, BTN_TOUCH, 1); input_report_abs(dev, ABS_PRESSURE, 1); input_sync(dev); } xp = 0; yp = 0; count = 0; iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC); iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON); } else { count = 0; input_report_key(dev, BTN_TOUCH, 0); input_report_abs(dev, ABS_PRESSURE, 0); input_sync(dev); iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC); if (OwnADC) { OwnADC = 0; up(&ADC_LOCK); } } } static struct timer_list touch_timer = TIMER_INITIALIZER(touch_timer_fire, 0, 0); static irqreturn_t stylus_updown(int irq, void *dev_id) { unsigned long data0; unsigned long data1; int updown; if (down_trylock(&ADC_LOCK) == 0) { OwnADC = 1; data0 = ioread32(base_addr+S3C2410_ADCDAT0); data1 = ioread32(base_addr+S3C2410_ADCDAT1); updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN)); if (updown) { touch_timer_fire(0); } else { OwnADC = 0; up(&ADC_LOCK); } } return IRQ_HANDLED; } static irqreturn_t stylus_action(int irq, void *dev_id) { unsigned long data0; unsigned long data1; if (OwnADC) { data0 = ioread32(base_addr+S3C2410_ADCDAT0); data1 = ioread32(base_addr+S3C2410_ADCDAT1); xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK; yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK; count++; if (count < (1<<2)) { iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC); iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON); } else { mod_timer(&touch_timer, jiffies+1); iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC); } } return IRQ_HANDLED; } static struct clk *adc_clock; static int __init s3c2410ts_init(void) { struct input_dev *input_dev; adc_clock = clk_get(NULL, "adc"); if (!adc_clock) { printk(KERN_ERR "failed to get adc clock source/n"); return -ENOENT; } clk_enable(adc_clock); base_addr=ioremap(S3C2410_PA_ADC,0x20); if (base_addr == NULL) { printk(KERN_ERR "Failed to remap register block/n"); return -ENOMEM; } /* Configure GPIOs */ s3c2410_ts_connect(); iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),/ base_addr+S3C2410_ADCCON); iowrite32(0xffff, base_addr+S3C2410_ADCDLY); iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC); /* Initialise input stuff */ input_dev = input_allocate_device(); if (!input_dev) { printk(KERN_ERR "Unable to allocate the input device !!/n"); return -ENOMEM; } dev = input_dev; dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS); dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH); input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0); input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0); input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0); dev->name = s3c2410ts_name; dev->id.bustype = BUS_RS232; dev->id.vendor = 0xDEAD; dev->id.product = 0xBEEF; dev->id.version = S3C2410TSVERSION; /* Get irqs */ if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM, "s3c2410_action", 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", dev)) { printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !/n"); iounmap(base_addr); return -EIO; } printk(KERN_INFO "%s successfully loaded/n", s3c2410ts_name); /* All went ok, so register to the input system */ input_register_device(dev); return 0; } static void __exit s3c2410ts_exit(void) { disable_irq(IRQ_ADC); disable_irq(IRQ_TC); free_irq(IRQ_TC,dev); free_irq(IRQ_ADC,dev); if (adc_clock) { clk_disable(adc_clock); clk_put(adc_clock); adc_clock = NULL; } input_unregister_device(dev); iounmap(base_addr); } module_init(s3c2410ts_init); module_exit(s3c2410ts_exit); |
#cp -f s3c24xx-adc.h mini2440_adc.c /linux-2.6.30.4/drivers/char/ #cp -f s3c2410_ts.c /linux-2.6.30.4/drivers/input/touchscreen/ |
3. 将驱动模块添加到内核配置文件中
#gedit linux-2.6.30.4/drivers/char/Kconfig //添加如下内容 |
config MY2440_ADC bool "ADC device for my2440" default y |
#gedit linux-2.6.30.4/drivers/char/Makefile //添加如下内容 |
obj-$(CONFIG_MY2440_ADC) += mini2440_adc.o |
#gedit linux-2.6.30.4/drivers/input/touchscreen/Kconfig //添加如下内容 |
config TOUCHSCREEN_MY2440 tristate "MY2440 touchscreens input driver" default y config TOUCHSCREEN_MY2440_DEBUG boolean "MY2440 touchscreens input driver debug messages" depends on TOUCHSCREEN_MY2440 help Select this if you want debug messages |
#gedit linux-2.6.30.4/drivers/input/touchscreen/Makefile //添加如下内容 |
obj-$(CONFIG_TOUCHSCREEN_MY2440) += s3c2410_ts.o |
Device Drivers ---> Input device support ---> (240) Horizontal screen resolution (320) Vertical screen resolution [*] Touchscreens ---> <*> MY2440 touchscreens input driver (NEW) [*] MY2440 touchscreens input driver debug messages Character devices ---> [*] ADC device for my2440 (NEW) |
6. 创建触摸屏设备节点并测试。由启动信息得知触摸屏设备为输入类设备,如下图操作可以得知输入类设备的主设备号为13,又查看总线的具体输入设备可得知该设备的详细信息,根据这些信息我们建立好设备节点,设置内核调试级别为8,然后打开触摸屏设备,点击触摸屏,此时可以看到打印的坐标信息,即触摸屏可正常使用了
文章出处:http://hbhuanggang.cublog.cn
相关文章推荐
- 嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之触摸屏驱动
- 嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之UDA1341声卡驱动
- 嵌入式开发七:实验二:本人实践:嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之内核
- 嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之UDA1341声卡驱动
- 嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之文件系统
- Linux-2.6.30.4在2440上的移植之触摸屏驱动
- 嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之内核
- 嵌入式开发二:mini2440开发-内核抑制-嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之内核
- 嵌入式开发三:mini2440开发-内核抑制-嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之内核
- 实验一:嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之内核
- 扬创2440 uboot移植(1)--基于《嵌入式Linux之我行--u-boot-2009.08在2440上的移植详解》
- 嵌入式Linux之我行——2440按键驱动实例开发详解(带去抖动)
- Linux-2.6.30.4在2440上的移植之MMC/SD卡驱动
- 嵌入式Linux之我行——Linux-2.6.30.4在2440上的移植之文件系统
- Linux-2.6.30.4在2440上的移植之MMC/SD卡驱动 ~
- linux2.6.30.4 内核移植(2)触摸屏驱动
- 扬创2440 uboot移植(1)--基于《嵌入式Linux之我行--u-boot-2009.08在2440上的移植详解》
- 【转】嵌入式Linux之我行——LCD背光驱动在2440上的实例开发
- 扬创uboot移植(2)--基于《嵌入式Linux之我行--u-boot-2009.08在2440上的移植详解》
- 嵌入式Linux之我行——S3C2440上触摸屏驱动实例开发讲解