免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 5656 | 回复: 11
打印 上一主题 下一主题

[驱动] 6410 矩阵键盘 input类型驱动 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-11-07 15:50 |只看该作者 |倒序浏览
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <mach/map.h>

#include <plat/gpio-cfg.h>
#include <plat/regs-clock.h>
#include <plat/regs-gpio.h>
#include <mach/gpio.h>

#include <plat/gpio-bank-n.h>

#define key1  1
#define key2  2
#define key3  3
#define key4  4
#define key5  5
#define key6  6
#define key7  7
#define key8  8
#define key9  9
#define key10 10
#define key11 11
#define key12 12

MODULE_AUTHOR("liutao");
MODULE_LICENSE("GPL");

unsigned long gpn_virt,gpncon,gpndat;

struct input_dev* button_devp;
static char *name = "my6410_buttons";

struct button_irq_desc{
        int irq;
        int pin;
        int number;
        char *name;
};

int key_code[] = {
        key1,key2,key3,key4,
        key5,key6,key7,key8,
        key9,key10,key11,key12,
};
static struct button_irq_desc button_irqs[] = {
        { IRQ_EINT(0),S3C64XX_GPN(0),  0,  "KEY1"},
        { IRQ_EINT(1),S3C64XX_GPN(1),  1,  "KEY2"},
        { IRQ_EINT(2),S3C64XX_GPN(2),  2,  "KEY3"},
};

static int cval , rval;


/*具体判断是哪个按键按下*/
static void check_key(int Cval,int Rval,int reportval)
{
        printk("key check ....\n");
        if(Cval == 1 )
        {
                switch(Rval){
                        case 1:
                                printk("key1 down...\n");
                                input_report_key(button_devp, key1, reportval);
                                break;
                        case 2:
                                printk("key2 down...\n");
                                input_report_key(button_devp, key2, reportval);
                                break;
                        case 3:
                                printk("key3 down...\n");
                                input_report_key(button_devp, key3, reportval);
                                break;
                        case 4:
                                printk("key4 down...\n");
                                input_report_key(button_devp, key4, reportval);
                                break;
                }
        }
        else if(Cval == 2 )
        {
                switch(Rval){
                        case 1:
                                printk("key5 down...\n");
                                input_report_key(button_devp, key5, reportval);
                                break;
                        case 2:
                                printk("key6 down...\n");
                                input_report_key(button_devp, key6, reportval);
                                break;
                        case 3:
                                printk("key7 down...\n");
                                input_report_key(button_devp, key7, reportval);
                                break;
                        case 4:
                                printk("key8 down...\n");
                                input_report_key(button_devp, key8, reportval);
                                break;
                }
        }
        else if(Cval == 3)
        {
                switch(Rval){
                        case 1:
                                printk("key9 down...\n");
                                input_report_key(button_devp, key9, reportval);
                                break;
                        case 2:
                                printk("key10 down...\n");
                                input_report_key(button_devp, key10, reportval);
                                break;
                        case 3:
                                printk("key11 down...\n");
                                input_report_key(button_devp, key11, reportval);
                                break;
                        case 4:
                                printk("key12 down...\n");
                                input_report_key(button_devp, key12, reportval);
                                break;
                }
        }
}
/*扫描键盘判断是Rval */
static int Scan_Keyboard(void)
{
        printk("key scan...\n");
        //
        //pan duan chu na hang zhihou zai pan duan chu na lie
        //int readval;

        //writel(readl(S3C64XX_GPNDAT),readval);
       
        if((*((unsigned long *)gpndat) & 0x00000080) == 0)       
                cval = 1;
        else if ((*((unsigned long *)gpndat) & 0x00000200) == 0)
                cval = 2;
        else if        ((*((unsigned long *)gpndat) & 0x00000800) == 0)
            cval = 3;
        else if ((*((unsigned long *)gpndat) & 0x00020001) == 0)
                cval = 4;
        else{
                printk("the key is unknown..\n");
                return -1;
        }
        return 0;
}

/*案件中断函数*/
static irqreturn_t  button_interrupt(int irq, void* dev_id)
{

        struct button_irq_desc *button_irqs = (struct button_irq_desc*)dev_id;
        int updown,retval;
       
        updown = readl(S3C64XX_GPNDAT) & ( 0x1 << button_irqs->number);
        retval = updown ? 0 : 1;
       
        switch(button_irqs->irq)
        {
                case IRQ_EINT(0):
                        rval = 1;
                        break;
                case IRQ_EINT(1):
                        rval = 2;
                        break;
                case IRQ_EINT(2):
                        rval = 3;
                        break;
                default:
                        break;
        }   
        Scan_Keyboard();
        check_key(cval,rval,retval);

        input_sync(button_devp);
        return IRQ_RETVAL(IRQ_HANDLED);

}
/*GPN0-GPN2 input  |||| GPN4---6 和 GPN9 output  */
static int port_init(void)
{
        gpn_virt = ioremap(0x7f008000,SZ_4K);
        gpncon = gpn_virt + 830;
        gpndat = gpn_virt + 834;

        *((unsigned long *)gpncon) &= ~0xffffffff;
        *((unsigned long *)gpncon) |=  0xfff7d5c0; //GPN(4-6 9 output) -> GPN(0-2 input)

        return 0;
}
/*申请中断*/
static int Request_Irq(void)
{
        int err = 0;
        int i;
        for(i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
        {
                err = request_irq(button_irqs[i].irq, button_interrupt, IRQ_TYPE_EDGE_BOTH, button_irqs[i].name, (void *)&button_irqs[i]);
                if(err)
                {
                        break;
                }
        }

        if(err)
        {
                i--;
                for(; i >= 0; i--)
                {
                        if(button_irqs[i].irq < 0)
                        {
                                continue;
                        }
                        disable_irq(button_irqs[i].irq);
                        free_irq(button_irqs[i].irq, (void*)&button_irqs[i]);
                }
                return -EBUSY;
        }
        set_bit(EV_KEY, button_devp->evbit);
        for(i = 0; i < 12; i++)
        {
                set_bit(key_code[i],button_devp->evbit);
        }

        return 0;
}
/*模块入口函数*/
static int __init button_init(void)
{
        struct input_dev *input_dev;
        int ret;

        port_init();
        input_dev = input_allocate_device();
        if(!input_dev){
                printk(KERN_ERR"Unable to alloc the input device!!\n");
        }

        button_devp = input_dev;
        button_devp->name = name;

        Request_Irq();
        ret = input_register_device(button_devp);
       
        if(ret < 0){
                printk("input_register_device(): failed !! \n");
        }

        return ret;
}
/*模块退出执行*/
static void __exit button_exit(void)
{
        int i;
        for(i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++)
        {
                disable_irq(button_irqs[i].irq);
                free_irq(button_irqs[i].irq, (void*)&button_irqs[i]);
        }
        input_unregister_device(button_devp);
}

module_init(button_init);
module_exit(button_exit);

论坛徽章:
0
2 [报告]
发表于 2011-11-07 16:03 |只看该作者
我一直有个疑惑,input类型的按键,用自己写去抖吗?

你们帮我看看我的Scan_Keyboard函数这么去判断是某一列低电压对吗?

set_bit是什么意思?等input_report_key的时候应用层获得的是什么值?

论坛徽章:
0
3 [报告]
发表于 2011-11-07 16:28 |只看该作者
再把GPIO口设置成输出之后,那个位的电压自动变成高电压,等按下键后变成低电压,在扫描是时,还用每次在某一行上输出一个数吗?

论坛徽章:
0
4 [报告]
发表于 2011-11-07 16:29 |只看该作者
我这是3x4矩阵键盘的

论坛徽章:
2
水瓶座
日期:2013-09-04 15:09:57白羊座
日期:2014-04-17 16:48:13
5 [报告]
发表于 2011-11-08 11:29 |只看该作者
说说你的内核版本。

我记得比较新的内核都帮你把GPIO键盘做好了,你只需要在板子的定义里面加一个按键对应行列的数组就可以了。

具体到mach-s3c6410目录下面找一个有GPIO键盘的板子看下。
去抖动啥的应该也做好了。

论坛徽章:
0
6 [报告]
发表于 2011-11-09 13:50 |只看该作者
回复 5# l2y3n2


    我的内核是linux-2.6.28.6  有吗!

论坛徽章:
2
水瓶座
日期:2013-09-04 15:09:57白羊座
日期:2014-04-17 16:48:13
7 [报告]
发表于 2011-11-09 14:44 |只看该作者
看下你的mach目录下面有没有板子有用到的。

另外如果有的话menuconfig的input device里面应该有类似s3c-keypad之类的设备的。

论坛徽章:
1
水瓶座
日期:2014-10-18 20:17:41
8 [报告]
发表于 2011-11-09 15:18 |只看该作者
高手啊,学习了!

论坛徽章:
0
9 [报告]
发表于 2011-11-10 09:40 |只看该作者
回复 5# l2y3n2


    linux/arch/arm/mach-s3c6410/mach-smdk6410.c是不是这个目录啊!这好像是添GPIO按键的,怎么添加矩阵的呢!

论坛徽章:
2
水瓶座
日期:2013-09-04 15:09:57白羊座
日期:2014-04-17 16:48:13
10 [报告]
发表于 2011-11-10 10:13 |只看该作者
http://lxr.linux.no/linux+v3.1/d ... rd/samsung-keypad.c
这是新内核的samsung通用keypad驱动文件。
http://lxr.linux.no/linux+v3.1/a ... e/plat/keypad.h#L33
要填的结构体应该是这个。

搜了一通好像mach下面的板子都没用到keypad,自己看下那个matrix_keymap_data怎么填吧。

老内核的话可以直接参考下samsung-keypad文件写驱动。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP