⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 key_driver.c

📁 s3c2410平台
💻 C
字号:
/*
 * Copyright (C) 2006 Shenzhen Genvict Technologies Co., Ltd.
 * Author: Zhong Yong <zelog@163.com>
 * Date  : 2006/05/22
 * vision: 0.03
 * 
 * 8*3 keyboard driver, 74hc164 based.
 *
 *
 *
 * 20080401 port to kernel 2.6 and add resume/suspend support
 *
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/time.h>

#include <asm/hardware.h>

//rwen
#include <linux/interrupt.h>
#include <asm/arch/hardware.h> 
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-irq.h>
#include <asm/io.h>
#include <linux/compiler.h>
#include <asm/plat-s3c24xx/irq.h>

#include <linux/timer.h>

#include <linux/device.h>

#include <linux/platform_device.h>


//#define DEBUG


#define DEVICE_NAME	"RSU_key"
#define RSU_KEY_MAJOR 251

//#define KEY_TEST

#define UCHAR unsigned char 

#define KEY_DISABLE 1
#define KEY_ENABLE 0

//74HC164 micro define
#define I_DSB S3C2410_GPH9
#define I_DSB_OUTP S3C2410_GPH9_OUTP

#define I_CP S3C2410_GPH10
#define I_CP_OUTP  S3C2410_GPH10_OUTP



//for 8*3 keys
#define ROW_NUM 8
#define COL_NUM ( (sizeof irq_col_tab) / sizeof (irq_col_tab[0]) )

//#define	ClearPending(x)	{SRCPND = (1 << (x)); INTPND = (1 << (x));}
#define	ClearPending(x)	


volatile int slowExit;
#define BIT_ALLMSK     (0xffffffff)
#define FCLK 202800000
#define HCLK (202800000/2)
#define PCLK (202800000/4)
#define UCLK PCLK
unsigned int saveREFRESH, saveINTMSK;


static int irq_col_tab[] = { IRQ_EINT1, IRQ_EINT2, IRQ_EINT11 };
static unsigned gpio_col_tab[] = { S3C2410_GPF1, S3C2410_GPF2, S3C2410_GPG3 };
static unsigned gpio_col_mode[] = {S3C2410_GPF1_INP, S3C2410_GPF2_INP, S3C2410_GPG3_INP };


static DECLARE_WAIT_QUEUE_HEAD(buttons_wait);
static int waitting_down_tab[] = {1, 1, 1};
static spinlock_t lk;

static int key_value = 0; 

#define MAX_KEY_LIST 8192
static unsigned char key_list[MAX_KEY_LIST];
static int           key_count = 0;

#define USE_LOCK

#ifdef USE_LOCK
#define lock() spin_lock(lk)
#define unlock() spin_unlock(lk)
#else
#define lock() 
#define unlock() 
#endif



static struct class *RSU_keys_class;


/*
  void Test_SlowMode(void)
  {
  int i;

  slowExit=0;
  saveINTMSK = INTMSK;
    
  INTMSK=~(IRQ_EINT1 | IRQ_EINT2 | IRQ_EINT11);
  LCDCON1 = LCDCON1 & 0x3fffe; // ENVID Off
		
  //CLKSLOW=7|(1<<4)|(1<<5)|(1<<7); //FCLK=FIN/1,SLOW mode,MPLL=off,UPLL=off 
  CLKSLOW=0|(1<<4)|(1<<5)|(1<<7); //FCLK=FIN/1,SLOW mode,MPLL=off,UPLL=off 
    
  saveREFRESH=REFRESH;
  REFRESH=(1<<23)|(unsigned int)(2048+1-12*15.6); //Trp=2clk,Trc=4clk
  //The other memory control register should be optimized for SLOW mode.
  while(!slowExit)
  {
  mdelay(1);
  }
  INTMSK=BIT_ALLMSK;

  CLKSLOW=0|(1<<4)|(0<<5);//PLL on,MPLL=on
    
  for(i=0;i<2048;i++);    //S/W MPLL lock-time
  CLKSLOW=0|(0<<4)|(0<<5);//NORMAL mode,PLL on,MPLL=on
  INTMSK = saveINTMSK;
  LCDCON1 |= 1; // ENVID=ON
  }


*/


static released=1;

static irqreturn_t buttons_irq(int irq, void *dev_id)
{
     int i;
     int col_no = -1, row_no = -1;
     unsigned long flags;
     int r;

     
/*
     lock();
   
     local_irq_save(flags);
*/
     disable_irq(irq);



#ifdef DEBUG	      
     printk("got irq = %d \n", irq);
#endif

     for (i = 0; i < COL_NUM; i++) 
     {
	  if (irq_col_tab[i] == irq) 
	  {
	       col_no = i;
	       break;
	  }
     }
     if (col_no < 0) 
     {
	  goto EXIT;
     }

     udelay(300);


     if (waitting_down_tab[col_no])
     {

	  released = 0;
	     
	  s3c2410_gpio_setpin(I_DSB, 1);
	  s3c2410_gpio_setpin(I_CP, 1);
	  s3c2410_gpio_setpin(I_CP, 0);

	  r = s3c2410_gpio_getpin(gpio_col_tab[col_no]);


	  if(r > 0)
	  {
	       row_no = 0;

	       udelay(300);  
	       
	       //the follow codes is fore checking wether the button is released.
	       s3c2410_gpio_setpin(I_DSB, 0);

	       s3c2410_gpio_setpin(I_CP, 1);
	       s3c2410_gpio_setpin(I_CP, 0);

//	       printk("<0>" "before: the value r = %d\n", r);
	       r = s3c2410_gpio_getpin(gpio_col_tab[col_no]);
//	       printk("<0>" "after: the value r = %d\n", r);
	       if (r > 0)       // the wrong key value from the dither
		    goto EXIT;

	  }
	  else 
	  {
	       s3c2410_gpio_setpin(I_DSB, 0);

	       for(i = 1; i < 8; i++)
	       {

		    s3c2410_gpio_setpin(I_CP, 1);
		    s3c2410_gpio_setpin(I_CP, 0);
		    r = s3c2410_gpio_getpin(gpio_col_tab[col_no]);

		    if(r > 0)
		    {
			 row_no = i;
			 break;
		    }
	       }
	  }


	  if (col_no < 0 || row_no < 0)
	  {
	       goto EXIT;
	  }

	  //need this?
//	  s3c2410_gpio_setpin(gpio_col_tab[col_no], 0);

	  slowExit = 1;
	  if(key_count < MAX_KEY_LIST)
	  {
	       key_value = row_no * 3 + col_no + 1;
	       key_list[key_count] = key_value;
#ifdef DEBUG	      
	       printk("<0>" "event key down, irq = %d, row = %d, col = %d, value = %d\n", irq, row_no, col_no, key_value);
#endif
	       key_count++;
	  }
     }
     else
     {
	  released = 1;

	  if(key_count < MAX_KEY_LIST)
	  {
	       key_list[key_count] = key_value | 0x80;
#ifdef DEBUG
	       printk("event key up, irq = %d, row = %d, col = %d, value = %d\n", irq, row_no, col_no, key_value);
#endif
	       key_count++;
	  }
     }


     waitting_down_tab[col_no] = !waitting_down_tab[col_no];
     set_irq_type(irq, waitting_down_tab[col_no]? IRQT_FALLING: IRQT_RISING);
//	  set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);


     wake_up_interruptible(&buttons_wait);


EXIT:


     s3c2410_gpio_setpin(I_DSB, 0);

     for(i = 0; i < 8; i++)
     {
	  s3c2410_gpio_setpin(I_CP, 1);
	  s3c2410_gpio_setpin(I_CP, 0);

     }

     enable_irq(irq);

/*
     local_irq_restore(flags);
     unlock();
*/

     return IRQ_HANDLED;
}




static void buttons_row_port_init(void)
{
     //set gpio status
     UCHAR i;

     s3c2410_gpio_cfgpin(I_DSB, I_DSB_OUTP);
     s3c2410_gpio_pullup(I_DSB, 1);
     s3c2410_gpio_cfgpin(I_CP, I_CP_OUTP);
     s3c2410_gpio_pullup(I_CP, 1);


     s3c2410_gpio_setpin(I_DSB, 0);
     for(i = 0; i < 8; i++)
     {
	  s3c2410_gpio_setpin(I_CP, 1);
	  s3c2410_gpio_setpin(I_CP, 0);

     }
	
     for (i = 0; i < COL_NUM; i++) 
     {

	  s3c2410_gpio_cfgpin(gpio_col_tab[i], gpio_col_mode[i]);
	  s3c2410_gpio_pullup(gpio_col_tab[i], 1);  //disable
     }
	
     //reset 74hc164 output  	
     s3c2410_gpio_setpin(I_DSB, 0);
     s3c2410_gpio_setpin(I_CP, 0);

}

static int RSU_key_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
{
     //static int key;
     static int keybuffer[2];
     int result;
     int i;
     if (count != sizeof keybuffer)
     {
	  return -EINVAL;
     }
	
     lock();
  
     if(key_count > 0)
     {
	  keybuffer[0] = key_list[0] & 0x7F;
	  keybuffer[1] = key_list[0] < 0x80;
	  copy_to_user(buffer, &keybuffer, sizeof(keybuffer));
	  for(i = 0; i < key_count-1; i++)
	  {
	       key_list[i] = key_list[i+1];
	  }
	  key_count--;
	  result = sizeof(keybuffer);
     }
     else
     {
	  result = -EAGAIN;
     }
  
     unlock();
  
     return result;
}

static unsigned int RSU_key_poll(struct file *file,  struct poll_table_struct *wait)
{
     int r;
     lock();
     r = key_count > 0;
     unlock();
     if(r)
     {
	  return 1;
     }
     else
     {
	  poll_wait(file, &buttons_wait, wait);
	  return 0;
     }
}

static int RSU_key_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
     int i;
     int irq;
//     int fd;
     switch(cmd) 
     {
     case 0:
     {
	  key_value = 0;
	  for (i = 0; i < COL_NUM; i++)
	  {
	       irq = irq_col_tab[i];
///	       INTMSK &= ~(1 << irq);	//unmask interrupts
//	       ClearPending(irq);
	       enable_irq(irq);

	  }
			
	  return 0;
     }
		
     case 1:
     {	
	  key_value = 0;
	  for (i = 0; i < COL_NUM; i++)
	  {
	       irq = irq_col_tab[i];
///	       INTMSK |= (1 << irq);		//mask interrupts
//	       ClearPending(irq);

	       disable_irq(irq);
	  }
			
	  return 0;
     }
     case 2:
     {
			
//	  Test_SlowMode();
	  return 0;
     }

     default:
	  return -EINVAL;
     }
}

static int request_irqs(void)
{
     int i;
     int irq;
     int ret;

     for (i = 0; i < COL_NUM; i++) {
	  irq = irq_col_tab[i];

	  set_irq_type(irq, IRQT_FALLING);
//	  set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
	  ret = request_irq(irq, &buttons_irq, 0, DEVICE_NAME, &buttons_irq);
	  if (ret) 
	  {
	       unregister_chrdev(RSU_KEY_MAJOR, DEVICE_NAME);
	       printk(DEVICE_NAME " can't request irq %d\n", irq);
	       return ret;
	  } else {
#ifdef DEBUG	
	       printk("%dth: request irq %d ok\n",i, irq);
#endif
	  }
	  

     }
}

static void free_irqs(void)
{
     int i;
     for (i = 0; i < COL_NUM; i++) 
     {
	  int irq = irq_col_tab[i];
	  free_irq(irq, buttons_irq);
     }
}

static struct file_operations RSU_key_fops = 
{
     .owner =	THIS_MODULE,
     .ioctl =   RSU_key_ioctl,
     .poll  =   RSU_key_poll,
     .read  =   RSU_key_read,
};

static int RSU_key_probe(struct platform_device *pdev)
{
     int ret;
     int i;
     int err;
	
     printk("rsukeys init ......\n");

     ret = register_chrdev(RSU_KEY_MAJOR, DEVICE_NAME, &RSU_key_fops);
     if (ret < 0) 
     {
	  printk(DEVICE_NAME " can't register major number\n");
	  return ret;
     }
	
     buttons_row_port_init();


     ret = request_irqs();

//     setup_timer(&isr_timer, timer_handler, 0);

     key_value = 0;


//  these need any more?
     for (i = 0; i < COL_NUM; i++)
     {
	  int irq;
	  irq = irq_col_tab[i];


//NO need this anymore
#ifndef DEBUG
//	  disable_irq(irq);
#endif
     }
	


     RSU_keys_class = class_create(THIS_MODULE, DEVICE_NAME);
     if (IS_ERR(RSU_keys_class)) {
	  err = PTR_ERR(RSU_keys_class);
	  goto ERR;
     }
     class_device_create(RSU_keys_class, NULL, MKDEV(RSU_KEY_MAJOR, 0), NULL, DEVICE_NAME);

#ifdef DEBUG
     printk("init finished.\n");
#endif

ERR:

     return 0;
}

static int RSU_key_remove(struct platform_device *pdev)
{

     class_device_destroy(RSU_keys_class, MKDEV(RSU_KEY_MAJOR, 0));
     class_destroy(RSU_keys_class);

     free_irqs();
     unregister_chrdev(RSU_KEY_MAJOR, DEVICE_NAME);

     return 0;
}


static struct platform_driver rsukeys_driver = {
     .driver = {
	  .name    = "rsu-keys",
	  .owner   = THIS_MODULE,
     },
     .probe   = RSU_key_probe,
     .remove  = RSU_key_remove,
//     .suspend = RSU_key_suspend,
//     .resume  = RSU_key_resume,
};

static int __init rsukeys_init(void)
{
  
     return platform_driver_register(&rsukeys_driver);        /* search board and register */
}

static void __exit
rsukeys_cleanup(void)
{
     platform_driver_unregister(&rsukeys_driver);
}




module_init(rsukeys_init);
module_exit(rsukeys_cleanup);
MODULE_LICENSE("GPL");


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -