Chinaunix首页 | 论坛 | 博客
  • 博客访问: 106018
  • 博文数量: 30
  • 博客积分: 300
  • 博客等级: 二等列兵
  • 技术积分: 253
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-08 00:35
文章分类

全部博文(30)

文章存档

2012年(16)

2011年(14)

我的朋友

分类:

2011-12-08 00:37:41

/*
 * This is a driver code for matrix keyboard
 * GPN0 1 2 --- ROW0 1 2
 * GPN4 5 6 9 --- COL0 1 2 3
 * use EINT0 1 2 for EX IRQ
 * AUTHOR: LiuTao
 * date : 2011-12-02
 */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

MODULE_AUTHOR("HaNdAEr~L.T");
MODULE_LICENSE("GPL");
struct input_dev *button_devp;
static char *name = "my6410_buttons";
 
volatile int COLVAL = 0;
volatile int ROWVAL = 0;
volatile int key_num = 0;
/*struct of irq*/
struct button_irq_desc{
 int irq;
 int pin;
 int number;
 char *name;
};
/*IRQ for module*/
static struct button_irq_desc button_irqs[] = {
 { IRQ_EINT(0),S3C64XX_GPN(0),  0,  "rol1"},
 { IRQ_EINT(1),S3C64XX_GPN(1),  1,  "rol2"},
 { IRQ_EINT(2),S3C64XX_GPN(2),  2,  "rol3"},
 { IRQ_EINT(3),S3C64XX_GPN(3),  3,  "s27" },
};

/*input_report_key */
static void report_key(int keyno,int reportval)
{
// printk("in check_key ...ret_keyno = %d...\n",keyno);
 //printk("in check_key ...reportval = %d...\n",reportval);
 switch(keyno){
  case 1:
      //printk("key1 down...\n");
   input_report_key(button_devp, BTN_0, reportval);
   break;
  case 2:
      //printk("key2 down...\n");
   input_report_key(button_devp, BTN_1, reportval); 
   break;
  case 3:
      //printk("key3 down...\n");
   input_report_key(button_devp, BTN_2, reportval);
   break;
  case 4:
      //printk("key4 down...\n");
   input_report_key(button_devp, BTN_3, reportval);
   break;
  case 5:
     // printk("key5 down...\n");
   input_report_key(button_devp, BTN_4, reportval);   
   break;
  case 6:
     // printk("key6 down...\n");
   input_report_key(button_devp, BTN_5, reportval);   
   break;
  case 7:
     // printk("key7 down...\n");
   input_report_key(button_devp, BTN_6, reportval);
   break;
  case 8:
     // printk("key8 down...\n");
   input_report_key(button_devp, BTN_7, reportval);
   break;
  case 9:
     // printk("key9 down...\n");
   input_report_key(button_devp, BTN_8, reportval);
   break;
  case 10:
     // printk("key10 down...\n");
   input_report_key(button_devp, BTN_9, reportval);
   break;
  case 11:
     // printk("key11 down...\n");
   input_report_key(button_devp, BTN_A, reportval);
   break;
  case 12:
     // printk("key12 down...\n");
   input_report_key(button_devp, BTN_B, reportval);
   break;
  default:
    break; 
 }
 input_sync(button_devp);
}
/*012 as input VS 4 5 6 9 as output*/
static void port_init(void)
{
 unsigned int tmp = 0;
 tmp = readl(S3C64XX_GPNCON);
 tmp &=  ~(0xffffffff); //0 1 2 input
 tmp |= (1 << 8) | (1 << 10) | (1 << 12) | (1 << 18) ;   // 4 5 6 9 0x010101 01
 writel(tmp,S3C64XX_GPNCON);
}
/*012 output VS 4 5 6 9 as input*/
static void Port_Init(void)
{
 unsigned int tmp = 0;
 
 tmp = readl(S3C64XX_GPNCON);
 tmp &= ~(0xffffffff);
 tmp |= 0x00000015;
 writel(tmp,S3C64XX_GPNCON);
}
volatile unsigned long GPNDAT,GPN_VIRT;
/*to make sure COLVAL = ? ROWVAL = ?*/
static void Scan_Keyboard(void)
{
 volatile unsigned int IOValue = 0,iovalue = 0;
 volatile unsigned int temp = 0;
 volatile unsigned int reiovalue = 0;
 volatile int i;
 //int count = 0;
 
 temp = readl(GPNDAT);
 temp |= (1 << 4) | (1 << 5) | (1 << 6) | (1 << 9);
// temp &= ~(1 << 0) & ~(1 << 1) & ~(1 << 2);
 writel(temp,GPNDAT);
 
 Port_Init();
 IOValue = readl(GPNDAT);
 //printk("1...IOVAlue = %x...\n",IOValue);
 
 if((IOValue & (1 << 0)) == 0)
 {
  ROWVAL= 1; 
 }
 else if((IOValue & (1 << 1)) == 0)
 {
  ROWVAL= 2;  
 }
 else if((IOValue & (1 << 2)) == 0)
 {
  ROWVAL = 3; 
 }
 /* delay */
 for (i=0; i<10000; i++) asm ("");
 
 iovalue = readl(GPNDAT);
 //printk("IOValue = %x..\n",iovalue);
 
 iovalue |= (1 << 4) | (1 << 5) | (1 << 6) | (1 << 9);
 //iovalue |= (1 << 0) | (1 << 1) | (1 << 2);
 //iovalue &= ~(1 << 4) & ~(1 << 5) & ~(1 << 6) & ~(1 << 9);
 //printk("IOValue = %x...\n",IOValue);
 writel(iovalue,GPNDAT);
  port_init(); // init GPNCON set 0 1 2 output
 temp = readl(GPNDAT);
 //printk("temp = %x..\n",temp);
 if((temp & (1 << 4)) == 0)
 {
  COLVAL = 1;
 }
 else if((temp & (1 << 5)) == 0)
 {
  COLVAL = 2;
 }
 else if((temp & ( 1 << 6)) == 0)
 {
  COLVAL = 3;
 }
 else if((temp & (1 << 9)) == 0)
 {
  COLVAL = 4;
 }
 
 /*set GPNDAT4 5 6 9 low level */
 /*The most important step*/
 reiovalue = readl(GPNDAT);
 reiovalue &= ~(1 << 4) & ~(1 << 5) & ~(1 << 6) & ~(1  << 9);
 writel(reiovalue,GPNDAT);
 
}
 
/*to make sure which key...  key_num = ? */
static void set_keynum(int Cval,int Rval,int reportval)
{
 if(Rval == 1)
 {
  switch(Cval)
  {
   case 1:
    key_num = 1;
    break;
   case 2:
    key_num = 2;
    
    break;
   case 3:
    key_num = 3;
   
    break;
   case 4:
    key_num = 4;
    
    break;
  }
 } 
 else if(Rval == 2)
 {
  switch(Cval)
  {
   case 1:
    key_num = 5;
   
    break;
   case 2:
    key_num = 6;
    
    break;
   case 3:
    key_num = 7;
    
    break;
   case 4:
    key_num = 8;
    
    break;
  }
 }
 else if(Rval == 3)
 {
  switch(Cval)
  {
   case 1:
    key_num = 9;
    
    break;
   case 2:
    key_num = 10;
   
    break;
   case 3:
    key_num = 11;
    
    break;
   case 4:
    key_num = 12;
    
    break;
  }
 }
}

/*interrupt code */
static int save_irq = 0;
static irqreturn_t  button_interrupt(int irq, void* dev_id)
{
 struct button_irq_desc *button_irqs = (struct button_irq_desc*)dev_id;
 unsigned int IOValue = 0;
 int status, retval;
 disable_irq(IRQ_EINT(0)); 
 disable_irq(IRQ_EINT(1));
 disable_irq(IRQ_EINT(2));
 
 status = readl(S3C64XX_GPNDAT) & ( 0x1 << button_irqs->number);
 retval = status ? 0 : 1;
  //printk("retval = %d \n",retval);
  
 if(retval == 1){ 
  save_irq = button_irqs->irq;
  Scan_Keyboard();  //scan_keyboard
 
 
   //printk("\n COLVAL =%d ROWVAL = %d.....\n",COLVAL,ROWVAL );
 //printk("+++++++++\n");
  set_keynum(COLVAL,ROWVAL,retval); //  key_num ?
  report_key(key_num,retval);

  //printk("\nkey_num = %d...\n",key_num);
  IOValue = readl(S3C64XX_GPNCON);
  IOValue &= ~(0xffffffff);
  IOValue |= 0x000415aa;;
  writel(IOValue,S3C64XX_GPNCON);
 }
 else if ((retval == 0) && (save_irq == button_irqs->irq))
 {
    report_key(key_num,retval);
 }
 enable_irq(IRQ_EINT(0)); 
 enable_irq(IRQ_EINT(1));
 enable_irq(IRQ_EINT(2));
 
 //printk("end irq+++++++++\n");
 return IRQ_RETVAL(IRQ_HANDLED);
}

/*request IRQ IRQ_EINT(0 1 2)*/
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;
 }
 
 return 0;
}

/*first run*/
static int __init button_init(void)
{
 struct input_dev *input_dev;
 int ret;
 
 GPN_VIRT = ioremap(0x7F008000,SZ_4K);
 GPNDAT   = GPN_VIRT + 0x834;

 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();
 
 set_bit(EV_KEY, button_devp->evbit);
 set_bit(BTN_0, button_devp->keybit);
 set_bit(BTN_1, button_devp->keybit);
 set_bit(BTN_2, button_devp->keybit);
 set_bit(BTN_3, button_devp->keybit);
 set_bit(BTN_4, button_devp->keybit);
 set_bit(BTN_5, button_devp->keybit);
 set_bit(BTN_6, button_devp->keybit);
 set_bit(BTN_7, button_devp->keybit);
 set_bit(BTN_8, button_devp->keybit);
 set_bit(BTN_9, button_devp->keybit);
 set_bit(BTN_A, button_devp->keybit);
 set_bit(BTN_B, button_devp->keybit);
 set_bit(BTN_C, button_devp->keybit);
 
 ret = input_register_device(button_devp);
 if(ret < 0){
  printk("input_register_device(): failed !! \n");
 }
 return ret;
}
/*exit*/
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);
阅读(688) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:基于mini2440的linphone移植

给主人留下些什么吧!~~