Rk3128 按键驱动

一、Rk3128 按键驱动

1、修改配置文件

vim arch/arm/boot/dts/rk3128-box.dts

新增gpio 管脚控制,描述如下,使用了 GPIO3_D2/GPIO3_D3/GPIO3_C1 

        rk3128_key{

                compatible = "rk3128_mykey";

                key_1 = <&gpio3 GPIO_D2 GPIO_ACTIVE_LOW>;

                key_2 = <&gpio3 GPIO_D3 GPIO_ACTIVE_LOW>;

                key_3 = <&gpio3 GPIO_C1 GPIO_ACTIVE_LOW>;

                status = "okay";

        };

2、编写驱动

中断方式

 #define IRQF_TRIGGER_NONE       0x00000000

 #define IRQF_TRIGGER_RISING     0x00000001  上升沿触发

 #define IRQF_TRIGGER_FALLING    0x00000002 下降沿触发  

 #define IRQF_TRIGGER_HIGH       0x00000004  高电平触发

 #define IRQF_TRIGGER_LOW        0x00000008  低电平触发

 

设置中断触发方式

int irq_set_irq_type(unsigned int irq, unsigned int type);

申请中断

Int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,

             const char *name, void *dev);

释放中断

void free_irq(unsigned int, void *);

 

3、按键功能定义

key_1 检测按下和抬起状态,按下状态提交BTN_0,抬起状态提交BTN_1值给安卓

key_2 检测按下状态 按下状态提交BTN_2值给安卓

key_3 检测按下状态 按下状态提交BTN_3值给安卓

 

#define CHECK_DOWN_UP   1  //检测按键按下和抬起状态

#define CHECK_DOWN      0 //检测按下状态

 typedef struct{

          unsigned int irqNum;  //按键中断编号

          unsigned int pin; //按键gpio

          unsigned int reportValue;  // report event value for android 提交按键值给应用

          unsigned int irqmode; //按键中断触发方式

          unsigned short old_down;//防抖,记录触发中断时按键值

          unsigned short type;       //按键检测类型 

    unsigned char keyState;    //记录按键按下还是抬起状态,防止错误提交

          char name[12]; //dts 里面配置的按键名

  }KeyButton;

4完整驱动如下

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

#include 

 

#define DEBUG 1

#ifdef DEBUG

#define dbg(x...) printk(x)

#else

#define dbg(x...) (void)(0)

#endif

 

#define CHECK_DOWN_UP   1

#define CHECK_DOWN      0

 #define KEY_DOWN 0
#define KEY_UP 1

#define BUTTION_SIZE    (sizeof(keybutton)/sizeof(KeyButton))

typedef struct{

        unsigned int irqNum;

        unsigned int pin;

        unsigned int reportValue;       // report event value for android

        unsigned int irqmode;

        unsigned short old_down;

        unsigned short type;

        char name[12]; //dts 里面配置的按键名

}KeyButton;

//定义按键值,和触发方式,默认设置按键为抬起状态

KeyButton keybutton[2]={

                {0,0,BTN_0,IRQF_DISABLED|IRQF_TRIGGER_FALLING,0,CHECK_DOWN_UP,KEY_UP,"key_1"},

                {0,0,BTN_2,IRQF_DISABLED|IRQF_TRIGGER_RISING,0,CHECK_DOWN,KEY_UP,"key_2"},

                {0,0,BTN_3,IRQF_DISABLED|IRQF_TRIGGER_RISING,0,CHECK_DOWN,KEY_UP,"key_3"}

                };

 

static struct platform_device *keypdev=NULL;

static struct input_dev *input_device;

struct timer_list my_timer;

static int old_down=0;

 

static int power_state=0;

 

// 提交按键值给安卓上传,因为是虚拟键值,需要上报1,再上报0

static void report_event(unsigned int event_value)

{

        input_report_key(input_device,event_value, 1);

        input_sync(input_device);

        input_report_key(input_device,event_value, 0);

        input_sync(input_device);

}

//定时器下半部,消抖检测

static void time_function(unsigned long data)
{
int i=0;
KeyButton *Key = (KeyButton *)data;

dbg("%s: interrupt gpio_get_value: %d  old value : %d\n",Key->name,gpio_get_value(Key->pin),Key->old_down);
if(CHECK_DOWN_UP==Key->type)
{
if(gpio_get_value(Key->pin)==1)
{
if(Key->keyState==KEY_DOWN)
{
Key->keyState=KEY_UP;
report_event(Key->reportValue+1);
}
irq_set_irq_type(Key->irqNum, IRQF_DISABLED|IRQF_TRIGGER_FALLING);
dbg("input_report_key up \n");


}else{
if(Key->keyState==KEY_UP)
{
Key->keyState=KEY_DOWN;
report_event(Key->reportValue);
}
irq_set_irq_type(Key->irqNum, IRQF_DISABLED|IRQF_TRIGGER_RISING);
dbg("input_report_key down \n");
}
}else{
if(gpio_get_value(Key->pin)==0)
{
report_event(Key->reportValue);
}
}

}

//设置定时器回调函数

DEFINE_TIMER(my_timer,time_function,0,0);

//中断入口函数

static irqreturn_t key_irqhandler(int irq, void *dev_id)

{

        //dbg("==========Interrupt============\n");

        int i=0;

        for(i=0;i

        {

                if(irq==keybutton[i].irqNum)

                {

                        keybutton[i].old_down=gpio_get_value(keybutton[i].pin);

                        //dbg("keybutton[%d].old_down =%d\n",i,keybutton[i].old_down);

                        my_timer.data=(unsigned long)&(keybutton[i]);

                        mod_timer(&my_timer,jiffies+HZ/10); //100ms

                        break;

                }

        }

        return IRQ_HANDLED;

}

 

 

int wakeupKey_open(struct inode *inode, struct file *filp)

{

    dbg("wakeupKey has been open!\n");

    return -1;

}

 

int wakeupKey_release(struct inode *inode, struct file *filp)

{

    dbg("wakeupKey has not been open yet!\n");

    return -1;

}

 

ssize_t wakeupKey_read(struct file *filp, char *buf,

        size_t count, loff_t fpos)

{

    dbg("wakeupKey read!\n");

    return 0;

}

 

ssize_t wakeupKey_write(struct file *filp, char *buf,

        size_t count, loff_t fpos)

{

    dbg("wakeupKey write!\n");

    return 0;

}

 

int wakeupKey_ioctl(struct inode *inode, struct file *filp,

        unsigned int cmd, unsigned long arg)

{

    dbg("ioctl is called!\n");

    dbg("cmd:%d arg:%d\n", cmd, arg);

    return 0;

}

struct file_operations fops =

{

    .owner              =   THIS_MODULE,

    .open               =   wakeupKey_open,

    .release            =   wakeupKey_release,

    .write              =   wakeupKey_write,

    .read               =   wakeupKey_read,

    .unlocked_ioctl     =   wakeupKey_ioctl

};

 

struct miscdevice dev =

{

    .minor  =   MISC_DYNAMIC_MINOR,

    .fops    =   &fops,

    .name   =   "rk3128_key",

    .nodename = "key_node"

};

 

static void gpioFree(unsigned int pin)

{

        if (gpio_is_valid(pin)&&pin!=0){

                gpio_free(pin);

        }

}

static int Request_keyIrq(void)

{

        int i,free;

        int err = 0;

        for(i=0;i

        {

                keybutton[i].pin = of_get_named_gpio(keypdev->dev.of_node, keybutton[i].name, 0);

                if (!gpio_is_valid(keybutton[i].pin))

                {

                        dbg("invalid keybutton[i].pin: %d\n",keybutton[i].pin);

                        return -1;

                }

                if (devm_gpio_request(&keypdev->dev,keybutton[i].pin, keybutton[i].name))

                {

                        dbg("gpio 0x%2x request failed name=%s ! ... \n",keybutton[i].pin,keybutton[i].name);

                        gpio_free(keybutton[i].pin);

                        keybutton[i].pin=0;

                        goto err0;

                }

                if(keybutton[i].pin==0)

                {

                        continue;

                }

                gpio_direction_input(keybutton[i].pin);

                keybutton[i].irqNum = gpio_to_irq(keybutton[i].pin);

                /*注册中断函数*/

                err = request_irq(keybutton[i].irqNum , key_irqhandler, keybutton[i].irqmode,keybutton[i].name, NULL);

                if (err)

                {

                        dbg("request_irq failed keybutton[%d].irqNum = %d \n",i,keybutton[i].irqNum);

                        goto err0;

                }

                dbg("gpio [%d] vaule = %d\n",i,gpio_get_value(keybutton[i].pin));

        }

        dbg("Request_keyIrq gpio request_irq ok .......\n");

        return 0;

err0:

        free=i;

        dbg(" err2 : free = %d \n",free);

        for(i=0;i

        {

                if(keybutton[i].irqNum)

                        free_irq(keybutton[i].irqNum,NULL);

                gpio_free(keybutton[i].pin);

        }

        return -1;

}

static void free_keyIrq(void)

{

        int i=0;

        for(i=0;i

        {

                if(keybutton[i].pin==0)

                {

                        continue;

                }

                dbg("free_keyIrq: %d\n",keybutton[i].pin);

                free_irq(keybutton[i].irqNum,NULL);

                //gpio_free(keybutton[i].pin);

        }

}

 

static int init_key(void)

{

        int i=0,err=0;

        Request_keyIrq();

        input_device = input_allocate_device();

        if (!input_device) {

                goto err_free_irq;

        }

        set_bit(EV_KEY, input_device->evbit);

        for(i=0;i

        {

                set_bit(keybutton[i].reportValue, input_device->keybit);

                if(keybutton[i].type==CHECK_DOWN_UP)

                        set_bit(keybutton[i].reportValue+1, input_device->keybit);

        }

        clear_bit(0, input_device->keybit);

 

        err = input_register_device(input_device);

        if (err) {

                dbg(KERN_ERR "button.c: Failed to register device\n");

                goto err_free_dev;

        }

 

        setup_timer(&my_timer,time_function,0);

        return misc_register(&dev);

 err_free_dev:

        input_free_device(input_device);

 err_free_irq:

        free_keyIrq();

        return -EBUSY;

}

 

static int event_key_probe(struct platform_device *pdev)

{

        dbg("event_key_probe ok  ............ \n");

        //keyIrq = kmalloc(sizeof(KeyIrq),GFP_KERNEL);

        keypdev = pdev;

        init_key();

        return 0;

}

static int event_key_remove(struct platform_device *pdev)

{

        del_timer(&my_timer);

        free_keyIrq();

        input_free_device(input_device);

        dbg("key remove ok \n");

        return 0;

}

static const struct of_device_id of_event_key_match[] = {

        { .compatible = "rk3128_mykey", },

        {},

};

 

static struct platform_driver event_key_driver = {

        .probe          = event_key_probe,

        .remove         = event_key_remove,

        .driver         = {

                .name   = "rk3128_key",

                .owner  = THIS_MODULE,

                .of_match_table = of_match_ptr(of_event_key_match),

        },

};

 

static int __init wakeupKey_init(void)

{

        dbg("wakeupKey init ! ... \n");

        platform_driver_register(&event_key_driver);

        return 0;

}

static void __exit wakeupKey_exit(void)

{

    platform_driver_unregister(&event_key_driver);

    misc_deregister(&dev);

    dbg("wakeupKey exit!\n");

}

module_init(wakeupKey_init);

module_exit(wakeupKey_exit);

MODULE_LICENSE("Dual BSD/GPL");

                                  

5、驱动测试

按下按键之后,事件会上报到安卓当中,测试阶段可以将提交的按键值为:

KEY_VOLUMEDOWN  音量减

KEY_VOLUMEUP 音量加 

android 界面当中会弹出音量加减界面

你可能感兴趣的:(linux驱动开发)