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";
};
中断方式
#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 *);
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)//设置定时器回调函数
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"); 按下按键之后,事件会上报到安卓当中,测试阶段可以将提交的按键值为: KEY_VOLUMEDOWN 音量减 KEY_VOLUMEUP 音量加 android 界面当中会弹出音量加减界面5、驱动测试