blob: 266a3a29cacf4425dbbdd3bc0dec743b83540353 [file] [log] [blame]
Gary Kinge550e3f2009-12-11 10:58:20 -08001/*
2 * drivers/input/keyboard/tegra-nvec.c
3 *
4 * Keyboard class input driver for keyboards connected to an NvEc compliant
5 * embedded controller
6 *
7 * Copyright (c) 2009, NVIDIA Corporation.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24#include <linux/module.h>
25#include <linux/input.h>
26#include <linux/platform_device.h>
27#include <linux/kthread.h>
Gary King1147a072009-12-15 17:42:32 -080028#include <linux/tegra_devices.h>
Ninad Malwadec1418ca2010-02-03 13:35:28 +053029#include <linux/freezer.h>
Gary Kinge550e3f2009-12-11 10:58:20 -080030
31#include "nvos.h"
32#include "nvec.h"
33#include "nvodm_services.h"
34#include "nvodm_keyboard.h"
35
36#define DRIVER_DESC "NvEc keyboard driver"
37#define DRIVER_LICENSE "GPL"
38
39MODULE_DESCRIPTION(DRIVER_DESC);
40MODULE_LICENSE(DRIVER_LICENSE);
41
42#define NVEC_PAYLOAD 32
43
44/* The total number of scan codes will be (first - last) */
45#define EC_FIRST_CODE 0x00
46#define EC_LAST_CODE 0x58
47#define EC_TOTAL_CODES (EC_LAST_CODE - EC_FIRST_CODE + 1)
48
49/**
50 * @brief This is the actual Scan-code-to-VKey mapping table. For new layouts
51 * this is the only structure which needs to be modified to return the
52 * proper vkey depending on the scan code.
53 */
54NvU8 code_tab_102us[EC_TOTAL_CODES] = {
55 KEY_GRAVE, // 0x00
56 KEY_BACK,
57 KEY_1,
58 KEY_2,
59 KEY_3,
60 KEY_4,
61 KEY_5,
62 KEY_6,
63 KEY_7,
64 KEY_8,
65 KEY_9,
66 KEY_0,
67 KEY_MINUS,
68 KEY_EQUAL,
69 KEY_BACKSPACE,
70 KEY_TAB,
71 KEY_Q, // 0x10
72 KEY_W,
73 KEY_E,
74 KEY_R,
75 KEY_T,
76 KEY_Y,
77 KEY_U,
78 KEY_I,
79 KEY_O,
80 KEY_P,
81 KEY_LEFTBRACE,
82 KEY_RIGHTBRACE,
83 KEY_ENTER,
84 KEY_LEFTCTRL,
85 KEY_A,
86 KEY_S,
87 KEY_D, // 0x20
88 KEY_F,
89 KEY_G,
90 KEY_H,
91 KEY_J,
92 KEY_K,
93 KEY_L,
94 KEY_SEMICOLON,
95 KEY_APOSTROPHE,
96 KEY_GRAVE,
97 KEY_LEFTSHIFT,
98 KEY_BACKSLASH,
99 KEY_Z,
100 KEY_X,
101 KEY_C,
102 KEY_V,
103 KEY_B, // 0x30
104 KEY_N,
105 KEY_M,
106 KEY_COMMA,
107 KEY_DOT,
108 KEY_SLASH,
109 KEY_RIGHTSHIFT,
110 KEY_KPASTERISK,
111 KEY_LEFTALT,
112 KEY_SPACE,
113 KEY_CAPSLOCK,
114 KEY_F1,
115 KEY_F2,
116 KEY_F3,
117 KEY_F4,
118 KEY_F5,
119 KEY_F6, // 0x40
120 KEY_F7,
121 KEY_F8,
122 KEY_F9,
123 KEY_F10,
124 KEY_NUMLOCK,
125 0, //VK_SCROLL
126 KEY_KP7,
127 KEY_KP8,
128 KEY_KP9,
129 KEY_KPMINUS,
130 KEY_KP4,
131 KEY_KP5,
132 KEY_KP6,
133 KEY_KPPLUS,
134 KEY_KP1,
135 KEY_KP2, // 0x50
136 KEY_KP3,
137 KEY_KP0,
Gary King1147a072009-12-15 17:42:32 -0800138 KEY_KPDOT,
Gary Kinge550e3f2009-12-11 10:58:20 -0800139 0, //VK_SNAPSHOT
140 0,
141 0, //VK_OEM_102
142 0, //VK_F11
143 0, //VK_F12
144};
145
146/* The total number of scan codes will be (first - last) */
147#define EC_EXT_CODE_FIRST 0xE010
148#define EC_EXT_CODE_LAST 0xE06D
149#define EC_EXT_TOTAL_CODES (EC_EXT_CODE_LAST - EC_EXT_CODE_FIRST + 1)
150
151/**
152 * @brief This table consists of the scan codes which were added after the
153 * original scan codes were designed.
154 * To avoid moving the already designed buttons to accomodate these
155 * new buttons, the new scan codes are preceded by 'E0'.
156 */
157NvU8 extcode_tab_us102[EC_EXT_TOTAL_CODES] = {
158 0, // 0xE0 0x10
159 0,
160 0,
161 0,
162 0,
163 0,
164 0,
165 0,
166 0,
167 0, //VK_MEDIA_NEXT_TRACK,
168 0,
169 0,
170 0, //VK_RETURN,
171 0, //VK_RCONTROL,
172 0,
173 0,
174 KEY_MUTE, // 0xE0 0x20
175 0, //VK_LAUNCH_APP1
176 0, //VK_MEDIA_PLAY_PAUSE
177 0,
178 0, //VK_MEDIA_STOP
179 0,
180 0,
181 0,
182 0,
183 0,
184 0,
185 0,
186 0,
187 0,
188 KEY_VOLUMEDOWN,
189 0,
190 KEY_VOLUMEUP, // 0xE0 0x30
191 0,
192 0, //VK_BROWSER_HOME
193 0,
194 0,
195 KEY_KPSLASH, //VK_DIVIDE
196 0,
197 0, //VK_SNAPSHOT
198 0, //VK_RMENU
199 0, //VK_OEM_NV_BACKLIGHT_UP
200 0, //VK_OEM_NV_BACKLIGHT_DN
201 0, //VK_OEM_NV_BACKLIGHT_AUTOTOGGLE
202 0, //VK_OEM_NV_POWER_INFO
203 0, //VK_OEM_NV_WIFI_TOGGLE
204 0, //VK_OEM_NV_DISPLAY_SELECT
205 0, //VK_OEM_NV_AIRPLANE_TOGGLE
206 0, //0xE0 0x40
207 0, //VK_OEM_NV_RESERVED
208 0, //VK_OEM_NV_RESERVED
209 0, //VK_OEM_NV_RESERVED
210 0, //VK_OEM_NV_RESERVED
211 0, //VK_OEM_NV_RESERVED
212 KEY_CANCEL,
213 KEY_HOME,
214 KEY_UP,
215 0, //VK_PRIOR
216 0,
217 KEY_LEFT,
218 0,
219 KEY_RIGHT,
220 0,
221 KEY_END,
222 KEY_DOWN, // 0xE0 0x50
223 0, //VK_NEXT
224 KEY_INSERT,
225 KEY_DELETE,
226 0,
227 0,
228 0,
229 0,
230 0,
231 0,
232 0,
233 KEY_MENU, //VK_LWIN
234 0, //VK_RWIN
235 KEY_BACK, //VK_APPS
236 0,
237 0,
238 0, // 0xE0 0x60
239 0,
240 0,
241 0,
242 0,
243 0, //VK_BROWSER_SEARCH
244 0, //VK_BROWSER_FAVORITES
245 0, //VK_BROWSER_REFRESH
246 0, //VK_BROWSER_STOP
247 0, //VK_BROWSER_FORWARD
248 0, //VK_BROWSER_BACK
249 0, //VK_LAUNCH_APP2
250 0, //VK_LAUNCH_MAIL
251 0, //VK_LAUNCH_MEDIA_SELECT
252};
253
254struct nvec_keyboard
255{
256 struct input_dev *input_dev;
257 struct task_struct *task;
258 char name[128];
Ninad Malwadea531df92010-01-28 20:42:39 +0530259 int shutdown;
Gary Kinge550e3f2009-12-11 10:58:20 -0800260 unsigned short keycode[512];
261 NvEcHandle hNvec;
262 NvEcEventRegistrationHandle hEvent;
263};
264
265static struct platform_device *nvec_keyboard_device;
266
267static int nvec_keyboard_recv(void *arg)
268{
269 struct input_dev *input_dev = (struct input_dev *)arg;
270 struct nvec_keyboard *keyboard = input_get_drvdata(input_dev);
271
Ninad Malwadec1418ca2010-02-03 13:35:28 +0530272 /* keyboard event thread should be frozen before suspending the
273 * keyboard and NVEC drivers */
274 set_freezable_with_signal();
275
Ninad Malwadea531df92010-01-28 20:42:39 +0530276 while (!keyboard->shutdown) {
Gary Kinge550e3f2009-12-11 10:58:20 -0800277 unsigned int pressed;
278 NvU32 code;
279 NvU8 flags;
280
281 if (!NvOdmKeyboardGetKeyData(&code, &flags, 0)) {
282 printk(KERN_INFO "nvec_keyboard: unhandled "
283 "scancode %x\n", code);
284 continue;
285 }
286
Ninad Malwadea531df92010-01-28 20:42:39 +0530287 if (keyboard->shutdown)
288 break;
Gary Kinge550e3f2009-12-11 10:58:20 -0800289
290 pressed = (flags & NV_ODM_SCAN_CODE_FLAG_MAKE);
291
292
293 if ((code >= EC_FIRST_CODE) && (code <= EC_LAST_CODE)) {
294 code -= EC_FIRST_CODE;
295 code = code_tab_102us[code];
296 input_report_key(keyboard->input_dev, code, pressed);
297 }
298 else if ((code >= EC_EXT_CODE_FIRST) &&
299 (code <= EC_EXT_CODE_LAST)) {
300
301 code -= EC_EXT_CODE_FIRST;
302 code = extcode_tab_us102[code];
303 input_report_key(keyboard->input_dev, code, pressed);
304 }
305 }
306
307 return 0;
308}
309
310static int nvec_keyboard_open(struct input_dev *dev)
311{
312 return 0;
313}
314
315static void nvec_keyboard_close(struct input_dev *dev)
316{
317 return;
318}
319
Gary Kinge550e3f2009-12-11 10:58:20 -0800320static int __devinit nvec_keyboard_probe(struct platform_device *pdev)
321{
322 int error;
323 NvError nverr;
324 struct nvec_keyboard *keyboard;
325 struct input_dev *input_dev;
326 int i;
327
328 keyboard = kzalloc(sizeof(struct nvec_keyboard), GFP_KERNEL);
329 input_dev = input_allocate_device();
330 if (!keyboard || !input_dev) {
331 error = -ENOMEM;
332 goto fail;
333 }
334
335 keyboard->input_dev = input_dev;
336 input_set_drvdata(input_dev, keyboard);
337 platform_set_drvdata(pdev, input_dev);
338
339 if (!NvOdmKeyboardInit()) {
340 error = -ENODEV;
341 pr_err("tegra_keyboard_probe: no keyboard\n");
342 goto fail_keyboard_init;
343 }
344
345 keyboard->task = kthread_create(nvec_keyboard_recv, input_dev,
346 "nvec_keyboard_thread");
347 if (keyboard->task == NULL) {
348 error = -ENOMEM;
349 goto fail_thread_create;
350 }
351 wake_up_process(keyboard->task);
352
353 if (!strlen(keyboard->name))
354 snprintf(keyboard->name, sizeof(keyboard->name),
355 "nvec keyboard");
356
357 input_dev->name = keyboard->name;
358 input_dev->open = nvec_keyboard_open;
359 input_dev->close = nvec_keyboard_close;
360
361 __set_bit(EV_KEY, input_dev->evbit);
362 for (i=1; i<EC_TOTAL_CODES; i++) {
363 __set_bit(code_tab_102us[i], input_dev->keybit);
364 }
365 for (i=1; i<EC_EXT_TOTAL_CODES; i++) {
366 __set_bit(extcode_tab_us102[i], input_dev->keybit);
367 }
368
Varun Wadekar87826b72010-01-21 20:53:04 +0530369 /* get EC handle */
370 nverr = NvEcOpen(&keyboard->hNvec, 0 /* instance */);
371 if (nverr != NvError_Success) {
Gary King3f3eefc2010-02-22 11:24:30 -0800372 error = -ENODEV;
Varun Wadekar87826b72010-01-21 20:53:04 +0530373 goto fail_input_register;
374 }
375
Gary Kinge550e3f2009-12-11 10:58:20 -0800376 error = input_register_device(keyboard->input_dev);
377 if (error)
378 goto fail_input_register;
379
380 return 0;
381
382fail_input_register:
383 (void)kthread_stop(keyboard->task);
384fail_thread_create:
385 NvOdmKeyboardDeInit();
386fail_keyboard_init:
387fail:
Varun Wadekar87826b72010-01-21 20:53:04 +0530388 NvEcClose(keyboard->hNvec);
389 keyboard->hNvec = NULL;
Gary Kinge550e3f2009-12-11 10:58:20 -0800390 input_free_device(input_dev);
391 kfree(keyboard);
392
393 return error;
394}
395
396static int __devexit nvec_keyboard_remove(struct platform_device *dev)
397{
398 struct input_dev *input_dev = platform_get_drvdata(dev);
Varun Wadekar87826b72010-01-21 20:53:04 +0530399 struct nvec_keyboard *keyboard = input_get_drvdata(input_dev);
Gary Kinge550e3f2009-12-11 10:58:20 -0800400
401 (void)kthread_stop(keyboard->task);
402 NvOdmKeyboardDeInit();
Varun Wadekar87826b72010-01-21 20:53:04 +0530403 NvEcClose(keyboard->hNvec);
404 keyboard->hNvec = NULL;
Ninad Malwadea531df92010-01-28 20:42:39 +0530405 keyboard->shutdown = 1;
Gary Kinge550e3f2009-12-11 10:58:20 -0800406 input_free_device(input_dev);
407 kfree(keyboard);
408
409 return 0;
410}
411
Gary King3f3eefc2010-02-22 11:24:30 -0800412#ifdef ENABLE_NVEC_KBD_SUSPEND
Varun Wadekar87826b72010-01-21 20:53:04 +0530413static int nvec_keyboard_suspend(struct platform_device *pdev, pm_message_t state)
414{
415 NvEcRequest Request = {0};
416 NvEcResponse Response = {0};
417 struct input_dev *input_dev = platform_get_drvdata(pdev);
418 struct nvec_keyboard *keyboard = input_get_drvdata(input_dev);
419 NvError err = NvError_Success;
420
421 if (!keyboard) {
422 printk("%s: device handle is NULL\n", __func__);
423 return -1;
424 }
425
426 /* disable keyboard scanning */
427 Request.PacketType = NvEcPacketType_Request;
428 Request.RequestType = NvEcRequestResponseType_Keyboard;
429 Request.RequestSubtype =
430 (NvEcRequestResponseSubtype)NvEcKeyboardSubtype_Disable;
431 Request.NumPayloadBytes = 0;
432
433 err = NvEcSendRequest(
434 keyboard->hNvec,
435 &Request,
436 &Response,
437 sizeof(Request),
438 sizeof(Response));
439 if (err != NvError_Success) {
440 printk("%s: scanning disable request send fail\n", __func__);
441 return -1;
442 }
443
444 if (Response.Status != NvEcStatus_Success) {
445 printk("%s: scanning could not be disabled\n", __func__);
446 return -1;
447 }
448
449 /* power down hardware */
450 if (!NvOdmKeyboardPowerHandler(NV_TRUE)) {
451 printk("%s: hardware power down fail\n", __func__);
452 return -1;
453 }
454
455 return 0;
456}
457
458static int nvec_keyboard_resume(struct platform_device *pdev)
459{
460 NvEcRequest Request = {0};
461 NvEcResponse Response = {0};
462 struct input_dev *input_dev = platform_get_drvdata(pdev);
463 struct nvec_keyboard *keyboard = input_get_drvdata(input_dev);
464 NvError err = NvError_Success;
465
466 if (!keyboard) {
467 printk("%s: device handle is NULL\n", __func__);
468 return -1;
469 }
470
471 /* power up hardware */
472 if (!NvOdmKeyboardPowerHandler(NV_FALSE)) {
473 printk("%s: hardware power up fail\n", __func__);
474 return -1;
475 }
476
477 /* re-enable keyboard scanning */
478 Request.PacketType = NvEcPacketType_Request;
479 Request.RequestType = NvEcRequestResponseType_Keyboard;
480 Request.RequestSubtype =
481 (NvEcRequestResponseSubtype)NvEcKeyboardSubtype_Enable;
482 Request.NumPayloadBytes = 0;
483
484 err = NvEcSendRequest(
485 keyboard->hNvec,
486 &Request,
487 &Response,
488 sizeof(Request),
489 sizeof(Response));
490 if (err != NvError_Success) {
491 printk("%s: scanning enable request send fail\n", __func__);
492 return -1;
493 }
494
495 if (Response.Status != NvEcStatus_Success) {
496 printk("%s: scanning could not be enabled\n", __func__);
497 return -1;
498 }
499
500 return 0;
501}
Gary King3f3eefc2010-02-22 11:24:30 -0800502#endif /* ENABLE_NVEC_KBD_SUSPEND */
Varun Wadekar87826b72010-01-21 20:53:04 +0530503
Gary Kinge550e3f2009-12-11 10:58:20 -0800504static struct platform_driver nvec_keyboard_driver = {
505 .driver = {
506 .name = "nvec_keyboard",
507 .owner = THIS_MODULE,
508 },
509 .probe = nvec_keyboard_probe,
510 .remove = __devexit_p(nvec_keyboard_remove),
Gary King3f3eefc2010-02-22 11:24:30 -0800511#ifdef ENABLE_NVEC_KBD_SUSPEND
Varun Wadekar87826b72010-01-21 20:53:04 +0530512 .suspend = nvec_keyboard_suspend,
513 .resume = nvec_keyboard_resume,
Gary King3f3eefc2010-02-22 11:24:30 -0800514#endif
Gary Kinge550e3f2009-12-11 10:58:20 -0800515};
516
Gary Kinge550e3f2009-12-11 10:58:20 -0800517static int __init nvec_keyboard_init(void)
518{
519 int err;
520
521 err = platform_driver_register(&nvec_keyboard_driver);
522 if (err) {
523 goto error;
524 }
525
526 nvec_keyboard_device = platform_device_alloc("nvec_keyboard", -1);
527 if (!nvec_keyboard_device) {
528 err = -ENOMEM;
529 goto error_unregister_driver;
530 }
531
532 err = platform_device_add(nvec_keyboard_device);
533 if (err)
534 goto error_free_device;
535
536 return 0;
537
538error_free_device:
539 platform_device_put(nvec_keyboard_device);
540error_unregister_driver:
541 platform_driver_unregister(&nvec_keyboard_driver);
542error:
543 return err;
544}
545
546static void __exit nvec_keyboard_exit(void)
547{
548 platform_device_unregister(nvec_keyboard_device);
549 platform_driver_unregister(&nvec_keyboard_driver);
550}
551
552module_init(nvec_keyboard_init);
553module_exit(nvec_keyboard_exit);
554