Commit | Line | Data |
---|---|---|
fff71312 RP |
1 | /* |
2 | * Keyboard driver for Sharp Spitz, Borzoi and Akita (SL-Cxx00 series) | |
3 | * | |
4 | * Copyright (c) 2005 Richard Purdie | |
5 | * | |
6 | * Based on corgikbd.c | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <linux/delay.h> | |
d052d1be | 15 | #include <linux/platform_device.h> |
fff71312 RP |
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> | |
fff71312 RP |
22 | |
23 | #include <asm/arch/spitz.h> | |
24 | #include <asm/arch/hardware.h> | |
25 | #include <asm/arch/pxa-regs.h> | |
26 | ||
27 | #define KB_ROWS 7 | |
28 | #define KB_COLS 11 | |
29 | #define KB_ROWMASK(r) (1 << (r)) | |
30 | #define SCANCODE(r,c) (((r)<<4) + (c) + 1) | |
31 | #define NR_SCANCODES ((KB_ROWS<<4) + 1) | |
32 | ||
4872f788 | 33 | #define SCAN_INTERVAL (50) /* ms */ |
fff71312 RP |
34 | #define HINGE_SCAN_INTERVAL (150) /* ms */ |
35 | ||
36 | #define SPITZ_KEY_CALENDER KEY_F1 | |
37 | #define SPITZ_KEY_ADDRESS KEY_F2 | |
38 | #define SPITZ_KEY_FN KEY_F3 | |
39 | #define SPITZ_KEY_CANCEL KEY_F4 | |
40 | #define SPITZ_KEY_EXOK KEY_F5 | |
41 | #define SPITZ_KEY_EXCANCEL KEY_F6 | |
42 | #define SPITZ_KEY_EXJOGDOWN KEY_F7 | |
43 | #define SPITZ_KEY_EXJOGUP KEY_F8 | |
44 | #define SPITZ_KEY_JAP1 KEY_LEFTALT | |
45 | #define SPITZ_KEY_JAP2 KEY_RIGHTCTRL | |
46 | #define SPITZ_KEY_SYNC KEY_F9 | |
47 | #define SPITZ_KEY_MAIL KEY_F10 | |
48 | #define SPITZ_KEY_OK KEY_F11 | |
49 | #define SPITZ_KEY_MENU KEY_F12 | |
50 | ||
51 | static unsigned char spitzkbd_keycode[NR_SCANCODES] = { | |
52 | 0, /* 0 */ | |
53 | KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0, /* 1-16 */ | |
54 | 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */ | |
55 | KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */ | |
f11a7c09 RP |
56 | SPITZ_KEY_ADDRESS, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */ |
57 | SPITZ_KEY_CALENDER, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */ | |
fff71312 RP |
58 | SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0, /* 81-96 */ |
59 | KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0 /* 97-112 */ | |
60 | }; | |
61 | ||
62 | static int spitz_strobes[] = { | |
63 | SPITZ_GPIO_KEY_STROBE0, | |
64 | SPITZ_GPIO_KEY_STROBE1, | |
65 | SPITZ_GPIO_KEY_STROBE2, | |
66 | SPITZ_GPIO_KEY_STROBE3, | |
67 | SPITZ_GPIO_KEY_STROBE4, | |
68 | SPITZ_GPIO_KEY_STROBE5, | |
69 | SPITZ_GPIO_KEY_STROBE6, | |
70 | SPITZ_GPIO_KEY_STROBE7, | |
71 | SPITZ_GPIO_KEY_STROBE8, | |
72 | SPITZ_GPIO_KEY_STROBE9, | |
73 | SPITZ_GPIO_KEY_STROBE10, | |
74 | }; | |
75 | ||
76 | static int spitz_senses[] = { | |
77 | SPITZ_GPIO_KEY_SENSE0, | |
78 | SPITZ_GPIO_KEY_SENSE1, | |
79 | SPITZ_GPIO_KEY_SENSE2, | |
80 | SPITZ_GPIO_KEY_SENSE3, | |
81 | SPITZ_GPIO_KEY_SENSE4, | |
82 | SPITZ_GPIO_KEY_SENSE5, | |
83 | SPITZ_GPIO_KEY_SENSE6, | |
84 | }; | |
85 | ||
86 | struct spitzkbd { | |
87 | unsigned char keycode[ARRAY_SIZE(spitzkbd_keycode)]; | |
3c42f0c3 | 88 | struct input_dev *input; |
fff71312 RP |
89 | char phys[32]; |
90 | ||
91 | spinlock_t lock; | |
92 | struct timer_list timer; | |
93 | struct timer_list htimer; | |
94 | ||
95 | unsigned int suspended; | |
96 | unsigned long suspend_jiffies; | |
97 | }; | |
98 | ||
99 | #define KB_DISCHARGE_DELAY 10 | |
100 | #define KB_ACTIVATE_DELAY 10 | |
101 | ||
102 | /* Helper functions for reading the keyboard matrix | |
103 | * Note: We should really be using pxa_gpio_mode to alter GPDR but it | |
104 | * requires a function call per GPIO bit which is excessive | |
105 | * when we need to access 11 bits at once, multiple times. | |
106 | * These functions must be called within local_irq_save()/local_irq_restore() | |
107 | * or similar. | |
108 | */ | |
109 | static inline void spitzkbd_discharge_all(void) | |
110 | { | |
111 | /* STROBE All HiZ */ | |
112 | GPCR0 = SPITZ_GPIO_G0_STROBE_BIT; | |
113 | GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; | |
114 | GPCR1 = SPITZ_GPIO_G1_STROBE_BIT; | |
115 | GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; | |
116 | GPCR2 = SPITZ_GPIO_G2_STROBE_BIT; | |
117 | GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; | |
118 | GPCR3 = SPITZ_GPIO_G3_STROBE_BIT; | |
119 | GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; | |
120 | } | |
121 | ||
122 | static inline void spitzkbd_activate_all(void) | |
123 | { | |
124 | /* STROBE ALL -> High */ | |
125 | GPSR0 = SPITZ_GPIO_G0_STROBE_BIT; | |
126 | GPDR0 |= SPITZ_GPIO_G0_STROBE_BIT; | |
127 | GPSR1 = SPITZ_GPIO_G1_STROBE_BIT; | |
128 | GPDR1 |= SPITZ_GPIO_G1_STROBE_BIT; | |
129 | GPSR2 = SPITZ_GPIO_G2_STROBE_BIT; | |
130 | GPDR2 |= SPITZ_GPIO_G2_STROBE_BIT; | |
131 | GPSR3 = SPITZ_GPIO_G3_STROBE_BIT; | |
132 | GPDR3 |= SPITZ_GPIO_G3_STROBE_BIT; | |
133 | ||
134 | udelay(KB_DISCHARGE_DELAY); | |
135 | ||
136 | /* Clear any interrupts we may have triggered when altering the GPIO lines */ | |
137 | GEDR0 = SPITZ_GPIO_G0_SENSE_BIT; | |
138 | GEDR1 = SPITZ_GPIO_G1_SENSE_BIT; | |
139 | GEDR2 = SPITZ_GPIO_G2_SENSE_BIT; | |
140 | GEDR3 = SPITZ_GPIO_G3_SENSE_BIT; | |
141 | } | |
142 | ||
143 | static inline void spitzkbd_activate_col(int col) | |
144 | { | |
145 | int gpio = spitz_strobes[col]; | |
146 | GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; | |
147 | GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; | |
148 | GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; | |
149 | GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; | |
150 | GPSR(gpio) = GPIO_bit(gpio); | |
151 | GPDR(gpio) |= GPIO_bit(gpio); | |
152 | } | |
153 | ||
154 | static inline void spitzkbd_reset_col(int col) | |
155 | { | |
156 | int gpio = spitz_strobes[col]; | |
157 | GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; | |
158 | GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; | |
159 | GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; | |
160 | GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; | |
161 | GPCR(gpio) = GPIO_bit(gpio); | |
162 | GPDR(gpio) |= GPIO_bit(gpio); | |
163 | } | |
164 | ||
165 | static inline int spitzkbd_get_row_status(int col) | |
166 | { | |
167 | return ((GPLR0 >> 12) & 0x01) | ((GPLR0 >> 16) & 0x02) | |
168 | | ((GPLR2 >> 25) & 0x04) | ((GPLR1 << 1) & 0x08) | |
169 | | ((GPLR1 >> 0) & 0x10) | ((GPLR1 >> 1) & 0x60); | |
170 | } | |
171 | ||
172 | /* | |
173 | * The spitz keyboard only generates interrupts when a key is pressed. | |
174 | * When a key is pressed, we enable a timer which then scans the | |
175 | * keyboard to detect when the key is released. | |
176 | */ | |
177 | ||
178 | /* Scan the hardware keyboard and push any changes up through the input layer */ | |
179 | static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs *regs) | |
180 | { | |
181 | unsigned int row, col, rowd; | |
182 | unsigned long flags; | |
183 | unsigned int num_pressed, pwrkey = ((GPLR(SPITZ_GPIO_ON_KEY) & GPIO_bit(SPITZ_GPIO_ON_KEY)) != 0); | |
184 | ||
185 | if (spitzkbd_data->suspended) | |
186 | return; | |
187 | ||
188 | spin_lock_irqsave(&spitzkbd_data->lock, flags); | |
189 | ||
3c42f0c3 | 190 | input_regs(spitzkbd_data->input, regs); |
fff71312 RP |
191 | |
192 | num_pressed = 0; | |
193 | for (col = 0; col < KB_COLS; col++) { | |
194 | /* | |
195 | * Discharge the output driver capacitatance | |
196 | * in the keyboard matrix. (Yes it is significant..) | |
197 | */ | |
198 | ||
199 | spitzkbd_discharge_all(); | |
200 | udelay(KB_DISCHARGE_DELAY); | |
201 | ||
202 | spitzkbd_activate_col(col); | |
203 | udelay(KB_ACTIVATE_DELAY); | |
204 | ||
205 | rowd = spitzkbd_get_row_status(col); | |
206 | for (row = 0; row < KB_ROWS; row++) { | |
207 | unsigned int scancode, pressed; | |
208 | ||
209 | scancode = SCANCODE(row, col); | |
210 | pressed = rowd & KB_ROWMASK(row); | |
211 | ||
3c42f0c3 | 212 | input_report_key(spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed); |
fff71312 RP |
213 | |
214 | if (pressed) | |
215 | num_pressed++; | |
216 | } | |
217 | spitzkbd_reset_col(col); | |
218 | } | |
219 | ||
220 | spitzkbd_activate_all(); | |
221 | ||
3c42f0c3 DT |
222 | input_report_key(spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 ); |
223 | input_report_key(spitzkbd_data->input, KEY_SUSPEND, pwrkey); | |
fff71312 RP |
224 | |
225 | if (pwrkey && time_after(jiffies, spitzkbd_data->suspend_jiffies + msecs_to_jiffies(1000))) { | |
3c42f0c3 | 226 | input_event(spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1); |
fff71312 RP |
227 | spitzkbd_data->suspend_jiffies = jiffies; |
228 | } | |
229 | ||
3c42f0c3 | 230 | input_sync(spitzkbd_data->input); |
fff71312 RP |
231 | |
232 | /* if any keys are pressed, enable the timer */ | |
233 | if (num_pressed) | |
4872f788 | 234 | mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL)); |
fff71312 RP |
235 | |
236 | spin_unlock_irqrestore(&spitzkbd_data->lock, flags); | |
237 | } | |
238 | ||
239 | /* | |
240 | * spitz keyboard interrupt handler. | |
241 | */ | |
242 | static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |
243 | { | |
244 | struct spitzkbd *spitzkbd_data = dev_id; | |
245 | ||
246 | if (!timer_pending(&spitzkbd_data->timer)) { | |
247 | /** wait chattering delay **/ | |
248 | udelay(20); | |
249 | spitzkbd_scankeyboard(spitzkbd_data, regs); | |
250 | } | |
251 | ||
252 | return IRQ_HANDLED; | |
253 | } | |
254 | ||
255 | /* | |
256 | * spitz timer checking for released keys | |
257 | */ | |
258 | static void spitzkbd_timer_callback(unsigned long data) | |
259 | { | |
260 | struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; | |
3c42f0c3 | 261 | |
fff71312 RP |
262 | spitzkbd_scankeyboard(spitzkbd_data, NULL); |
263 | } | |
264 | ||
265 | /* | |
266 | * The hinge switches generate an interrupt. | |
267 | * We debounce the switches and pass them to the input system. | |
268 | */ | |
269 | ||
270 | static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id, struct pt_regs *regs) | |
271 | { | |
272 | struct spitzkbd *spitzkbd_data = dev_id; | |
273 | ||
274 | if (!timer_pending(&spitzkbd_data->htimer)) | |
275 | mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); | |
276 | ||
277 | return IRQ_HANDLED; | |
278 | } | |
279 | ||
280 | #define HINGE_STABLE_COUNT 2 | |
281 | static int sharpsl_hinge_state; | |
282 | static int hinge_count; | |
283 | ||
284 | static void spitzkbd_hinge_timer(unsigned long data) | |
285 | { | |
286 | struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; | |
287 | unsigned long state; | |
288 | unsigned long flags; | |
289 | ||
290 | state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB)); | |
4872f788 | 291 | state |= (GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)); |
fff71312 RP |
292 | if (state != sharpsl_hinge_state) { |
293 | hinge_count = 0; | |
294 | sharpsl_hinge_state = state; | |
295 | } else if (hinge_count < HINGE_STABLE_COUNT) { | |
296 | hinge_count++; | |
297 | } | |
298 | ||
299 | if (hinge_count >= HINGE_STABLE_COUNT) { | |
300 | spin_lock_irqsave(&spitzkbd_data->lock, flags); | |
301 | ||
ed8f9e2f RP |
302 | input_report_switch(spitzkbd_data->input, SW_LID, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0)); |
303 | input_report_switch(spitzkbd_data->input, SW_TABLET_MODE, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0)); | |
304 | input_report_switch(spitzkbd_data->input, SW_HEADPHONE_INSERT, ((GPLR(SPITZ_GPIO_AK_INT) & GPIO_bit(SPITZ_GPIO_AK_INT)) != 0)); | |
3c42f0c3 | 305 | input_sync(spitzkbd_data->input); |
fff71312 RP |
306 | |
307 | spin_unlock_irqrestore(&spitzkbd_data->lock, flags); | |
308 | } else { | |
309 | mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); | |
310 | } | |
311 | } | |
312 | ||
313 | #ifdef CONFIG_PM | |
3ae5eaec | 314 | static int spitzkbd_suspend(struct platform_device *dev, pm_message_t state) |
fff71312 | 315 | { |
9480e307 | 316 | int i; |
3ae5eaec | 317 | struct spitzkbd *spitzkbd = platform_get_drvdata(dev); |
9480e307 RK |
318 | spitzkbd->suspended = 1; |
319 | ||
320 | /* Set Strobe lines as inputs - *except* strobe line 0 leave this | |
321 | enabled so we can detect a power button press for resume */ | |
322 | for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++) | |
323 | pxa_gpio_mode(spitz_strobes[i] | GPIO_IN); | |
324 | ||
fff71312 RP |
325 | return 0; |
326 | } | |
327 | ||
3ae5eaec | 328 | static int spitzkbd_resume(struct platform_device *dev) |
fff71312 | 329 | { |
9480e307 | 330 | int i; |
3ae5eaec | 331 | struct spitzkbd *spitzkbd = platform_get_drvdata(dev); |
fff71312 | 332 | |
9480e307 RK |
333 | for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) |
334 | pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); | |
335 | ||
336 | /* Upon resume, ignore the suspend key for a short while */ | |
337 | spitzkbd->suspend_jiffies = jiffies; | |
338 | spitzkbd->suspended = 0; | |
fff71312 | 339 | |
fff71312 RP |
340 | return 0; |
341 | } | |
342 | #else | |
343 | #define spitzkbd_suspend NULL | |
344 | #define spitzkbd_resume NULL | |
345 | #endif | |
346 | ||
3ae5eaec | 347 | static int __init spitzkbd_probe(struct platform_device *dev) |
fff71312 | 348 | { |
fff71312 | 349 | struct spitzkbd *spitzkbd; |
3c42f0c3 DT |
350 | struct input_dev *input_dev; |
351 | int i; | |
fff71312 RP |
352 | |
353 | spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL); | |
354 | if (!spitzkbd) | |
355 | return -ENOMEM; | |
356 | ||
3c42f0c3 DT |
357 | input_dev = input_allocate_device(); |
358 | if (!input_dev) { | |
359 | kfree(spitzkbd); | |
360 | return -ENOMEM; | |
361 | } | |
362 | ||
3ae5eaec | 363 | platform_set_drvdata(dev, spitzkbd); |
fff71312 RP |
364 | strcpy(spitzkbd->phys, "spitzkbd/input0"); |
365 | ||
366 | spin_lock_init(&spitzkbd->lock); | |
367 | ||
368 | /* Init Keyboard rescan timer */ | |
369 | init_timer(&spitzkbd->timer); | |
370 | spitzkbd->timer.function = spitzkbd_timer_callback; | |
371 | spitzkbd->timer.data = (unsigned long) spitzkbd; | |
372 | ||
373 | /* Init Hinge Timer */ | |
374 | init_timer(&spitzkbd->htimer); | |
375 | spitzkbd->htimer.function = spitzkbd_hinge_timer; | |
376 | spitzkbd->htimer.data = (unsigned long) spitzkbd; | |
377 | ||
3c42f0c3 DT |
378 | spitzkbd->suspend_jiffies = jiffies; |
379 | ||
380 | spitzkbd->input = input_dev; | |
381 | ||
382 | input_dev->private = spitzkbd; | |
383 | input_dev->name = "Spitz Keyboard"; | |
384 | input_dev->phys = spitzkbd->phys; | |
3ae5eaec | 385 | input_dev->cdev.dev = &dev->dev; |
3c42f0c3 DT |
386 | |
387 | input_dev->id.bustype = BUS_HOST; | |
388 | input_dev->id.vendor = 0x0001; | |
389 | input_dev->id.product = 0x0001; | |
390 | input_dev->id.version = 0x0100; | |
391 | ||
392 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); | |
393 | input_dev->keycode = spitzkbd->keycode; | |
394 | input_dev->keycodesize = sizeof(unsigned char); | |
395 | input_dev->keycodemax = ARRAY_SIZE(spitzkbd_keycode); | |
fff71312 RP |
396 | |
397 | memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode)); | |
398 | for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++) | |
3c42f0c3 DT |
399 | set_bit(spitzkbd->keycode[i], input_dev->keybit); |
400 | clear_bit(0, input_dev->keybit); | |
ed8f9e2f RP |
401 | set_bit(SW_LID, input_dev->swbit); |
402 | set_bit(SW_TABLET_MODE, input_dev->swbit); | |
403 | set_bit(SW_HEADPHONE_INSERT, input_dev->swbit); | |
3c42f0c3 DT |
404 | |
405 | input_register_device(input_dev); | |
fff71312 | 406 | |
fff71312 RP |
407 | mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); |
408 | ||
409 | /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ | |
410 | for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) { | |
411 | pxa_gpio_mode(spitz_senses[i] | GPIO_IN); | |
412 | if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt, | |
dace1453 | 413 | IRQF_DISABLED|IRQF_TRIGGER_RISING, |
9ded96f2 | 414 | "Spitzkbd Sense", spitzkbd)) |
fff71312 | 415 | printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i); |
fff71312 RP |
416 | } |
417 | ||
418 | /* Set Strobe lines as outputs - set high */ | |
419 | for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) | |
420 | pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); | |
421 | ||
422 | pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN); | |
423 | pxa_gpio_mode(SPITZ_GPIO_ON_KEY | GPIO_IN); | |
424 | pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN); | |
425 | pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN); | |
426 | ||
9ded96f2 | 427 | request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, |
dace1453 | 428 | IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
9ded96f2 RK |
429 | "Spitzkbd Sync", spitzkbd); |
430 | request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, | |
dace1453 | 431 | IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
9ded96f2 RK |
432 | "Spitzkbd PwrOn", spitzkbd); |
433 | request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, | |
dace1453 | 434 | IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
9ded96f2 RK |
435 | "Spitzkbd SWA", spitzkbd); |
436 | request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, | |
dace1453 | 437 | IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
9ded96f2 | 438 | "Spitzkbd SWB", spitzkbd); |
4872f788 | 439 | request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr, |
dace1453 | 440 | IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, |
4872f788 | 441 | "Spitzkbd HP", spitzkbd); |
fff71312 RP |
442 | |
443 | printk(KERN_INFO "input: Spitz Keyboard Registered\n"); | |
444 | ||
445 | return 0; | |
446 | } | |
447 | ||
3ae5eaec | 448 | static int spitzkbd_remove(struct platform_device *dev) |
fff71312 RP |
449 | { |
450 | int i; | |
3ae5eaec | 451 | struct spitzkbd *spitzkbd = platform_get_drvdata(dev); |
fff71312 RP |
452 | |
453 | for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) | |
454 | free_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd); | |
455 | ||
456 | free_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd); | |
457 | free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd); | |
458 | free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd); | |
459 | free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd); | |
4872f788 | 460 | free_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd); |
fff71312 RP |
461 | |
462 | del_timer_sync(&spitzkbd->htimer); | |
463 | del_timer_sync(&spitzkbd->timer); | |
464 | ||
3c42f0c3 | 465 | input_unregister_device(spitzkbd->input); |
fff71312 RP |
466 | |
467 | kfree(spitzkbd); | |
468 | ||
469 | return 0; | |
470 | } | |
471 | ||
3ae5eaec | 472 | static struct platform_driver spitzkbd_driver = { |
fff71312 RP |
473 | .probe = spitzkbd_probe, |
474 | .remove = spitzkbd_remove, | |
475 | .suspend = spitzkbd_suspend, | |
476 | .resume = spitzkbd_resume, | |
3ae5eaec RK |
477 | .driver = { |
478 | .name = "spitz-keyboard", | |
479 | }, | |
fff71312 RP |
480 | }; |
481 | ||
482 | static int __devinit spitzkbd_init(void) | |
483 | { | |
3ae5eaec | 484 | return platform_driver_register(&spitzkbd_driver); |
fff71312 RP |
485 | } |
486 | ||
487 | static void __exit spitzkbd_exit(void) | |
488 | { | |
3ae5eaec | 489 | platform_driver_unregister(&spitzkbd_driver); |
fff71312 RP |
490 | } |
491 | ||
492 | module_init(spitzkbd_init); | |
493 | module_exit(spitzkbd_exit); | |
494 | ||
495 | MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); | |
496 | MODULE_DESCRIPTION("Spitz Keyboard Driver"); | |
497 | MODULE_LICENSE("GPLv2"); |