blob: 883b1c7bdb0aaf41a49b3eb7549f0b393361c9c0 [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>
Ninad Malwade92891e22010-02-26 13:54:32 +053026#include <linux/device.h>
Gary Kinge550e3f2009-12-11 10:58:20 -080027#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"
Ninad Malwade92891e22010-02-26 13:54:32 +053035#include "nvec_device.h"
Gary Kinge550e3f2009-12-11 10:58:20 -080036
37#define DRIVER_DESC "NvEc keyboard driver"
38#define DRIVER_LICENSE "GPL"
39
40MODULE_DESCRIPTION(DRIVER_DESC);
41MODULE_LICENSE(DRIVER_LICENSE);
42
43#define NVEC_PAYLOAD 32
Varun Wadekar68a38772010-04-19 11:53:44 +053044#define KEYBOARD_SCANNING_DISABLED_IN_SUSPEND 0
Gary Kinge550e3f2009-12-11 10:58:20 -080045
46/* The total number of scan codes will be (first - last) */
47#define EC_FIRST_CODE 0x00
48#define EC_LAST_CODE 0x58
49#define EC_TOTAL_CODES (EC_LAST_CODE - EC_FIRST_CODE + 1)
50
51/**
52 * @brief This is the actual Scan-code-to-VKey mapping table. For new layouts
53 * this is the only structure which needs to be modified to return the
54 * proper vkey depending on the scan code.
55 */
56NvU8 code_tab_102us[EC_TOTAL_CODES] = {
57 KEY_GRAVE, // 0x00
Sachin Nikam04d40532010-06-01 15:40:23 +053058 KEY_ESC,
Gary Kinge550e3f2009-12-11 10:58:20 -080059 KEY_1,
60 KEY_2,
61 KEY_3,
62 KEY_4,
63 KEY_5,
64 KEY_6,
65 KEY_7,
66 KEY_8,
67 KEY_9,
68 KEY_0,
69 KEY_MINUS,
70 KEY_EQUAL,
71 KEY_BACKSPACE,
72 KEY_TAB,
73 KEY_Q, // 0x10
74 KEY_W,
75 KEY_E,
76 KEY_R,
77 KEY_T,
78 KEY_Y,
79 KEY_U,
80 KEY_I,
81 KEY_O,
82 KEY_P,
83 KEY_LEFTBRACE,
84 KEY_RIGHTBRACE,
85 KEY_ENTER,
86 KEY_LEFTCTRL,
87 KEY_A,
88 KEY_S,
89 KEY_D, // 0x20
90 KEY_F,
91 KEY_G,
92 KEY_H,
93 KEY_J,
94 KEY_K,
95 KEY_L,
96 KEY_SEMICOLON,
97 KEY_APOSTROPHE,
98 KEY_GRAVE,
99 KEY_LEFTSHIFT,
100 KEY_BACKSLASH,
101 KEY_Z,
102 KEY_X,
103 KEY_C,
104 KEY_V,
105 KEY_B, // 0x30
106 KEY_N,
107 KEY_M,
108 KEY_COMMA,
109 KEY_DOT,
110 KEY_SLASH,
111 KEY_RIGHTSHIFT,
112 KEY_KPASTERISK,
113 KEY_LEFTALT,
114 KEY_SPACE,
115 KEY_CAPSLOCK,
116 KEY_F1,
117 KEY_F2,
118 KEY_F3,
119 KEY_F4,
120 KEY_F5,
121 KEY_F6, // 0x40
122 KEY_F7,
123 KEY_F8,
124 KEY_F9,
125 KEY_F10,
126 KEY_NUMLOCK,
127 0, //VK_SCROLL
128 KEY_KP7,
129 KEY_KP8,
130 KEY_KP9,
131 KEY_KPMINUS,
132 KEY_KP4,
133 KEY_KP5,
134 KEY_KP6,
135 KEY_KPPLUS,
136 KEY_KP1,
137 KEY_KP2, // 0x50
138 KEY_KP3,
139 KEY_KP0,
Gary King1147a072009-12-15 17:42:32 -0800140 KEY_KPDOT,
Gary Kinge550e3f2009-12-11 10:58:20 -0800141 0, //VK_SNAPSHOT
142 0,
143 0, //VK_OEM_102
144 0, //VK_F11
145 0, //VK_F12
146};
147
148/* The total number of scan codes will be (first - last) */
149#define EC_EXT_CODE_FIRST 0xE010
150#define EC_EXT_CODE_LAST 0xE06D
151#define EC_EXT_TOTAL_CODES (EC_EXT_CODE_LAST - EC_EXT_CODE_FIRST + 1)
152
153/**
154 * @brief This table consists of the scan codes which were added after the
155 * original scan codes were designed.
156 * To avoid moving the already designed buttons to accomodate these
157 * new buttons, the new scan codes are preceded by 'E0'.
158 */
159NvU8 extcode_tab_us102[EC_EXT_TOTAL_CODES] = {
160 0, // 0xE0 0x10
161 0,
162 0,
163 0,
164 0,
165 0,
166 0,
167 0,
168 0,
169 0, //VK_MEDIA_NEXT_TRACK,
170 0,
171 0,
172 0, //VK_RETURN,
173 0, //VK_RCONTROL,
174 0,
175 0,
176 KEY_MUTE, // 0xE0 0x20
177 0, //VK_LAUNCH_APP1
178 0, //VK_MEDIA_PLAY_PAUSE
179 0,
180 0, //VK_MEDIA_STOP
181 0,
182 0,
183 0,
184 0,
185 0,
186 0,
187 0,
188 0,
189 0,
190 KEY_VOLUMEDOWN,
191 0,
192 KEY_VOLUMEUP, // 0xE0 0x30
193 0,
194 0, //VK_BROWSER_HOME
195 0,
196 0,
197 KEY_KPSLASH, //VK_DIVIDE
198 0,
199 0, //VK_SNAPSHOT
200 0, //VK_RMENU
201 0, //VK_OEM_NV_BACKLIGHT_UP
202 0, //VK_OEM_NV_BACKLIGHT_DN
203 0, //VK_OEM_NV_BACKLIGHT_AUTOTOGGLE
204 0, //VK_OEM_NV_POWER_INFO
205 0, //VK_OEM_NV_WIFI_TOGGLE
206 0, //VK_OEM_NV_DISPLAY_SELECT
207 0, //VK_OEM_NV_AIRPLANE_TOGGLE
208 0, //0xE0 0x40
209 0, //VK_OEM_NV_RESERVED
210 0, //VK_OEM_NV_RESERVED
211 0, //VK_OEM_NV_RESERVED
212 0, //VK_OEM_NV_RESERVED
213 0, //VK_OEM_NV_RESERVED
214 KEY_CANCEL,
215 KEY_HOME,
216 KEY_UP,
217 0, //VK_PRIOR
218 0,
219 KEY_LEFT,
220 0,
221 KEY_RIGHT,
222 0,
223 KEY_END,
224 KEY_DOWN, // 0xE0 0x50
225 0, //VK_NEXT
226 KEY_INSERT,
227 KEY_DELETE,
228 0,
229 0,
230 0,
231 0,
232 0,
233 0,
234 0,
235 KEY_MENU, //VK_LWIN
236 0, //VK_RWIN
237 KEY_BACK, //VK_APPS
238 0,
239 0,
240 0, // 0xE0 0x60
241 0,
242 0,
243 0,
244 0,
245 0, //VK_BROWSER_SEARCH
246 0, //VK_BROWSER_FAVORITES
247 0, //VK_BROWSER_REFRESH
248 0, //VK_BROWSER_STOP
249 0, //VK_BROWSER_FORWARD
250 0, //VK_BROWSER_BACK
251 0, //VK_LAUNCH_APP2
252 0, //VK_LAUNCH_MAIL
253 0, //VK_LAUNCH_MEDIA_SELECT
254};
255
256struct nvec_keyboard
257{
258 struct input_dev *input_dev;
259 struct task_struct *task;
260 char name[128];
Ninad Malwadea531df92010-01-28 20:42:39 +0530261 int shutdown;
Gary Kinge550e3f2009-12-11 10:58:20 -0800262 unsigned short keycode[512];
263 NvEcHandle hNvec;
264 NvEcEventRegistrationHandle hEvent;
265};
266
Gary Kinge550e3f2009-12-11 10:58:20 -0800267static 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
Ninad Malwade92891e22010-02-26 13:54:32 +0530320static int __devinit nvec_keyboard_probe(struct nvec_device *pdev)
Gary Kinge550e3f2009-12-11 10:58:20 -0800321{
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);
Ninad Malwade92891e22010-02-26 13:54:32 +0530337 nvec_set_drvdata(pdev, input_dev);
Gary Kinge550e3f2009-12-11 10:58:20 -0800338
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
Sachin Nikamc3be44e2010-05-25 13:44:14 +0530396static void nvec_keyboard_remove(struct nvec_device *dev)
Gary Kinge550e3f2009-12-11 10:58:20 -0800397{
Ninad Malwade92891e22010-02-26 13:54:32 +0530398 struct input_dev *input_dev = nvec_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);
Gary Kinge550e3f2009-12-11 10:58:20 -0800408}
409
Ninad Malwade92891e22010-02-26 13:54:32 +0530410static int nvec_keyboard_suspend(struct nvec_device *pdev, pm_message_t state)
Varun Wadekar87826b72010-01-21 20:53:04 +0530411{
Varun Wadekar68a38772010-04-19 11:53:44 +0530412#if KEYBOARD_SCANNING_DISABLED_IN_SUSPEND
Varun Wadekar87826b72010-01-21 20:53:04 +0530413 NvEcRequest Request = {0};
414 NvEcResponse Response = {0};
Varun Wadekar68a38772010-04-19 11:53:44 +0530415 NvError err = NvError_Success;
416#endif
Ninad Malwade92891e22010-02-26 13:54:32 +0530417 struct input_dev *input_dev = nvec_get_drvdata(pdev);
Varun Wadekar87826b72010-01-21 20:53:04 +0530418 struct nvec_keyboard *keyboard = input_get_drvdata(input_dev);
Varun Wadekar87826b72010-01-21 20:53:04 +0530419
420 if (!keyboard) {
421 printk("%s: device handle is NULL\n", __func__);
422 return -1;
423 }
424
Varun Wadekar68a38772010-04-19 11:53:44 +0530425#if KEYBOARD_SCANNING_DISABLED_IN_SUSPEND
Varun Wadekar87826b72010-01-21 20:53:04 +0530426 /* 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 }
Varun Wadekar68a38772010-04-19 11:53:44 +0530448#endif
Varun Wadekar87826b72010-01-21 20:53:04 +0530449 /* 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
Ninad Malwade92891e22010-02-26 13:54:32 +0530458static int nvec_keyboard_resume(struct nvec_device *pdev)
Varun Wadekar87826b72010-01-21 20:53:04 +0530459{
Varun Wadekar68a38772010-04-19 11:53:44 +0530460#if KEYBOARD_SCANNING_DISABLED_IN_SUSPEND
Varun Wadekar87826b72010-01-21 20:53:04 +0530461 NvEcRequest Request = {0};
462 NvEcResponse Response = {0};
Varun Wadekar68a38772010-04-19 11:53:44 +0530463 NvError err = NvError_Success;
464#endif
Ninad Malwade92891e22010-02-26 13:54:32 +0530465 struct input_dev *input_dev = nvec_get_drvdata(pdev);
Varun Wadekar87826b72010-01-21 20:53:04 +0530466 struct nvec_keyboard *keyboard = input_get_drvdata(input_dev);
Varun Wadekar87826b72010-01-21 20:53:04 +0530467
468 if (!keyboard) {
469 printk("%s: device handle is NULL\n", __func__);
470 return -1;
471 }
472
473 /* power up hardware */
474 if (!NvOdmKeyboardPowerHandler(NV_FALSE)) {
475 printk("%s: hardware power up fail\n", __func__);
476 return -1;
477 }
478
Varun Wadekar68a38772010-04-19 11:53:44 +0530479#if KEYBOARD_SCANNING_DISABLED_IN_SUSPEND
Varun Wadekar87826b72010-01-21 20:53:04 +0530480 /* re-enable keyboard scanning */
481 Request.PacketType = NvEcPacketType_Request;
482 Request.RequestType = NvEcRequestResponseType_Keyboard;
483 Request.RequestSubtype =
484 (NvEcRequestResponseSubtype)NvEcKeyboardSubtype_Enable;
485 Request.NumPayloadBytes = 0;
486
487 err = NvEcSendRequest(
Varun Wadekar68a38772010-04-19 11:53:44 +0530488 keyboard->hNvec,
489 &Request,
490 &Response,
491 sizeof(Request),
492 sizeof(Response));
Varun Wadekar87826b72010-01-21 20:53:04 +0530493 if (err != NvError_Success) {
494 printk("%s: scanning enable request send fail\n", __func__);
495 return -1;
496 }
497
498 if (Response.Status != NvEcStatus_Success) {
499 printk("%s: scanning could not be enabled\n", __func__);
500 return -1;
501 }
Varun Wadekar68a38772010-04-19 11:53:44 +0530502#endif
Varun Wadekar87826b72010-01-21 20:53:04 +0530503
504 return 0;
505}
506
Ninad Malwade92891e22010-02-26 13:54:32 +0530507static struct nvec_driver nvec_keyboard_driver = {
508 .name = "nvec_keyboard",
509 .probe = nvec_keyboard_probe,
510 .remove = nvec_keyboard_remove,
Varun Wadekar87826b72010-01-21 20:53:04 +0530511 .suspend = nvec_keyboard_suspend,
512 .resume = nvec_keyboard_resume,
Ninad Malwade92891e22010-02-26 13:54:32 +0530513};
514
515static struct nvec_device nvec_keyboard_device = {
516 .name = "nvec_keyboard",
517 .driver = &nvec_keyboard_driver,
Gary Kinge550e3f2009-12-11 10:58:20 -0800518};
519
Gary Kinge550e3f2009-12-11 10:58:20 -0800520static int __init nvec_keyboard_init(void)
521{
522 int err;
523
Ninad Malwade92891e22010-02-26 13:54:32 +0530524 err = nvec_register_driver(&nvec_keyboard_driver);
Gary Kinge550e3f2009-12-11 10:58:20 -0800525 if (err)
Ninad Malwade92891e22010-02-26 13:54:32 +0530526 {
527 pr_err("**nvec_keyboard_init: nvec_register_driver: fail\n");
528 return err;
529 }
530
531 err = nvec_register_device(&nvec_keyboard_device);
532 if (err)
533 {
534 pr_err("**nvec_keyboard_init: nvec_device_add: fail\n");
535 nvec_unregister_driver(&nvec_keyboard_driver);
536 return err;
537 }
Gary Kinge550e3f2009-12-11 10:58:20 -0800538
539 return 0;
Gary Kinge550e3f2009-12-11 10:58:20 -0800540}
541
542static void __exit nvec_keyboard_exit(void)
543{
Ninad Malwade92891e22010-02-26 13:54:32 +0530544 nvec_unregister_device(&nvec_keyboard_device);
545 nvec_unregister_driver(&nvec_keyboard_driver);
Gary Kinge550e3f2009-12-11 10:58:20 -0800546}
547
548module_init(nvec_keyboard_init);
549module_exit(nvec_keyboard_exit);
550