原创
s3c2440-gpio-button(keyboard)驱动
/*
* 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.pin, 1 - c_s3c2440_row.pin_val);
100 } else {
101 for (i = 0; i < KB_ROWS; i++)
102 s3c2410_gpio_setpin(c_s3c2440_row.pin, c_s3c2440_row.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)) {
188 /** wait chattering delay **/
189 //udelay(20);
190 //s3c2440_kbd_scankeyboard(&g_s3c2440_kbd, regs);
191 disable_irq(c_s3c2440_col.irq);
192 s3c2410_gpio_cfgpin(c_s3c2440_col.pin, c_s3c2440_col.pin_in);
193 mod_timer(&g_s3c2440_kbd.timers, 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 | 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 | 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, 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.pin, c_s3c2440_row.pin_out);
300 s3c2410_gpio_pullup(c_s3c2440_row.pin, 1);
301 s3c2410_gpio_setpin(c_s3c2440_row.pin, c_s3c2440_row.pin_val);
302 s3c2440_kbd_states = -1;
303 }
304
305 for (i = 0; i < KB_COLS; i++) {
306 init_timer(&g_s3c2440_kbd.timers);
307 g_s3c2440_kbd.timers.function = s3c2440_kbd_timer_callback;
308 g_s3c2440_kbd.timers.data = (unsigned long)i;
309
310 s3c2410_gpio_pullup(c_s3c2440_col.pin, 0);
311
312 set_irq_type(c_s3c2440_col.irq, c_s3c2440_col.irq_type);
313 if (request_irq(c_s3c2440_col.irq, s3c2440_kbd_interrupt, c_s3c2440_col.irq_flag,"kbd_irq",(void*)i)){
314 while ( i >= 0 ){
315 disable_irq(c_s3c2440_col.irq);
316 free_irq(c_s3c2440_col.irq, (void*)i);
317 s3c2410_gpio_cfgpin(c_s3c2440_col.pin, c_s3c2440_col.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);
377 disable_irq(c_s3c2440_col.irq);
378 free_irq(c_s3c2440_col.irq, (void*)i);
379 s3c2410_gpio_cfgpin(c_s3c2440_col.pin, c_s3c2440_col.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条评论)
登录后参与讨论