s3c2440-gpio-button(keyboard)驱动

来源:互联网 发布:什么软件看电影最好 编辑:程序博客网 时间:2024/05/22 02:09
/*
  *  Keyboard driver for s3c2440 gpio button, Borzoi and Akita (SL-Cxx00 series)
  *
  *  Copyright (c) 2005 Richard Purdie
  *
  *  Based on corgikbd.c
  *
   *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  *
  */
     13
     14 #include <linux/delay.h>
     15 #include <linux/platform_device.h>
     16 #include <linux/init.h>
     17 #include <linux/input.h>
     18 #include <linux/interrupt.h>
     19 #include <linux/jiffies.h>
     20 #include <linux/module.h>
     21 #include <linux/slab.h>
     22 #include <linux/irq.h>
     23
     24 #include <asm/io.h>
     25 #include <asm/irq.h>
     26 #include <asm/arch/regs-gpio.h>
     27 #include <asm/arch/hardware.h>
     28
     29 #define KB_ROWS         3
     30 #define KB_COLS         8
     31
     32 #define SCAN_INTERVAL       (50) /* ms */
     33 #define KB_DELAY            10
     34 #define KB_ACTIVATE_DELAY   10
     35
     36 static const unsigned int s3c2440_kbd_keycode[KB_COLS * KB_ROWS] = {
     37     KEY_PLAYPAUSE, KEY_STOPCD, KEY_BACK,KEY_FORWARD,  KEY_RECORD, 0, 0, 0,
     38     KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_F1, KEY_F2, KEY_F3, KEY_F4,
     39     KEY_ESC, KEY_SOUND, KEY_ENTER, KEY_PAGEUP, KEY_PAGEDOWN, 0, KEY_HELP, KEY_F5,
 };
     41
     42 struct s3c2440_kbd {
     43     unsigned int keycode[ARRAY_SIZE(s3c2440_kbd_keycode)];
     44     struct input_dev *input;
     45     char phys[32];
     46
     47     spinlock_t lock;
     48     struct timer_list timers[KB_COLS];
     49
     50     unsigned int suspended;
     51     unsigned long suspend_jiffies;
     52 };
     53
     54 static struct s3c2440_kbd g_s3c2440_kbd;
     55
     56 struct s3c2440_kbd_row{
     57     unsigned int pin;
     58     unsigned int pin_out;
     59     unsigned int pin_val;
     60     unsigned int pin_in;
     61     unsigned int irq;
     62     unsigned int irq_type;
     63     unsigned int irq_flag;
     64 };
     65
     66 static const struct s3c2440_kbd_row c_s3c2440_row[KB_ROWS]=
     67 {
     68     {S3C2410_GPG5, S3C2410_GPG5_OUTP, 0, S3C2410_GPG5_INP, 0, 0, 0},
     69     {S3C2410_GPG6, S3C2410_GPG6_OUTP, 0, S3C2410_GPG6_INP, 0, 0, 0},
     70     {S3C2410_GPG7, S3C2410_GPG7_OUTP, 0, S3C2410_GPG7_INP, 0, 0, 0},
     71 /*
     72     {S3C2410_GPG2, S3C2410_GPG2_OUTP, 0, S3C2410_GPG2_INP, 0, 0, 0},
     73     {S3C2410_GPG3, S3C2410_GPG3_OUTP, 0, S3C2410_GPG3_INP, 0, 0, 0},
     74     {S3C2410_GPG1, S3C2410_GPG1_OUTP, 0, S3C2410_GPG1_INP, 0, 0, 0},
     75     {S3C2410_GPG12, S3C2410_GPG12_OUTP, 0, S3C2410_GPG12_INP, 0, 0, 0},*/
     76 };
 static unsigned int s3c2440_kbd_states[KB_ROWS];
     91
     92
     93 static inline void s3c2440_kbd_set_row_status(int col, int flag)
     94 {
     95     int i;
     96
     97     if (!flag) {
     98         for (i = 0; i < KB_ROWS; i++)
     99             s3c2410_gpio_setpin(c_s3c2440_row[i].pin, 1 - c_s3c2440_row[i].pin_val);
    100     } else {
    101         for (i = 0; i < KB_ROWS; i++)
    102             s3c2410_gpio_setpin(c_s3c2440_row[i].pin, c_s3c2440_row[i].pin_val);
    103     }
    104     return ;
    105 }
static void s3c2440_kbd_scankeyboard(struct s3c2440_kbd *kbd_data, struct pt_regs *regs, int timer_id)
    108 {
    109     unsigned int row;
    110     unsigned long flags;
    111     unsigned int num_pressed;
    112
    113     //printk("\n %s timer_id = %d\n", __FUNCTION__, timer_id);
    114
    115     if (kbd_data->suspended)
    116         return;
    117
    118     spin_lock_irqsave(&kbd_data->lock, flags);
    119
    120     input_regs(kbd_data->input, regs);
    121
    122     num_pressed = 0;
    123
    124     s3c2440_kbd_set_row_status(timer_id, 0);
    125
    126     for (row = 0; row < KB_ROWS; row++) {
    127         unsigned int pin1, pin2, pin3;
    128
    129         s3c2410_gpio_setpin(c_s3c2440_row[row].pin, c_s3c2440_row[row].pin_val);
    130
    131         udelay(KB_ACTIVATE_DELAY);
    132         pin1 = s3c2410_gpio_getpin(c_s3c2440_col[timer_id].pin);
    133
    134         udelay(KB_DELAY);
    135         pin2 = s3c2410_gpio_getpin(c_s3c2440_col[timer_id].pin);
    136
    137         udelay(KB_DELAY);
    138         pin3 = s3c2410_gpio_getpin(c_s3c2440_col[timer_id].pin);
    139
    140         if (pin2 == pin3)
    141             pin1 = pin3;
    142
    143         if (pin1 == pin2 ) {
    144             if (pin1 == c_s3c2440_col[timer_id].pin_val) {
5                 num_pressed++;
    146                 if (s3c2440_kbd_states[row] & (1 << timer_id)) {
    147                     s3c2440_kbd_states[row] &= ~(1 << timer_id);
    148                     input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + timer_id], 1);
    149                     printk("\n keycode = %d pressed = 1 \n", kbd_data->keycode[row * KB_COLS + timer_id]);
    150                     //printk("\n row = %d col = %d \n", row, timer_id);
    151
    152                 }
    153             }else {
    154                 if ( !(s3c2440_kbd_states[row] & (1 << timer_id)) ) {
    155                     s3c2440_kbd_states[row] |= (1 << timer_id);
    156                     input_report_key(kbd_data->input, kbd_data->keycode[row * KB_COLS + timer_id], 0);
    157                     printk("\n keycode = %d pressed = 0 \n", kbd_data->keycode[row * KB_COLS + timer_id]);
    158                 }
    159             }
    160         }
    161
    162         s3c2410_gpio_setpin(c_s3c2440_row[row].pin, 1 - c_s3c2440_row[row].pin_val);
    163     }
    164
    165     s3c2440_kbd_set_row_status(timer_id, 1);
    166
    167     input_sync(kbd_data->input);
    168
    169     /* if any keys are pressed, enable the timer */
    170     if (num_pressed) {
    171         mod_timer(&kbd_data->timers[timer_id], jiffies + msecs_to_jiffies(SCAN_INTERVAL));
    172     }else {
    173         set_irq_type(c_s3c2440_col[timer_id].irq, c_s3c2440_col[timer_id].irq_type);
    174         enable_irq(c_s3c2440_col[timer_id].irq);
    175     }
    176     spin_unlock_irqrestore(&kbd_data->lock, flags);
    177 }


static irqreturn_t s3c2440_kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
    180 {
    181     int i = (int)dev_id;
    182
    183     //printk("\n %s : IRQ = %d \n", __FUNCTION__, i);
    184
    185     if (i >= 0 && i < KB_COLS) {
    186
    187         if (!timer_pending(&g_s3c2440_kbd.timers[i])) {
    188             /** wait chattering delay **/
    189             //udelay(20);
    190             //s3c2440_kbd_scankeyboard(&g_s3c2440_kbd, regs);
    191             disable_irq(c_s3c2440_col[i].irq);
    192             s3c2410_gpio_cfgpin(c_s3c2440_col[i].pin, c_s3c2440_col[i].pin_in);
    193             mod_timer(&g_s3c2440_kbd.timers[i], jiffies + msecs_to_jiffies(SCAN_INTERVAL));
    194         }
    195     }
    196
    197     return IRQ_HANDLED;
    198 }

 static void s3c2440_kbd_timer_callback(unsigned long data)
    201 {
    202     int timer_id = (int)data;
    203
    204     //printk("\n %s: timer id = %d\n", __FUNCTION__, timer_id);
    205
    206     if (timer_id >= 0 && timer_id < KB_COLS) {
    207         s3c2440_kbd_scankeyboard(&g_s3c2440_kbd, NULL, timer_id);
    208     #if 0
    209         set_irq_type(c_s3c2440_col[timer_id].irq, c_s3c2440_col[timer_id].irq_type);
    210         enable_irq(c_s3c2440_col[timer_id].irq);
    211     #endif
    212     }
    213 }
    214
6 #ifdef CONFIG_PM
    217 static int s3c2440_kbd_suspend(struct platform_device *dev, pm_message_t state)
    218 {
    219     struct s3c2440_kbd *s3c2440_kbd = platform_get_drvdata(dev);
    220     s3c2440_kbd->suspended = 1;
    221
    222     #if 0
    223     /* Set Strobe lines as inputs - *except* strobe line 0 leave this
    224        enabled so we can detect a power button press for resume */
    225     for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++)
    226         pxa_gpio_mode(s3c2440_kbd_strobes[i] | GPIO_IN);
    227     #endif
    228
    229     return 0;
    230 }
    231
    232 static int s3c2440_kbd_resume(struct platform_device *dev)
    233 {
    234     struct s3c2440_kbd *s3c2440_kbd = platform_get_drvdata(dev);
    235
    236     #if 0
    237     for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++)
    238         pxa_gpio_mode(s3c2440_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH);
    239     #endif
    240
    241     /* Upon resume, ignore the suspend key for a short while */
    242     s3c2440_kbd->suspend_jiffies = jiffies;
    243     s3c2440_kbd->suspended = 0;
    244
    245     return 0;
    246 }
    247 #else
    248 #define s3c2440_kbd_suspend NULL
    249 #define s3c2440_kbd_resume      NULL
    250 #endif

 static int __init s3c2440_kbd_probe(struct platform_device *dev)
    253 {
    254     struct input_dev *input_dev;
    255     int i;
    256
    257     input_dev = input_allocate_device();
    258     if (!input_dev) {
    259         return -ENOMEM;
    260     }
    261
    262     platform_set_drvdata(dev, &g_s3c2440_kbd);
    263
    264     strcpy(g_s3c2440_kbd.phys, "input/kbd0");
    265
    266     spin_lock_init(&g_s3c2440_kbd.lock);
    267
    268     /* Init Keyboard rescan timer */
    269     //init_timer(&g_s3c2440_kbd.timer);
    270     //g_s3c2440_kbd.timer.function = s3c2440_kbd_timer_callback;
    271     //g_s3c2440_kbd.timer.data = (unsigned long)&g_s3c2440_kbd;
    272
    273     g_s3c2440_kbd.suspend_jiffies = jiffies;
    274
    275     g_s3c2440_kbd.input = input_dev;
    276
    277     input_dev->private = &g_s3c2440_kbd;
    278     input_dev->name = "S3c2440 Keyboard";
    279     input_dev->phys = g_s3c2440_kbd.phys;
    280     input_dev->cdev.dev = &dev->dev;
    281
    282     input_dev->id.bustype = BUS_PARPORT;
    283     input_dev->id.vendor = 0x0001;
    284     input_dev->id.product = 0x0001;
    285     input_dev->id.version = 0x0100;
    286
    287     input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_SYN);
    288     input_dev->keycode = g_s3c2440_kbd.keycode;
    289     input_dev->keycodesize = sizeof(unsigned int);
    290     input_dev->keycodemax = ARRAY_SIZE(s3c2440_kbd_keycode);
    292     memcpy(g_s3c2440_kbd.keycode, s3c2440_kbd_keycode, sizeof(g_s3c2440_kbd.keycode));
    293     for (i = 0; i < ARRAY_SIZE(s3c2440_kbd_keycode); i++)
    294         set_bit(g_s3c2440_kbd.keycode[i], input_dev->keybit);
    295
    296     //clear_bit(0, input_dev->keybit);
    297
    298     for (i = 0; i < KB_ROWS; i++) {
    299         s3c2410_gpio_cfgpin(c_s3c2440_row[i].pin, c_s3c2440_row[i].pin_out);
    300         s3c2410_gpio_pullup(c_s3c2440_row[i].pin, 1);
    301         s3c2410_gpio_setpin(c_s3c2440_row[i].pin, c_s3c2440_row[i].pin_val);
    302         s3c2440_kbd_states[i] = -1;
    303     }
    304
    305     for (i = 0; i < KB_COLS; i++) {
    306         init_timer(&g_s3c2440_kbd.timers[i]);
    307         g_s3c2440_kbd.timers[i].function = s3c2440_kbd_timer_callback;
    308         g_s3c2440_kbd.timers[i].data = (unsigned long)i;
    309
    310         s3c2410_gpio_pullup(c_s3c2440_col[i].pin, 0);
    311
    312         set_irq_type(c_s3c2440_col[i].irq, c_s3c2440_col[i].irq_type);
    313         if (request_irq(c_s3c2440_col[i].irq, s3c2440_kbd_interrupt, c_s3c2440_col[i].irq_flag,"kbd_irq",(void*)i)){
    314             while ( i >= 0 ){
    315                 disable_irq(c_s3c2440_col[i].irq);
    316                 free_irq(c_s3c2440_col[i].irq, (void*)i);
    317                 s3c2410_gpio_cfgpin(c_s3c2440_col[i].pin, c_s3c2440_col[i].pin_in);
    318             }
    319             printk(KERN_ERR "s3c2440_gpio_kbd.c: Could not allocate irq !\n");
    320             return -EIO;
    321         }
    322
    323     }

    354     input_register_device(input_dev);
    355
    356     printk(KERN_INFO "input: S3c2440  Keyboard Registered\n");
    357
    358     return 0;
    359 }
 static int s3c2440_kbd_remove(struct platform_device *dev)
    362 {
    363     int i;
    364     struct s3c2440_kbd *s3c2440_kbd = platform_get_drvdata(dev);
    365
    366     #if 0
    367     disable_irq(IRQ_EINT0);
    368     disable_irq(IRQ_EINT2);
    369
    370     free_irq(IRQ_EINT0, (void*)IRQ_EINT0);
    371     free_irq(IRQ_EINT2, (void*)IRQ_EINT2);
    372     #endif
    373
    374     for (i = 0; i < KB_COLS; i++)
    375     {
    376         del_timer_sync(&s3c2440_kbd->timers[i]);
    377         disable_irq(c_s3c2440_col[i].irq);
    378         free_irq(c_s3c2440_col[i].irq, (void*)i);
    379         s3c2410_gpio_cfgpin(c_s3c2440_col[i].pin, c_s3c2440_col[i].pin_in);
    380     }
    381
    382     input_unregister_device(s3c2440_kbd->input);
    383
    384     return 0;
    385 }
    386
    387 static struct platform_driver s3c2440_kbd_driver = {
    388     .probe      = s3c2440_kbd_probe,
    389     .remove     = s3c2440_kbd_remove,
    390     .suspend    = s3c2440_kbd_suspend,
    391     .resume     = s3c2440_kbd_resume,
    392     .driver     = {
    393         .name   = "s3c2440-gpio-kbd",
    394     },
    395 };
    396

 static int __init s3c2440_kbd_init(void)
    398 {
    399     return platform_driver_register(&s3c2440_kbd_driver);
    400 }
    401
    402 static void __exit s3c2440_kbd_exit(void)
    403 {
    404     platform_driver_unregister(&s3c2440_kbd_driver);
    405 }
    406
    407 module_init(s3c2440_kbd_init);
    408 module_exit(s3c2440_kbd_exit);
           MODULE_AUTHOR("s3c2440");
           MODULE_DESCRIPTION("smdk s3c2440 Keyboard Driver");
           MODULE_LICENSE("GPLv2");
0 0