s3c2410 4X4矩阵键盘驱动

发布者:码字探险最新更新时间:2016-11-25 来源: eefocus关键字:s3c2410  4X4  矩阵键盘驱动 手机看文章 扫描二维码
随时随地手机看文章

//驱动代码如下.主设备号设为232 ,适用GEC2410 十六键矩阵键盘

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include  
#include
#include
#include
#include
#include  
#include  
#include  
#include  
#include
#include
#include
#include

#define S3C2410_GPG11 S3C2410_GPIONO(S3C2410_GPIO_BANKG, 11) // S3C2410_GPG11 undefined in regs-gpio.h


#define DEVICE_NAME "matrix_button" 
#define BUTTON_MAJOR 232

unsigned int s3c2410_gpio_getpin(unsigned int pin)
{
     unsigned long base = S3C2410_GPIO_BASE(pin);
     unsigned long offs = S3C2410_GPIO_OFFSET(pin); 
         return __raw_readl(base + 0x04) & (1<< offs);
}

void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
    unsigned long base = S3C2410_GPIO_BASE(pin);
    unsigned long mask;
    unsigned long con;
    unsigned long flags;
    if(pin        mask=1<    else
        mask =3<< (S3C2410_GPIO_OFFSET(pin)*2);
    local_irq_save(flags);

    con = __raw_readl(base + 0x00);

    con &= ~mask;
    con |= function;

    __raw_writel(con, base + 0x00);

    local_irq_restore(flags);
}

void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
    unsigned long base = S3C2410_GPIO_BASE(pin);
    unsigned long offs = S3C2410_GPIO_OFFSET(pin);
    unsigned long flags;
    unsigned long dat;

    local_irq_save(flags);

    dat = __raw_readl(base + 0x04);
    dat &= ~(1 << offs);
    dat |= to << offs;
    __raw_writel(dat, base + 0x04);

    local_irq_restore(flags);
}

#define EXTINT_OFF (IRQ_EINT4 - 4)

// clear SRCPND&INTPND
void s3c_irq_ack(unsigned int irqno) 
{
    unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
    __raw_writel(bitval, S3C2410_SRCPND);
    __raw_writel(bitval, S3C2410_INTPND);
    return;
}
void s3c_irqext_ack(unsigned int irqno)
{
    unsigned long req;
    unsigned long bit;
    bit = 1UL << (irqno - EXTINT_OFF);
    __raw_writel(bit, S3C2410_EINTPEND);
    req = __raw_readl(S3C2410_EINTPEND);
    if (irqno <= IRQ_EINT7 )
    {
        if ((req & 0xf0) == 0)
        s3c_irq_ack(IRQ_EINT4t7);
    }
    else
    {
        if ((req >> 8) == 0)
        s3c_irq_ack(IRQ_EINT8t23);
    }
    return;
}


// set external interrupt mode, trigger type and gpio registers
int realarm_interrupt_init(unsigned int irq, unsigned int type)
{
    unsigned long gpcon_reg;
    unsigned long gpcon_offset;
    unsigned long extint_reg;
    unsigned long extint_offset;
    unsigned long newvalue = 0;
    unsigned long value;
    if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
    {
        gpcon_reg = S3C2410_GPFCON;
        extint_reg = S3C2410_EXTINT0;
        gpcon_offset = (irq - IRQ_EINT0) * 2;
        extint_offset = (irq - IRQ_EINT0) * 4;
    }
    else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))
    {
        gpcon_reg = S3C2410_GPFCON;
        extint_reg = S3C2410_EXTINT0;
        gpcon_offset = (irq - EXTINT_OFF) * 2;
        extint_offset = (irq - EXTINT_OFF) * 4;
    }
    else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))
    {
        gpcon_reg = S3C2410_GPGCON;
        extint_reg = S3C2410_EXTINT1;
        gpcon_offset = (irq - IRQ_EINT8) * 2;
        extint_offset = (irq - IRQ_EINT8) * 4;
    }
    else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))
    {
        gpcon_reg = S3C2410_GPGCON;
        extint_reg = S3C2410_EXTINT2;
        gpcon_offset = (irq - IRQ_EINT8) * 2;
        extint_offset = (irq - IRQ_EINT16) * 4;
    } else
    {
        return -1;
    }
    /* Set the GPIO to external interrupt mode */
    value = __raw_readl(gpcon_reg);
    value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
    __raw_writel(value, gpcon_reg);
    /* Set the external interrupt to pointed trigger type */
    switch (type)
    {
    case IRQT_NOEDGE:
        printk(KERN_WARNING "No edge setting!\n");
        break;
    case IRQT_RISING:
        newvalue = S3C2410_EXTINT_RISEEDGE;
        break;
    case IRQT_FALLING:
        newvalue = S3C2410_EXTINT_FALLEDGE;
        break;
    case IRQT_BOTHEDGE:
        newvalue = S3C2410_EXTINT_BOTHEDGE;
        break;
    case IRQT_LOW:
        newvalue = S3C2410_EXTINT_LOWLEV;
        break;
    case IRQT_HIGH:
        newvalue = S3C2410_EXTINT_HILEV;
        break;
    default:
        printk(KERN_ERR "No such irq type %d", type);
        return -1;
    }
    value = __raw_readl(extint_reg);
    value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
    __raw_writel(value, extint_reg);
    return 0;
}

 

static struct key_info { 
int irq_no; 
unsigned int gpio_port; 
int function_inp;
int function_eintn; 
}key_info_tab[4]={
        { IRQ_EINT0, S3C2410_GPF0,S3C2410_GPF0_INP,S3C2410_GPF0_EINT0}, 
        { IRQ_EINT2, S3C2410_GPF2,S3C2410_GPF2_INP,S3C2410_GPF2_EINT2}, 
        { IRQ_EINT11,S3C2410_GPG3,S3C2410_GPG3_INP,S3C2410_GPG3_EINT11 }, 
        { IRQ_EINT19,S3C2410_GPG11,S3C2410_GPG11_INP,S3C2410_GPG11_EINT19}};

struct matrix_button
{
    int key_value;
    int ready;
    int open_count;
    wait_queue_head_t buttons_wait;
    struct cdev cdev;
    struct semaphore sem;
};

static struct matrix_button* matrix_button_dev;

static struct output_pin
{
    unsigned int gpio_pin;
    int function_outp;
}output_pin_tab[4]={
    {S3C2410_GPE11,S3C2410_GPE11_OUTP},
    {S3C2410_GPG6,S3C2410_GPG6_OUTP},
    {S3C2410_GPE13,S3C2410_GPE13_OUTP},
    {S3C2410_GPG2,S3C2410_GPG2_OUTP}
};

static int  key_scan(void)
{

    int i,j,k,ret=0;
    for(i=0;i<4;i++)
    {
                
            for(j=0;j<4;j++)
            {
                if(i==j)s3c2410_gpio_setpin(output_pin_tab[j].gpio_pin,0);
                 else s3c2410_gpio_setpin(output_pin_tab[j].gpio_pin,1);
            }
            for(k=0;k<4;k++)
            {
                if(s3c2410_gpio_getpin(key_info_tab[k].gpio_port)==0)
                {
                    ret=i*10+k+1;
                    return ret;
                }
            }
    }    
    return ret;
}

static void port_init(void)
{
    int i;
    for(i=0;i<4;i++)
    {
        s3c2410_gpio_cfgpin(output_pin_tab[i].gpio_pin,output_pin_tab[i].function_outp);
        s3c2410_gpio_setpin(output_pin_tab[i].gpio_pin,0);
        s3c2410_gpio_cfgpin(key_info_tab[i].gpio_port,key_info_tab[i].function_eintn);
        realarm_interrupt_init(key_info_tab[i].irq_no,IRQT_FALLING);
    }
}

static irqreturn_t matrix_button_irq(int irq, void *dev_id, struct pt_regs *reg) 

    struct matrix_button *dev=dev_id;
    struct key_info *k; 
    int i; 
    int found = 0;
    int flags;
    down(&dev->sem); 
    for (i = 0; i < sizeof(key_info_tab)/ sizeof(key_info_tab[0]); i++)
    { 
            k = key_info_tab + i; 
            if (k->irq_no == irq)
            { 
                    found = 1; 
                    break; 
            } 
    } 
    if (!found) 
    { 
        printk(KERN_NOTICE "bad irq %d in button\n", irq); 
        return IRQ_HANDLED; 
    } 
    save_flags(flags); // save CPSR
    cli();     // Close interrupt 
    if(k->irq_no        s3c_irq_ack(k->irq_no);
    else
        s3c_irqext_ack(k->irq_no);
    for(i=0;i    {
        k=key_info_tab+i;
        s3c2410_gpio_cfgpin(k->gpio_port,k->function_inp);
    }
    mdelay(100);
    dev->key_value=key_scan();
    if(dev->key_value==0)
    {
        up(&dev->sem);
        port_init();
        restore_flags(flags);
        return IRQ_HANDLED; 
    }
    dev->ready=1;
    up(&dev->sem);
    wake_up(&dev->buttons_wait);
    port_init();
    restore_flags(flags); 
    return IRQ_HANDLED; 
}


static int request_irqs(struct matrix_button *dev) 

    struct key_info *k; 
    int i; 
    for (i = 0; i < sizeof(key_info_tab) / sizeof(key_info_tab[0]); i++)
    { 
        k = key_info_tab + i;
        if (request_irq(k->irq_no, &matrix_button_irq, SA_INTERRUPT, DEVICE_NAME, dev)) return -1;  
    } 
    return 0; 
}

static void free_irqs(struct matrix_button *dev) 

    struct key_info *k; 
    int i; 
    for (i = 0; i < sizeof(key_info_tab) / sizeof(key_info_tab[0]); i++)
    { 
        k = key_info_tab + i; 
        free_irq(k->irq_no,dev); 
    } 
}

static int matrix_button_read(struct file * filp, char __user * buffer, size_t count, loff_t *f_pos) 

    struct matrix_button *dev=filp->private_data; 
    down(&dev->sem); 
    if(!dev->ready)
       return -EAGAIN;
    copy_to_user(buffer, &dev->key_value, sizeof(int)); 
    dev->ready = 0; 
    up(&dev->sem);
    return count; 
}

static unsigned int matrix_button_poll( struct file *filp, struct poll_table_struct *wait) 

    struct matrix_button *dev=filp->private_data; 
    poll_wait(filp, &dev->buttons_wait, wait); 
    if (dev->ready) 
        return POLLIN;
    else 
        return 0;
}


static int matrix_button_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 

    switch(cmd) { 
    default: 
    return -EINVAL; 
    } 
}

static int matrix_button_open(struct inode *inode,struct file *filp)
{
    int ret;
    struct matrix_button *dev;
    dev=container_of(inode->i_cdev,struct matrix_button,cdev);
    down(&dev->sem);
    filp->private_data=dev;
    if(dev->open_count==0)
    {
        ret = request_irqs(dev); 
        if (ret) 
        {
        cdev_del(&matrix_button_dev->cdev);
        unregister_chrdev_region(MKDEV(BUTTON_MAJOR,0),1);
        kfree(matrix_button_dev);
        printk(DEVICE_NAME " can't request irqs\n"); 
        return ret; 
        }
    }
    dev->open_count++;
    up(&dev->sem);
    return 0;
}

static int matrix_button_release(struct inode *inode,struct file *filp)
{
    struct matrix_button *dev=filp->private_data;
    down(&dev->sem);
    if((dev->open_count--)==1)
        free_irqs(dev);
    up(&dev->sem);
    return 0;
}

static struct file_operations matrix_button_fops = { 
owner: THIS_MODULE, 
ioctl: matrix_button_ioctl, 
poll: matrix_button_poll, 
read: matrix_button_read, 
open: matrix_button_open,
release:matrix_button_release
};

static int __init matrix_button_init(void) 

    int ret; 
    dev_t dev=MKDEV(BUTTON_MAJOR,0);
    ret=register_chrdev_region(dev,1,"matrix_button");
    if(ret<0)
        return ret;
    matrix_button_dev=kmalloc(sizeof(struct matrix_button),GFP_KERNEL);
    memset(matrix_button_dev,0,sizeof(struct matrix_button));
    matrix_button_dev->ready=0;
    matrix_button_dev->key_value=0;
    matrix_button_dev->open_count=0;
    init_waitqueue_head(&matrix_button_dev->buttons_wait);
    init_MUTEX(&matrix_button_dev->sem);    
    cdev_init(&matrix_button_dev->cdev,&matrix_button_fops);
    matrix_button_dev->cdev.owner=THIS_MODULE;
    matrix_button_dev->cdev.ops=&matrix_button_fops;
    port_init();
    ret=cdev_add(&matrix_button_dev->cdev,dev,1);
    if(ret)
        printk(KERN_NOTICE "Error %d",ret); 
    
    return 0; 
}

static void __exit matrix_button_exit(void) 

    cdev_del(&matrix_button_dev->cdev);
    unregister_chrdev_region(MKDEV(BUTTON_MAJOR,0),1);
    kfree(matrix_button_dev);
    free_irqs(matrix_button_dev);  
}

module_init(matrix_button_init); 
module_exit(matrix_button_exit); 
MODULE_LICENSE("GPL");


//以下为测试代码

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include

int main(void) 

    int buttons_fd,i; 
    int key_value; 
    buttons_fd = open("/dev/matrix_button", 0); 
    if (buttons_fd < 0) { 
    perror("open device buttons"); 
    exit(1); 
    } 
    for (;;) 
    { 
        fd_set rds; 
        int ret; 
        FD_ZERO(&rds); 
        FD_SET(buttons_fd, &rds); 
        ret = select(buttons_fd + 1, &rds, NULL, NULL, NULL); 
        if (ret < 0) 
        { 
            perror("select"); 
            exit(1); 
        } 
        if (ret == 0) 
        { 
            printf("Timeout.\n"); 
        } 
        else if (FD_ISSET(buttons_fd, &rds)) 
        { 
            int ret = read(buttons_fd, &key_value, sizeof key_value); 
            if (ret != sizeof key_value) 
            { 
                if (errno != EAGAIN) 
                    perror("read buttons\n"); 
                continue; 
            } 
            else 
            { 
                printf("buttons_value: %d\n", key_value); 
            } 
        } 
    } 
    close(buttons_fd); 
    return 0; 
}


关键字:s3c2410  4X4  矩阵键盘驱动 引用地址:s3c2410 4X4矩阵键盘驱动

上一篇:S3C2410 LED驱动程序
下一篇:s3c2410的Bootloader(Vivi)简介

推荐阅读最新更新时间:2024-03-16 15:22

ARM9系列嵌入式处理器S3C2410系统中LCD驱动开发
  本文以三星公司ARM9内核芯片S3C2410的LCD接口为基础,介绍了在Linux平台上开发嵌入式LCD驱动程序的一般方法。   本文硬件采用三星公司的S3C2410芯片的开发板,软件采用Linux 2.4.19平台,编译器为arm-linux-gcc的交叉编译器,使用640×480分辨率的TFT彩色LCD,通过对其Linux驱动程序进行改写和调试,成功地实现了对该种屏的驱动和显示。   嵌入式驱动的概念   设备驱动程序是操作系统内核和机器硬件之间的接口,设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,
[单片机]
S3c2410软件调试总结(三)
2410启动代码分析 这一章主要对目前广泛流行的2410启动代码进行分析:S3C2410的初始化代码主要涉及到对系统主要模块的配置、运行环境的建立、系统时钟、MMU等模块的配置,下面按执行顺序依次都各个部分进行分析: 程序入口:(ResetHandler) 在程序一开始,首先进行的一些操作主要保证初始化程序能够顺利的运行, 因此主要包括关闭WDT、中断,配置锁相环等。 配置memory接口 memory接口是确保数据访问正确的基本保障,此处主要配置SFR寄存器中0x48000000开始的memory接口寄存器组, 确保每个bank的位宽、访问类型(waitable)以及时序参数正确。如果没有特别的要求,一般来说时序参数
[嵌入式]
s3c2410上搭建QT/Embedded4.8.5开发环境(五)
前面我们已经搭建好了三个不同版本的QT编译环境 ①qt-4.8.5-x11:依赖于x11的qt版本,在PC可以直接 ./ 运行 ②qt-4.8.5-x86:依赖与qvfb的qt版本,在PC机上可以使用 qvfb & , 然后“./ -qws”运行 ③qt-4.8.5-arm:arm上的QT版本,交叉编译后在arm上运行 编译大概花了配置两天半的时间,期间还遇见一些问题,好在全部解决了,但是我们总不能每次搭环境都费这么长时间吧,好在我们还有tar可以使用,我们把最后的编译版本打包备份,这样以后我们使用的时候直接解压缩就可以了 备份qt-4.8.5 tar -cvzf tslib-1.4-arm.tar.gz /o
[单片机]
基于S3C2410开发板的U-BOOT移植解决方案
引言 随着嵌入式系统的日趋复杂,它对大容量数据存储的需求越来越紧迫。而嵌入式设备低功耗、小体积以及低成本的要求,使硬盘无法得到广泛的应用。NAND闪存设备就是为了满足这种需求而迅速发展起来的。目前关于U-BOOT的移植解决方案主要面向的是微处理器中的NOR 闪存,如果能在微处理器上的NAND 闪存中实现U-BOOT的启动,则会给实际应用带来极大的方便。 U-BOOT简介 U-BOOT 支持ARM、 PowerPC等多种架构的处理器,也支持Linux、NetBSD和VxWorks等多种操作系统,主要用来开发嵌入式系统初始化代码bootloader。bootloader是芯片复位后进入操作系统之前执行的一段代码,完成由硬件启动到操
[单片机]
基于<font color='red'>S3C2410</font>开发板的U-BOOT移植解决方案
s3c2410时钟信号:FCLK、HCLK和PCLK
s3c2410 有三个时钟FLCK 、HCLK 和PCLK (这3个时针都是核心时针) s3c2410 芯片有这么一段话: FCLK is used by ARM920T ,内核时钟,主频。 HCLK is used for AHB bus, which is used by the ARM920T, the memory controller, the interrupt controller, the LCD controller, the DMA and USB host block. 也就是为AHB总线上的外设提供时钟信号,包括USB时钟。 AHB总线用于连接高速外设。 PCLK is used for APB bus,
[单片机]
<font color='red'>s3c2410</font>时钟信号:FCLK、HCLK和PCLK
基于ARM处理器的远程参数测量的设计
1 引言 嵌入式系统由于性价比高开发周期短等优点目前得到了迅猛发展,各类基于 ARM 处理器的应用开发更是如火如荼。这里介绍基于 ARM9 嵌入式芯片 S3C2410 构建的测量监控系统,该系统设计方案先进,集成度较高,在实践中得到了广泛的应用。   2. 嵌入式 ARM9 S3C2410X 简介   S3C2410X 是三星公司提供的基于 ARM920T 内核的 32 位 RISC 处理器,它的低功耗、低价格、高性能设计特别适合于手持设备和通用嵌入式应用场合,为降低整个系统的成本,它提供了丰富的内部设备,包括分开的 16KB 指令 Cache 和 16KB 数据 Cache,MMU 虚拟存储器管理,24bbp 模式
[单片机]
基于ARM处理器的远程参数测量的设计
基于S3C2410的GPRS模块的设计
  嵌入式系统就是一个具有特定功能或用途的计算机软硬件结合体,或指装入另一个设备并且控制该设备的专用计算机系统。嵌入式系统的最大特点是其具有目的性和针对性,即每一套嵌入式系统的开发都有其特殊的应用场合与特定功能。嵌入式系统包含硬件和软件两部分:硬件架构以嵌入式处理器为中心,配置 存储器 、I/O设备、通信模块等;软件部分以软件开发平台为核心,向上提供应用编程接口API,向下屏蔽具体硬件特性的板级支持包BSP。嵌入式系统中,软件和硬件紧密配合,协调工作,共同完成系统预定的功能。   GPRS是General Packet Radio Service的简称,即通用无线分组业务。它是基于现在运行的GSM基础上发展的数据业务,类似于固定
[单片机]
基于<font color='red'>S3C2410</font>的GPRS模块的设计
ARM9学习4-S3C2410的启动代码分析-For ADSv1.2
通常,启动代码是指CPU复位后到进入C语言的main函数之前需要执行的那段汇编代码.这是由于C语言程序的运行需要具备一定的条件,比如:分配好外部数据空闿堆栈空间和中断入口等筿另外汇编代码可以更直接的对硬件进行操使效率更高. 通常启动代码是放在2410init.s汇编文件;特殊功能寄存器定义在2410addr.s;Memory Bank 配置在mencfg.s;还有系统的选项等在option.s文件;2410init.s不仅包括复位后执行的代码,还包括CPU进入掉电模式,产生中断等和处理器直接相关的,用汇编实现的代码. ;========================================= ; NAME: 2410IN
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved