Chinaunix首页 | 论坛 | 博客
  • 博客访问: 125163
  • 博文数量: 29
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 200
  • 用 户 组: 普通用户
  • 注册时间: 2014-12-18 18:29
文章分类

全部博文(29)

文章存档

2016年(1)

2015年(24)

2014年(4)

我的朋友

分类: 嵌入式

2015-05-25 23:40:02

参考SDK 3x3键盘驱动修改而来。


点击(此处)折叠或打开

  1. /* linux/driver/input/w55fa92_keypad_4*4.c
  2.  *
  3.  * Copyright (c) 2010 Nuvoton technology corporation
  4.  * All rights reserved.
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * Changelog:
  12.  *
  13.  */

  14. #include <linux/init.h>
  15. #include <linux/slab.h>
  16. #include <asm/errno.h>
  17. #include <asm/delay.h>
  18. #include <linux/mm.h>
  19. #include <linux/poll.h>
  20. #include <linux/module.h>
  21. #include <mach/hardware.h>
  22. #include <asm/io.h>
  23. #include <linux/cdev.h>
  24. #include <linux/interrupt.h>
  25. #include <linux/completion.h>
  26. #include <mach/irqs.h>
  27. #include <mach/w55fa92_keypad.h>
  28. #include <mach/w55fa92_reg.h>
  29. #include <mach/regs-clock.h>
  30. #undef BIT
  31. #include <linux/input.h>
  32. #include <linux/bitops.h>
  33. #define BIT(x) (1UL<<((x)%BITS_PER_LONG))

  34. #define KPD_IRQ_NUM W55FA92_IRQ(2) // nIRQ0
  35. #define DEF_KPD_DELAY HZ/20

  36. #define KEY_COUNT    16    
  37. #define ROW_CNT        4
  38. #define COL_CNT        4
  39. #define COL_MASK    0x0f

  40. //#define W55FA92_DEBUG printk

  41. static struct input_dev *w55fa92_keypad_input_dev;
  42. static struct timer_list kpd_timer;
  43. static char timer_active = 0;

  44. static u32 old_key;
  45. static u32 new_key;
  46. static u32 open_cnt = 0;

  47. u32 w55fa92_key_pressing = 0;
  48. EXPORT_SYMBOL(w55fa92_key_pressing);
  49. /*
  50.         {
  51.          1, 2, 3, 4,
  52.          5, 6, 7, 8,
  53.          9, 10, 11, 12,
  54.          13, 14, 15, 16

  55.             }
  56. */

  57. /*
  58. const int key_map[KEY_COUNT] = {
  59.                 9,10,11,12,
  60.                 5,6,7,8,
  61.                 1,2,3,4,
  62.                 13,14,15,16
  63.                         };//as #
  64. */
  65. const int key_map[KEY_COUNT] = {
  66.                 7,8,9,15,
  67.                 4,5,6,14,
  68.                 1,2,3,13,
  69.                 11,10,12,16
  70.                         };//as #


  71. // arg = 0, from isr, 1 from timer.
  72. static void w55fa92_check_ghost_state(void)
  73. {
  74.     int i,j;
  75.     u32 check = 0;
  76.     u32 col, check_col, cmp_col;            

  77.     for (i = 0; i < ROW_CNT; i++)
  78.     {
  79.         col = (new_key >> (i*COL_CNT)) & COL_MASK;        

  80.         if ((col & check) && hweight8(col) > 1)
  81.         {
  82.             for(j=0; j<ROW_CNT; j++)
  83.             {
  84.                 check_col = (new_key >> (j*COL_CNT)) & COL_MASK;
  85.                 if((col & check_col) != 0)
  86.                 {
  87.                     cmp_col = (old_key >> (j*COL_CNT)) & COL_MASK;                                        
  88.                     new_key = new_key & ~((cmp_col ^ check_col) << (j*COL_CNT));
  89.                 }
  90.             }                        
  91.         }

  92.         check |= col;
  93.     }
  94.         
  95. }

  96. /*new_key: [0-3]: row 1
  97.          [4-7]: row 2
  98.          [8-11]: row 3
  99.          [12-15]:row 4
  100.          */
  101. static void read_key(unsigned long arg)
  102. {
  103.         u32 i;

  104.         // ISR detect key press, disable irq, use timer to read following key press until released
  105.         if (!timer_active) {
  106.                 writel(1 << KPD_IRQ_NUM, REG_AIC_MDCR);
  107.         w55fa92_key_pressing = 1;
  108.                 disable_irq_nosync(KPD_IRQ_NUM); //disable_irq(KPD_IRQ_NUM);
  109.         }

  110.          new_key = readl(REG_GPIOC_PIN) & 0x0f;
  111.         if ((new_key & 0x0f) == 0x0f) { // all key released
  112.                 for (i = 0; i < KEY_COUNT; i++) {
  113.                         if (old_key & (1 << i)) {
  114.                                 input_report_key(w55fa92_keypad_input_dev, key_map[i], 0); //key up
  115.                                 input_sync(w55fa92_keypad_input_dev);
  116.                         }
  117.                 }
  118.                 old_key = 0;
  119.                 del_timer(&kpd_timer);
  120.                 timer_active = 0;
  121.                 enable_irq(KPD_IRQ_NUM);
  122.                 w55fa92_key_pressing = 0;
  123.                 return;
  124.         }

  125.         writel((readl(REG_GPIOC_DOUT) |(1 << 6) | (1 << 7)|(1<<4))&~(1<<5), REG_GPIOC_DOUT); // one line low,others high
  126.         udelay(1);
  127.         new_key = ~(readl(REG_GPIOC_PIN) >> 0) & 0xf;
  128.         
  129.         writel((readl(REG_GPIOC_DOUT) |(1 << 5) | (1 << 7)|(1<<4))&~(1<<6), REG_GPIOC_DOUT);
  130.         udelay(1);
  131.         new_key |= ((~(readl(REG_GPIOC_PIN) >> 0) & 0x0f)<<4);
  132.         
  133.         writel((readl(REG_GPIOC_DOUT) |(1 << 5) | (1 << 6)|(1<<4))&~(1<<7), REG_GPIOC_DOUT);
  134.         udelay(1);
  135.         new_key |= ((~(readl(REG_GPIOC_PIN) >> 0) & 0x0f)<<8);
  136.         
  137.         writel((readl(REG_GPIOC_DOUT) |(1 << 6) | (1 << 7)|(1<<5))&~(1<<4), REG_GPIOC_DOUT);

  138.         udelay(1);
  139.         new_key |= ((~(readl(REG_GPIOC_PIN) >> 0) & 0x0f)<<12);
  140.         
  141.         writel(readl(REG_GPIOC_DOUT) &~((1 << 6) | (1 << 7)|(1<<5)|(1<<4)), REG_GPIOC_DOUT);
  142.         //printk("new_key:%x\n",new_key);
  143.         w55fa92_check_ghost_state();

  144.         for (i = 0; i < KEY_COUNT; i++) {
  145.                 if ((new_key ^ old_key) & (1 << i)) {// key state change
  146.                         if (new_key & (1 << i)) {
  147.                                 input_report_key(w55fa92_keypad_input_dev, key_map[i], 1);    //key down
  148.                         } else {
  149.                                 input_report_key(w55fa92_keypad_input_dev, key_map[i], 0);    //key up
  150.                         }
  151.                         input_sync(w55fa92_keypad_input_dev);
  152.                 }

  153.         }

  154.         old_key = new_key;

  155.         timer_active = 1;
  156.         if ( arg == 0 )
  157.                 mod_timer(&kpd_timer, jiffies + DEF_KPD_DELAY*2); //*3); //### to avoid key too sensitive
  158.         else
  159.                 mod_timer(&kpd_timer, jiffies + DEF_KPD_DELAY);

  160.         return;

  161. }


  162. static irqreturn_t w55fa92_kpd_irq(int irq, void *dev_id) {

  163.         u32 src;    
  164.     
  165.         src = readl(REG_IRQTGSRC1);

  166.         read_key(0);

  167.         // clear source
  168.        writel(src & 0x000000f, REG_IRQTGSRC1);
  169.     
  170.         return IRQ_HANDLED;
  171. }


  172. int w55fa92_kpd_open(struct input_dev *dev) {
  173.     
  174.         if (open_cnt > 0) {
  175.                 goto exit;
  176.         }

  177.         new_key = old_key = 0;
  178.         init_timer(&kpd_timer);
  179.         kpd_timer.function = read_key;    /* timer handler */
  180.         kpd_timer.data = 1;
  181.         writel((1 << KPD_IRQ_NUM), REG_AIC_SCCR); // force clear previous interrupt, if any.
  182.         
  183.         writel(readl(REG_IRQTGSRC1) & 0x000000f, REG_IRQTGSRC1); // clear source

  184.         if (request_irq(KPD_IRQ_NUM, w55fa92_kpd_irq, IRQF_DISABLED, "Keypad",NULL) != 0) {
  185.                 printk("register the keypad_irq failed!\n");
  186.                 return -1;
  187.         }
  188.         //enable falling edge triggers
  189.        writel((readl(REG_IRQENGPC)& ~(0x000f0000)) | 0x000000f, REG_IRQENGPC);

  190. exit:
  191.         open_cnt++;
  192.         return 0;
  193. }



  194. void w55fa92_kpd_close(struct input_dev *dev) {
  195.     
  196.         open_cnt--;
  197.         if (open_cnt == 0) {
  198.             //disable falling edge triggers
  199.             writel((readl(REG_IRQENGPC)& ~(0x000f000f)), REG_IRQENGPC);

  200.                 del_timer(&kpd_timer);
  201.                 free_irq(KPD_IRQ_NUM,NULL);
  202.         }
  203.         return;
  204. }


  205. static int __init w55fa92_kpd_reg(void) {

  206.         int i, err;
  207.         //PORTC[0-3] for Interrupt
  208.         writel(readl(REG_GPIOC_OMD) & ~((1 << 0)|(1 << 1)|(1 << 2) | (1 << 3)), REG_GPIOC_OMD); // input
  209.         writel(readl(REG_GPIOC_PUEN) | ((1 << 0)|(1 << 1)|(1 << 2) | (1 << 3)), REG_GPIOC_PUEN); // pull-up
  210.         writel(readl(REG_IRQSRCGPC) & ~(0xFF), REG_IRQSRCGPC); // GPC[1~4] as nIRQ0 source
  211.         writel((readl(REG_IRQENGPC)& ~(0x000F0000)) | 0x000000F, REG_IRQENGPC); // falling edge trigger
  212.         writel((readl(REG_AIC_SCR1)& ~(0x00C70000)) | 0x00470000, REG_AIC_SCR1);//
  213.          //GPC[4-7]:key other 4lines
  214.         writel(readl(REG_GPIOC_OMD) | ((1 <<4 )|(1 << 5)|(1 << 6)|(1 << 7)), REG_GPIOC_OMD); // output
  215.         writel(readl(REG_GPIOC_PUEN) | ((1 <<4 )|(1 << 5)|(1 << 6)|(1 << 7)), REG_GPIOC_PUEN); // pull up
  216.         writel(readl(REG_GPIOC_DOUT) &~((1 <<4 )|(1 << 5)|(1 << 6)|(1 << 7)), REG_GPIOC_DOUT); // low
  217.         writel(readl(REG_GPCFUN0) & ~(0xFFFFFFFF), REG_GPCFUN0);

  218.         writel(readl(REG_DBNCECON) |0x71, REG_DBNCECON);
  219.         if (!(w55fa92_keypad_input_dev = input_allocate_device())) {
  220.                 printk("upsmaker001 Keypad Drvier Allocate Memory Failed!\n");
  221.                 err = -ENOMEM;
  222.                 goto fail;
  223.         }

  224.         w55fa92_keypad_input_dev->name = "upsmaker001 Keypad";
  225.         w55fa92_keypad_input_dev->phys = "input/event1";
  226.         w55fa92_keypad_input_dev->id.bustype = BUS_HOST;
  227.         w55fa92_keypad_input_dev->id.vendor = 0x0005;
  228.         w55fa92_keypad_input_dev->id.product = 0x0001;
  229.         w55fa92_keypad_input_dev->id.version = 0x0100;

  230.         w55fa92_keypad_input_dev->open = w55fa92_kpd_open;
  231.         w55fa92_keypad_input_dev->close = w55fa92_kpd_close;

  232.         w55fa92_keypad_input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_SYN) | BIT(EV_REP);

  233.         for (i = 0; i < KEY_MAX; i++)
  234.                 set_bit(i+1, w55fa92_keypad_input_dev->keybit);

  235.         err = input_register_device(w55fa92_keypad_input_dev);
  236.         if (err) {

  237.                 input_free_device(w55fa92_keypad_input_dev);
  238.                 return err;
  239.         }

  240.         // must set after input device
  241.         w55fa92_keypad_input_dev->rep[REP_DELAY] = 300; //250ms
  242.         w55fa92_keypad_input_dev->rep[REP_PERIOD] = 200; //ms

  243.         printk("upsmaker001 keypad driver has been initialized successfully!\n");

  244.         return 0;

  245. fail:
  246.         input_free_device(w55fa92_keypad_input_dev);
  247.         return err;
  248. }

  249. static void __exit w55fa92_kpd_exit(void) {
  250.         free_irq(KPD_IRQ_NUM, NULL);
  251.         input_unregister_device(w55fa92_keypad_input_dev);
  252. }

  253. module_init(w55fa92_kpd_reg);
  254. module_exit(w55fa92_kpd_exit);

  255. MODULE_AUTHOR("upsmaker001 eRain");
  256. MODULE_DESCRIPTION("KeyPad 4*4 driver@2015.4.9");
  257. MODULE_LICENSE("GPL");

阅读(1459) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~