📄 kpp.c
字号:
#ifndef __KERNEL__# define __KERNEL__#endif#ifndef MODULE# define MODULE#endif//<<<<<< Private Macro#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/delay.h>#include <linux/poll.h>#include <asm/uaccess.h> /* get_user,copy_to_user */#include <linux/miscdevice.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/string.h>#include <linux/init.h>#include <asm/bitops.h>#include <asm/io.h>#include <linux/errno.h>#include <linux/tqueue.h>#include <linux/wait.h>#include <asm/irq.h>#include <asm/arch/hardware.h>#include <asm/arch/irqs.h>#include <asm/arch/mx2.h>#include <linux/pm.h>#include "kpp.h"#define CONFIG_ARCH_MX2ADS#define MODULE_NAME "kpp"//#define DBMX_DEBUG 1#ifdef DBMX_DEBUG#define TRACE(fmt, args...) \ { \ printk("\n %s:%d:%s:",__FILE__, __LINE__,__FUNCTION__); \ printk(fmt, ## args);\ }#else#define TRACE(fmt, args...)#endif#define FAILED(fmt, args...) \ { \ printk("\n %s:%d:%s:",__FILE__, __LINE__,__FUNCTION__); \ printk(fmt, ## args);\ }#define INFO(fmt, args...) \ { \ printk("\n"); \ printk(fmt, ## args);\ }//>>>>>> Private Macro#define KPP_MX2_MASK 0x3f3f //for MX2, it is 6*6 key matrix#define KPP_MX2_COL_NUM 6#define KPP_MX2_ROW_NUM 6#ifdef _reg_KPP_KPCR#undef _reg_KPP_KPCR#endif#ifdef _reg_KPP_KPSR#undef _reg_KPP_KPSR#endif#ifdef _reg_KPP_KDDR#undef _reg_KPP_KDDR#endif#ifdef _reg_KPP_KPDR#undef _reg_KPP_KPDR#endif#define KPP_BASE_ADDR 0x10008000#define _reg_KPP_KPCR (*((volatile unsigned short *)(IO_ADDRESS(KPP_BASE_ADDR+0x00)))) // 16bit kpp keypad control reg#define _reg_KPP_KPSR (*((volatile unsigned short *)(IO_ADDRESS(KPP_BASE_ADDR+0x02)))) // 16bit kpp keypad status reg#define _reg_KPP_KDDR (*((volatile unsigned short *)(IO_ADDRESS(KPP_BASE_ADDR+0x04)))) // 16bit kpp keypad data directon reg#define _reg_KPP_KPDR (*((volatile unsigned short *)(IO_ADDRESS(KPP_BASE_ADDR+0x06)))) // 16bit kpp keypad data reg#define kpp_row_enable(mask) (_reg_KPP_KPCR|(mask))#define kpp_col_enable(mask) (_reg_KPP_KPCR|(mask<<8))#define KPP_KPPEN_BIT_MASK 0x0400 //kpp clock gating enable#define KPP_KRIE_BIT_MASK 0x0200 //kpp release interrupt enable#define KPP_KDIE_BIT_MASK 0x0100 //kpp depress interrupt enable#define KPP_KRSS_BIT_MASK 0x0008 //kpp release synchronizer set#define KPP_KDSC_BIT_MASK 0x0004 //kpp depress synchronizer clear#define KPP_KPKR_BIT_MASK 0x0002 //kpp key release#define KPP_KPKD_BIT_MASK 0x0001 //kpp key depress#define KPP_IRQ 21//<<<<<Private Function Declearation//>>>>>Private Function Declearation//<<<<<< Global Variablestatic int g_kpp_major=0;//static struct proc_dir_entry * g_proc_dir;static devfs_handle_t g_devfs_handle;static u8 kpp_pressed=0;static struct timer_list kpp_timer; static u8 kpp_timer_status; wait_queue_head_t g_mx21_kpp_wait;spinlock_t kpp_lock;static u32 g_key_code[2];static u32 old_key_code[2];static u16 rptr, wptr;key_code_t * g_mx21_kpp_buffer;struct pm_dev *g_kpp_pm;static int g_kpp_status;#define KPP_OPEN_STATUS 0x0001#define KPP_SUSPEND_STATUS 0x0002//>>>>>> Global Variable#define NODATA() (rptr == wptr)#define BUFFLENTH 8#define BUFFSIZE (BUFFLENTH*sizeof(key_code_t))#define NEXTITEM(i) {i=(i==BUFFLENTH-1)?0:i+1;}#define GETNEXTIEM(i) ((i==BUFFLENTH-1)?0:i+1)#define DATASIZE() ((wptr<rptr)?(BUFFLENTH-rptr):(wptr-rptr))#define DEPRESSED 0xff#define RELEASED 0x0static int init_buf(void){ g_mx21_kpp_buffer = (key_code_t*) kmalloc(BUFFSIZE,GFP_KERNEL); if(!g_mx21_kpp_buffer){ printk(KERN_ERR"no enough kernel memory for spi data buffer\n"); return -1; } rptr = wptr = 0; return 1;}static void add_key_code(u32 low, u32 high, u32 flag){ if (GETNEXTIEM(wptr) == rptr) return; g_mx21_kpp_buffer[wptr].low = low; g_mx21_kpp_buffer[wptr].high = high; g_mx21_kpp_buffer[wptr].status = flag; NEXTITEM(wptr); // goto next wptr}static key_code_t* get_data(void){ key_code_t *data; if(NODATA()) return NULL; data = &(g_mx21_kpp_buffer[rptr]); TRACE("*** Read - low: 0x%04x, high: 0x%04x, rptr: 0x%04x, wptr: 0x%04x\n", data->low, data->high, (int)rptr, (int)wptr); NEXTITEM(rptr); return data;}static void mx2ads_mask_irq(unsigned int irq){ _reg_AITC_INTENABLEL &= ~(1<<irq);}static void mx2ads_unmask_irq(unsigned int irq){ _reg_AITC_INTENABLEL |= (1<<irq);}//Configure KPP setting, void kpp_hw_configure(){ u16 row,col; row = KPP_MX2_MASK&0x00ff; col = KPP_MX2_MASK&0xff00; //GPIO portE3467 as alternate function, since the UART2 has some conflict to Keypad _reg_GPIO_GIUS(GPIOE) &= ~0x000000d8; _reg_GPIO_GPR(GPIOE) |= 0x000000d8; //enable clk gate of kpp _reg_CRM_PCCR1 |= 0x40000000; _reg_KPP_KPSR |= KPP_KPPEN_BIT_MASK; //enable key _reg_KPP_KPCR |= row; //clear kpp data register _reg_KPP_KPDR &= ~(col|row); //configure col as output opendrain _reg_KPP_KPCR |= col; _reg_KPP_KDDR |= col; //configure row as input _reg_KPP_KDDR &= ~row; //Clear KPKD status flag and synchronizer chain _reg_KPP_KPSR |= KPP_KDSC_BIT_MASK; _reg_KPP_KPSR |= KPP_KPKD_BIT_MASK; //Set KDIE control bit, clear the KRIE control bit _reg_KPP_KPSR |= KPP_KDIE_BIT_MASK; _reg_KPP_KPSR &= ~KPP_KRIE_BIT_MASK;}static void kpp_irq_enable(){ //clear key depress event _reg_KPP_KPSR |= KPP_KPKD_BIT_MASK; //clear key release event _reg_KPP_KPSR |= KPP_KPKR_BIT_MASK; //enable irq mx2ads_unmask_irq(KPP_IRQ); }//for col0, will have eight bit mask, though bit6,7 is not used by any key in current keyboardstatic void keycode_convert(u16 scancode, u32* p_key_code){ u16 tempcol,colnum; u16 temprow; u16 tmp; int i; u32 code[2]; tmp = 1; tempcol = (scancode&KPP_MX2_MASK&0xff00)>>8; temprow = ~(scancode&KPP_MX2_MASK&0x00ff); code[0]=code[1]=0; TRACE("scancode = 0x%x ,temprow = 0x%x \n",scancode,temprow); if(tempcol & 0xf)//col0~3 { for(i=0;i<4;i++) { if(tempcol & (1<<i)) { colnum = i; break; } } for(i=0; i<6; i++) { if(temprow&(1<<i)) code[0] |= 1<<(colnum*8 + i); } } if(tempcol & 0xf0)//col4~7 { for(i=4;i<8;i++) { if(tempcol & (1<<i)) { colnum = i-4; break; } } for(i=0; i<6; i++) { if(temprow&(1<<i)) code[1] |= 1<<(colnum*8 + i); } } *p_key_code |= code[0]; p_key_code++; *p_key_code |= code[1];// TRACE("key_code[0] = 0x%x key_code[1] = 0x%x \n",code[0],code[1]); }static void kpp_scan_matrix(){ u16 row,col; u16 iCol,scanMask; u16 keypressed; old_key_code[0] = g_key_code[0]; old_key_code[1] = g_key_code[1]; g_key_code[0] = g_key_code[1] = 0; row = KPP_MX2_MASK&0x00ff; col = KPP_MX2_MASK&0xff00; iCol=0; scanMask=0; kpp_pressed = 0; for(iCol=0; iCol<KPP_MX2_COL_NUM; iCol++) { //write 1's to KPDR[15:8] _reg_KPP_KPDR |= col; //configure columns as totem-pole outputs _reg_KPP_KPCR &= ~col; //configure columns as open-drain _reg_KPP_KPCR |= col; //write a single column to 0,others to 1 scanMask = (1<<(iCol+8)); _reg_KPP_KPDR &= ~scanMask; //sample row inputs and save data. keypressed = (_reg_KPP_KPDR&0x00ff)| scanMask; if((_reg_KPP_KPDR&row)!=row) { kpp_pressed = 1; keycode_convert(keypressed,g_key_code); } //restore the colmask _reg_KPP_KPDR |= scanMask; } _reg_KPP_KPDR &= ~col; TRACE("g_key_code[0] = 0x%x g_key_code[1]=0x%x \n",g_key_code[0],g_key_code[1]); if((g_key_code[0] != old_key_code[0])||(g_key_code[1] != old_key_code[1])) { if(kpp_pressed == 1) add_key_code(g_key_code[0], g_key_code[1], DEPRESSED); else add_key_code(g_key_code[0], g_key_code[1], RELEASED); wake_up_interruptible(&g_mx21_kpp_wait);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -