UT4412BV03矩阵键盘驱动分析.docx
《UT4412BV03矩阵键盘驱动分析.docx》由会员分享,可在线阅读,更多相关《UT4412BV03矩阵键盘驱动分析.docx(12页珍藏版)》请在冰豆网上搜索。
UT4412BV03矩阵键盘驱动分析
UT4412BV03矩阵键盘驱动分析
一.UT4412BV03开发板外接了一个3*3的矩阵键盘,通过对矩阵键盘的驱动的编写来实现按键的功能linux内核中已经包含了一个矩阵键盘的驱动,用户只需要简单修改就能实现按键的功能。
UT4412BV03矩阵键盘原理图
如图:
在默认倩况下,矩阵键盘的行线被电阻上拉到高电平。
如果某个按键被按下则其对应的行线和列线都为低电平
软件流程图
二.矩阵键盘驱动分析
1.矩阵键盘对应的IO管脚的初始化
linux/arch/arm/mach-exynos/setup-keypad.c
voidsamsung_keypad_cfg_gpio(unsignedintrows,unsignedintcols)
{
if(rows>8){
/*SetallthenecessaryGPX2pins:
KP_ROW[0~7]*/
s3c_gpio_cfgall_range(EXYNOS4_GPX2(0),8,
S3C_GPIO_SFN(3),S3C_GPIO_PULL_UP);
/*SetallthenecessaryGPX3pins:
KP_ROW[8~]*/
s3c_gpio_cfgall_range(EXYNOS4_GPX3(0),(rows-8),
S3C_GPIO_SFN(3),S3C_GPIO_PULL_UP);
}else{
/*SetallthenecessaryGPX2pins:
KP_ROW[x]*/
s3c_gpio_cfgall_range(EXYNOS4_GPX2(0),rows,
S3C_GPIO_SFN(3),S3C_GPIO_PULL_UP);
}
/*SetallthenecessaryGPX1pinstospecial-function3:
KP_COL[x]*/
s3c_gpio_cfgrange_nopull(EXYNOS4_GPX1(0),cols,S3C_GPIO_SFN(3));
}
2.矩阵键盘平台设备和平台资源的初始化
linux/arch/arm/plat-samsung/dev-keypad.c
staticstructresourcesamsung_keypad_resources[]={
[0]={
.start=SAMSUNG_PA_KEYPAD,
.end=SAMSUNG_PA_KEYPAD+0x20-1,
.flags=IORESOURCE_MEM,
},
[1]={
.start=IRQ_KEYPAD,
.end=IRQ_KEYPAD,
.flags=IORESOURCE_IRQ,
},
};
structplatform_devicesamsung_device_keypad={
.name="samsung-keypad",
.id=-1,
.num_resources=ARRAY_SIZE(samsung_keypad_resources),
.resource=samsung_keypad_resources,
};
3. SamSung-keypd.c矩阵键盘驱动分析
//填充一个平台驱动结构体
staticstructplatform_driversamsung_keypad_driver={
.probe=samsung_keypad_probe, //按键探测函数,驱动注册后最先执行的函数
.remove=__devexit_p(samsung_keypad_remove),
.driver={
.name="samsung-keypad", //平台驱动的名字
.owner=THIS_MODULE,
#ifdefCONFIG_PM
.pm=&samsung_keypad_pm_ops,
#endif
},
.id_table=samsung_keypad_driver_ids,
};
//注册一个平台驱动
staticint__initsamsung_keypad_init(void)
{
returnplatform_driver_register(&samsung_keypad_driver);
}
//驱动注册后最先执行的探测函数分析
staticint__devinitsamsung_keypad_probe(structplatform_device*pdev)
{
conststructsamsung_keypad_platdata*pdata;
conststructmatrix_keymap_data*keymap_data;
structsamsung_keypad*keypad;
structresource*res;
structinput_dev*input_dev;
unsignedintrow_shift;
unsignedintkeymap_size;
interror;
#ifdefCONFIG_WAKELOCK_KEEP
wake_lock_init(&s_ut_wake_lock2, WAKE_LOCK_SUSPEND,"holdwakebuttom");
keep_wakeup_timeout
(2);
#endif
pdata=pdev->dev.platform_data; //获取平台私有数据
if(!
pdata){
dev_err(&pdev->dev,"noplatformdatadefined\n");
return-EINVAL;
}
keymap_data=pdata->keymap_data;
if(!
keymap_data){
dev_err(&pdev->dev,"nokeymapdatadefined\n");
return-EINVAL;
}
if(!
pdata->rows||pdata->rows>SAMSUNG_MAX_ROWS)
return-EINVAL;
if(!
pdata->cols||pdata->cols>SAMSUNG_MAX_COLS)
return-EINVAL;
/*initializethegpio*/
if(pdata->cfg_gpio)
//调用GPIO初始化函数,设置对应引脚为按键模式
pdata->cfg_gpio(pdata->rows,pdata->cols);
row_shift=get_count_order(pdata->cols);
keymap_size=(pdata->rows<keycodes[0]);
keypad=kzalloc(sizeof(*keypad)+keymap_size,GFP_KERNEL);
input_dev=input_allocate_device();
if(!
keypad||!
input_dev){
error=-ENOMEM;
gotoerr_free_mem;
}
res=platform_get_resource(pdev,IORESOURCE_MEM,0);
if(!
res){
error=-ENODEV;
gotoerr_free_mem;
}
keypad->base=ioremap(res->start,resource_size(res));
if(!
keypad->base){
error=-EBUSY;
gotoerr_free_mem;
}
keypad->clk=clk_get(&pdev->dev,"keypad");
if(IS_ERR(keypad->clk)){
dev_err(&pdev->dev,"failedtogetkeypadclk\n");
error=PTR_ERR(keypad->clk);
gotoerr_unmap_base;
}
//初始化keypad结构体
keypad->input_dev=input_dev;
keypad->row_shift=row_shift;
keypad->rows=pdata->rows;
keypad->cols=pdata->cols;
init_waitqueue_head(&keypad->wait);
input_dev->name=pdev->name;
input_dev->id.bustype=BUS_HOST;
input_dev->dev.parent=&pdev->dev;
input_set_drvdata(input_dev,keypad);
input_dev->open=samsung_keypad_open;
input_dev->close=samsung_keypad_close;
input_dev->evbit[0]=BIT_MASK(EV_KEY); //表示输入设备为按键
if(!
pdata->no_autorepeat)
input_dev->evbit[0]|=BIT_MASK(EV_REP);
input_set_capability(input_dev,EV_MSC,MSC_SCAN);
input_dev->keycode=keypad->keycodes;
input_dev->keycodesize=sizeof(keypad->keycodes[0]);
input_dev->keycodemax=pdata->rows< matrix_keypad_build_keymap(keymap_data,row_shift,
input_dev->keycode,input_dev->keybit);
keypad->irq=platform_get_irq(pdev,0);
if(keypad->irq<0){
error=keypad->irq;
gotoerr_put_clk;
}
//注册一个按键中断,当有按键按下时,将触发samsung_keypad_irq函数的执行
error=request_threaded_irq(keypad->irq,NULL, samsung_keypad_irq,
IRQF_ONESHOT,dev_name(&pdev->dev),keypad);
if(error){
dev_err(&pdev->dev,"failedtoregisterkeypadinterrupt\n");
gotoerr_put_clk;
}
error=input_register_device(keypad->input_dev);
if(error)
gotoerr_free_irq;
device_init_wakeup(&pdev->dev,pdata->wakeup);
platform_set_drvdata(pdev,keypad);
return0;
err_free_irq:
free_irq(keypad->irq,keypad);
err_put_clk:
clk_put(keypad->clk);
err_unmap_base:
iounmap(keypad->base);
err_free_mem:
input_free_device(input_dev);
kfree(keypad);
returnerror;
}
//矩阵键盘按键使能函数
staticvoidsamsung_keypad_start(structsamsung_keypad*keypad)
{
unsignedintval;
/*TellIRQthreadthatitmaypollthedevice.*/
keypad->stopped=false;
clk_enable(keypad->clk);
/*Enableinterruptbits.*/
val=readl(keypad->base+SAMSUNG_KEYIFCON);
//使能按键在上升沿和下降沿出发按键中断
val|=SAMSUNG_KEYIFCON_INT_F_EN|SAMSUNG_KEYIFCON_INT_R_EN;
writel(val,keypad->base+SAMSUNG_KEYIFCON);
/*KEYIFCOLregclear.*/
//KEYIFCOL寄存器写零,使每个行输入引脚为正常输入模式
writel(0,keypad->base+SAMSUNG_KEYIFCOL);
}
//按键中断函数
staticirqreturn_tsamsung_keypad_irq(intirq,void*dev_id)
{
structsamsung_keypad*keypad=dev_id;
unsignedintrow_state[SAMSUNG_MAX_COLS];
unsignedintval;
boolkey_down;
do{
val=readl(keypad->base+SAMSUNG_KEYIFSTSCLR);
//清除中断标志位
writel(~0x0,keypad->base+SAMSUNG_KEYIFSTSCLR);
//调用按键扫描函数
samsung_keypad_scan(keypad,row_state);
//按键值上报到android用户空间
key_down=samsung_keypad_report(keypad,row_state);
if(key_down)
//当按键按下时调用下面函数来达到消斗动作用
wait_event_timeout(keypad->wait,keypad->stopped,
msecs_to_jiffies(50));
}while(key_down&&!
keypad->stopped); //等待按键释放
returnIRQ_HANDLED;
4.按键值的定义
//linux/arch/arm/mach-exynos/mach-smdk4x12.c
按键值定义在input.h中,并且最终按键值要和android中定义的键值匹配才行
staticuint32_tsmdk4x12_keymap0[]__initdata={
158 172 108
KEY(0,0,KEY_BACK), KEY(0,1,KEY_HOMEPAGE), KEY(0,2,KEY_DOWN),
114 139 115
KEY(1,0,KEY_VOLUMEDOWN), KEY(1,1,KEY_MENU), KEY(1,2,KEY_VOLUMEUP),
103 105 106
KEY(2,0,KEY_UP), KEY(2,1,KEY_LEFT), KEY(2,2,KEY_RIGHT),
};
staticstructmatrix_keymap_datasmdk4x12_keymap_data0__initdata={
.keymap=smdk4x12_keymap0,
.keymap_size=ARRAY_SIZE(smdk4x12_keymap0),
};
staticstructsamsung_keypad_platdatasmdk4x12_keypad_data0__initdata={
.keymap_data=&smdk4x12_keymap_data0,
.rows=3, //3行
.cols=3, //3列
};
android代码中定义的按键值如下
kernel中定义的键值要和android中定义的键值一一对应
/device/samsung/smdk4x12$
key103 DPAD_UP WAKE_DROPPED
key3 DPAD_CENTER WAKE_DROPPED
key108 DPAD_DOWN WAKE_DROPPED
key106 DPAD_RIGHT WAKE_DROPPED
key105 DPAD_LEFT WAKE_DROPPED
key114 VOLUME_DOWN WAKE
key172 HOME WAKE_DROPPED
key139 MENU WAKE_DROPPED
key115 VOLUME_UP WAKE
key158 BACK WAKE_DROPPED